{"id":27147370,"url":"https://github.com/sunsided/sillyecs","last_synced_at":"2025-04-08T11:25:55.467Z","repository":{"id":285649598,"uuid":"958873472","full_name":"sunsided/sillyecs","owner":"sunsided","description":"A silly little compile-time generated archetype ECS in Rust","archived":false,"fork":false,"pushed_at":"2025-04-01T23:26:11.000Z","size":0,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-01T23:32:54.183Z","etag":null,"topics":["archetype","archetype-ecs","ecs","game-development","game-engine","rust"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/sillyecs","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"eupl-1.2","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sunsided.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-04-01T22:49:12.000Z","updated_at":"2025-04-01T23:26:14.000Z","dependencies_parsed_at":"2025-04-01T23:32:55.596Z","dependency_job_id":"ef035005-fa6a-4d39-87bc-8bcc7fe99930","html_url":"https://github.com/sunsided/sillyecs","commit_stats":null,"previous_names":["sunsided/sillyecs"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fsillyecs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fsillyecs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fsillyecs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fsillyecs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sunsided","download_url":"https://codeload.github.com/sunsided/sillyecs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247831833,"owners_count":21003474,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["archetype","archetype-ecs","ecs","game-development","game-engine","rust"],"created_at":"2025-04-08T11:25:55.005Z","updated_at":"2025-04-08T11:25:55.439Z","avatar_url":"https://github.com/sunsided.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sillyecs\n\nA silly little compile-time generated archetype ECS in Rust.\n\n[![Crates.io](https://img.shields.io/crates/v/sillyecs)](https://crates.io/crates/sillyecs)\n[![License](https://img.shields.io/badge/license-EUPL--1.2-blue.svg)](LICENSE)\n\n## Installation\n\n`sillyecs` is a build-time dependency. To use it, add this to your `Cargo.toml`:\n\n```toml\n[build-dependencies]\nsillyecs = \"0.0.2\"\n```\n\n## Usage\n\nUse `sillyecs` in your `build.rs`:\n\n```rust\nuse sillyecs::EcsCode;\nuse std::fs::File;\nuse std::io::BufReader;\n\nfn main() -\u003e eyre::Result\u003c()\u003e {\n    println!(\"cargo:rerun-if-changed=ecs.yaml\");\n\n    let file = File::open(\"ecs.yaml\").expect(\"Failed to open ecs.yaml\");\n    let reader = BufReader::new(file);\n    EcsCode::generate(reader)?.write_files()?;\n    Ok(())\n}\n```\n\nDefine your ECS components and systems in a YAML file:\n\n```yaml\n# ecs.yaml\nstates:\n  - name: WgpuRender\n    description: The WGPU render state; will be initialized in the Render phase hooks\n\ncomponents:\n  - name: Position\n  - name: Velocity\n  - name: Health\n  - name: Collider\n\narchetypes:\n  - name: Particle\n    description: A particle system particle.\n    components:\n      - Position\n      - Velocity\n\n  - name: Player\n    components:\n      - Position\n      - Velocity\n      - Health\n\n  - name: ForegroundObject\n    components:\n      - Position\n      - Collider\n    promotions:\n      - BackgroundObject\n\n  - name: BackgroundObject\n    components:\n      - Position\n    promotions:\n      - ForegroundObject\n\nphases:\n  - name: Startup\n  - name: FixedUpdate\n    fixed: 60 Hz  # or \"0.01666 s\"\n  - name: Update\n  - name: Render\n    states:\n      - use: WgpuRender  # Use state in phase begin/end hooks\n        write: true\n\nsystems:\n  - name: Physics\n    phase: FixedUpdate\n    context: true\n    run_after: []  # optional\n    inputs:\n      - Velocity\n    outputs:\n      - Position\n  - name: Render\n    phase: Render\n    manual: true        # Require manual call to world.apply_system_phase_render()\n    # on_request: true  # call world.request_render_phase() to allow execution (resets atomically) \n    states:\n      - use: WgpuRender\n        write: false  # optional\n    inputs:\n      - Position\n\nworlds:\n  - name: Main\n    archetypes:\n      - Particle\n      - Player\n      - ForegroundObject\n      - BackgroundObject\n```\n\nInclude the compile-time generated files:\n\n```rust\ninclude!(concat!(env!(\"OUT_DIR\"), \"/components_gen.rs\"));\ninclude!(concat!(env!(\"OUT_DIR\"), \"/archetypes_gen.rs\"));\ninclude!(concat!(env!(\"OUT_DIR\"), \"/systems_gen.rs\"));\ninclude!(concat!(env!(\"OUT_DIR\"), \"/world_gen.rs\"));\n```\n\nThe compiler will tell you which traits and functions to implement.\n\n### Command Queue\n\nYou will have to implement a command queue. Below is an example for a queue based on\n[`crossbeam-channel`](https://docs.rs/crossbeam/latest/crossbeam/channel):\n\n```rust\nstruct CommandQueue {\n    sender: crossbeam_channel::Sender\u003cWorldCommand\u003e,\n    receiver: crossbeam_channel::Receiver\u003cWorldCommand\u003e,\n}\n\nimpl CommandQueue {\n    pub fn new() -\u003e Self {\n        let (sender, receiver) = crossbeam_channel::unbounded();\n        Self {\n            sender,\n            receiver,\n        }\n    }\n}\n\nimpl WorldCommandReceiver for CommandQueue {\n    type Error = TryRecvError;\n\n    fn recv(\u0026self) -\u003e Result\u003cOption\u003cWorldCommand\u003e, Self::Error\u003e {\n        match self.receiver.try_recv() {\n            Ok(cmd) =\u003e Ok(Some(cmd)),\n            Err(TryRecvError::Empty) =\u003e Ok(None),\n            Err(err) =\u003e Err(err),\n        }\n    }\n}\n\nimpl WorldCommandSender for CommandQueue {\n    type Error = crossbeam_channel::SendError\u003cWorldCommand\u003e;\n\n    fn send(\u0026self, command: WorldCommand) -\u003e Result\u003c(), Self::Error\u003e {\n        self.sender.send(command)\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunsided%2Fsillyecs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsunsided%2Fsillyecs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunsided%2Fsillyecs/lists"}