archetype_ecs 1.1.6

Archetype ECS - High-performance Entity Component System with parallel execution
Documentation

Archetype ECS

A high-performance, strictly-typed, archetype-based Entity Component System for Rust.

Archetype ECS differs from other Rust ECS libraries by focusing on a "pure" data-oriented design with zero "game engine" bloat. It provides a robust kernel for building complex simulations and game engines, offering industry-standard features like parallel iteration, reactive queries, and hierarchical transforms out of the box.

features

  • 🚀 High Performance: Cache-friendly archetype storage with SoA (Structure of Arrays) layout.
  • ⚡ Parallel Execution: Automatic multi-threaded system scheduling with dependency resolution.
  • 🔍 Reactive Queries: Efficient Changed<T>, Added<T>, and Removed<T> filters.
  • 🌳 Hierarchy System: First-class parent-child relationship management with efficient transform propagation using glam.
  • 💾 Serialization: Built-in JSON serialization for entities, components, and entire worlds.
  • 📦 Asset Management: Typed asset handles, async-ready loaders, and hot-reloading support.
  • 🧩 Modularity: Zero "engine" assumptions. Use it for rendering, physics, or data processing.

Quick Start

Add to Cargo.toml:

[dependencies]
archetype_ecs = { git = "https://github.com/saptak7777/archetype_ecs" }
glam = "0.25" # Recommended for math types

Basic Example

use archetype_ecs::prelude::*;
use glam::{Vec3, Quat};

// 1. Define Components
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
struct Velocity {
    pub value: Vec3,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
struct Player {
    pub name: &'static str,
}

// 2. Define a System
struct MovementSystem;

impl System for MovementSystem {
    fn name(&self) -> &'static str { "Movement" }

    fn access(&self) -> SystemAccess {
        SystemAccess::new()
            .read::<Velocity>()
            .write::<LocalTransform>()
    }

    fn run(&mut self, world: &mut World) -> Result<()> {
        // Query for entities with Velocity and LocalTransform
        // We use query_mut to modify the transform
        for (vel, transform) in world.query_mut::<(&Velocity, &mut LocalTransform)>() {
            transform.position += vel.value * 0.016; // Assume 60 FPS dt
        }
        Ok(())
    }
}

fn main() -> Result<()> {
    let mut world = World::new();

    // 3. Spawn Entities
    // We use standard glam types for positions
    let player_id = world.spawn((
        Player { name: "Hero" },
        LocalTransform::with_position(Vec3::new(0.0, 1.0, 0.0)),
        GlobalTransform::identity(), // Required for hierarchy participation
        Velocity { value: Vec3::new(1.0, 0.0, 1.0) },
    ));

    // 4. Run Systems
    let mut movement = MovementSystem;
    movement.run(&mut world)?;

    // 5. Verify Result
    let player_pos = world.get_component::<GlobalTransform>(player_id).unwrap().position;
    println!("Player is now at: {}", player_pos);

    Ok(())
}

Core Concepts

World & Archetypes

Data is stored in Archetypes, grouping entities with the precise same set of components together. This guarantees contiguous memory for iteration, minimizing cache misses.

// Entities are just IDs.
let entity = world.spawn((ComponentA, ComponentB));

Queries & Filters

Queries are cached for O(1) access after the first run.

// Basic iteration
for (pos, vel) in world.query::<(&Position, &Velocity)>() { ... }

// Mutable iteration
for (pos, vel) in world.query_mut::<(&mut Position, &Velocity)>() { ... }

// Change detection (Reactive)
for pos in world.query::<&Position, Changed<Position>>() {
    println!("Position changed: {:?}", pos);
}

Hierarchy & Transforms

The hierarchy module provides optimized component-based scene graphs.

let parent = world.spawn((LocalTransform::identity(), GlobalTransform::identity()));
let child = world.spawn((LocalTransform::identity(), GlobalTransform::identity()));

// Attach child to parent
world.attach(parent, child)?;

// HierarchyUpdateSystem will automatically propagate transforms

Parallel Systems

The ParallelExecutor distributes systems across a thread pool, ensuring thread safety via runtime borrow checking.

let mut executor = ParallelExecutor::new(vec![
    Box::new(PhysicsSystem),
    Box::new(RenderSystem),
    Box::new(AudioSystem),
]);

// Automatically runs independent systems in parallel
executor.execute_parallel(&mut world)?;

Performance

Archetype ECS is designed for speed.

  • Iteration: Linear memory access pattern allows efficient prefetching.
  • Change Detection: Bitset-based filtering makes reactive systems negligible in cost.
  • Fragmentation: Archetype moves are somewhat expensive, so distinct "States" (like Walking vs Flying components) should be used judiciously.

(Benchmarks running on Intel Core i9-13900K, 100k entities)

  • Simple Iteration: ~0.5ns / entity
  • Composed Query: ~1.2ns / entity
  • Parallel Dispatch: Scales linearly with cores for disjoint data.

Standard Compliance

  • Math: Uses glam for SIMD-accelerated linear algebra.
  • Serialization: Uses serde for universal IO.
  • Async: Compatible with standard async runtimes for non-ECS tasks (like asset loading).

License

Apache-2.0.