API Reference
Welcome to the KeenEyes ECS API documentation.
This reference is automatically generated from XML documentation comments in the source code. For tutorials and guides, see the Documentation.
Namespaces
KeenEyes
Core ECS runtime types for building high-performance entity component systems.
| Type | Description |
|---|---|
| World | Main ECS container - manages entities, components, systems, and queries |
| @KeenEyes.Entity | Lightweight entity handle (Id, Version) for staleness detection |
| EntityBuilder | Fluent builder for spawning entities with components |
| @KeenEyes.IComponent | Marker interface for component structs |
| @KeenEyes.ITagComponent | Marker interface for zero-size tag components |
| ComponentRegistry | Per-world component type registration |
| Archetype | Storage for entities sharing the same component types |
| ArchetypeManager | Manages archetype lifecycle and entity migrations |
| QueryBuilder | Fluent query builder for filtering entities |
| QueryEnumerator | Cache-friendly query iteration |
| @KeenEyes.ISystem | Base interface for ECS systems |
| @KeenEyes.SystemBase | Abstract base class with lifecycle hooks and runtime control |
| @KeenEyes.SystemGroup | Groups systems for collective execution |
| @KeenEyes.SystemPhase | Enum defining execution phases (EarlyUpdate, FixedUpdate, Update, LateUpdate, Render, PostRender) |
| @KeenEyes.RunBeforeAttribute | Specifies this system must run before another system (topologically sorted) |
| @KeenEyes.RunAfterAttribute | Specifies this system must run after another system (topologically sorted) |
| EntityPool | Manages entity ID recycling with versioning |
| @KeenEyes.MemoryStats | Memory usage statistics snapshot |
KeenEyes.Abstractions
Lightweight interfaces and types for plugin development without Core dependency.
| Type | Description |
|---|---|
| @KeenEyes.IWorld | Plugin-facing interface for world operations |
| @KeenEyes.IEntityBuilder | Interface for fluent entity building |
| @KeenEyes.ICommandBuffer | Interface for deferred entity operations |
| @KeenEyes.CommandBuffer | Queues entity operations for deferred execution (20-50x faster than reflection) |
| @KeenEyes.EntityCommands | Fluent builder for queued entity spawns |
| @KeenEyes.IWorldPlugin | Base interface for modular world extensions |
| @KeenEyes.IPluginContext | Context for plugin installation with system registration |
| @KeenEyes.EventSubscription | Disposable subscription handle for event cleanup |
KeenEyes.Events
Types for reactive programming patterns - events, subscriptions, and change tracking.
| Type | Description |
|---|---|
| EventBus | Generic pub/sub event system for custom events |
| @KeenEyes.Events.EventSubscription | Disposable subscription handle for event cleanup |
KeenEyes.Generators.Attributes
Attributes for Roslyn source generators that reduce boilerplate code.
| Attribute | Description |
|---|---|
| @KeenEyes.ComponentAttribute | Generates WithComponentName() fluent builder methods |
| @KeenEyes.TagComponentAttribute | Generates parameterless tag methods for marker components |
| @KeenEyes.DefaultValueAttribute | Specifies default values for component fields in builders |
| @KeenEyes.BuilderIgnoreAttribute | Excludes a field from generated builder parameters |
| @KeenEyes.QueryAttribute | Generates efficient query iterator structs |
| @KeenEyes.SystemAttribute | Generates system metadata (Phase, Order, Group) |
Getting Started
The main entry point is the World class:
using KeenEyes;
// Create an isolated ECS world
using var world = new World();
// Create an entity with components using the fluent builder
var entity = world.Spawn()
.With(new Position { X = 0, Y = 0 })
.With(new Velocity { X = 1, Y = 0 })
.Build();
// Query and iterate over matching entities
foreach (var e in world.Query<Position, Velocity>())
{
ref var pos = ref world.Get<Position>(e);
ref readonly var vel = ref world.Get<Velocity>(e);
pos.X += vel.X;
pos.Y += vel.Y;
}
Key Concepts
| Concept | Description |
|---|---|
| World | Isolated container for entities, components, and systems. Each world has its own component registry - no static state. |
| Entity | Lightweight (Id, Version) tuple. Version increments on recycle for staleness detection. |
| Component | Plain data struct implementing IComponent. Use ITagComponent for zero-size markers. |
| Archetype | Internal storage grouping entities with identical component types for cache-friendly iteration. |
| Query | Fluent API for filtering entities: world.Query<A, B>().With<C>().Without<D>() |
| System | Logic that processes entities. Inherit from SystemBase for lifecycle hooks (OnBeforeUpdate, OnAfterUpdate, OnEnabled, OnDisabled) and runtime control. |
| SystemPhase | Execution stage: EarlyUpdate → FixedUpdate → Update → LateUpdate → Render → PostRender. |
| CommandBuffer | Queues spawn/despawn/component operations for safe execution outside iteration. |
| Singleton | World-level resources via SetSingleton<T>() / GetSingleton<T>(). |
| Hierarchy | Parent-child entity relationships via SetParent() / GetChildren(). |
| Messaging | Inter-system communication via Send<T>() / Subscribe<T>() with immediate or queued delivery. |
| Plugin | Modular extensions via IWorldPlugin with Install() / Uninstall() lifecycle and Extension API. |
| Events | Lifecycle events via OnEntityCreated(), OnComponentAdded<T>(), etc. |
| Change Tracking | Dirty entity tracking via MarkDirty<T>() / GetDirtyEntities<T>(). |
| Prefabs | Reusable entity templates via RegisterPrefab() / SpawnFromPrefab() with inheritance support. |
| String Tags | Runtime-flexible tagging via AddTag() / HasTag() / QueryByTag() for data-driven workflows. |
| Component Validation | Enforce component dependencies and conflicts via [RequiresComponent] / [ConflictsWith] attributes. |
Quick Reference
Entity Operations
// Spawn
var entity = world.Spawn()
.With(new Position { X = 0, Y = 0 })
.WithTag<Player>()
.Build();
// Check and get components
if (world.Has<Position>(entity))
{
ref var pos = ref world.Get<Position>(entity);
pos.X += 10;
}
// Add/remove components
world.Add(entity, new Velocity { X = 1, Y = 0 });
world.Remove<Velocity>(entity);
// Despawn
world.Despawn(entity);
Queries
// Basic query - entities with Position AND Velocity
foreach (var e in world.Query<Position, Velocity>())
{
ref var pos = ref world.Get<Position>(e);
ref readonly var vel = ref world.Get<Velocity>(e);
}
// Filtered query - with Health, without Dead tag
foreach (var e in world.Query<Position>().With<Health>().Without<Dead>())
{
// Process living entities with position and health
}
Systems
[System(Phase = SystemPhase.Update, Order = 10)]
public partial class MovementSystem : SystemBase
{
protected override void OnBeforeUpdate(float deltaTime)
{
// Called before Update - setup, accumulation, etc.
}
public override void Update(float deltaTime)
{
foreach (var entity in World.Query<Position, Velocity>())
{
ref var pos = ref World.Get<Position>(entity);
ref readonly var vel = ref World.Get<Velocity>(entity);
pos.X += vel.X * deltaTime;
pos.Y += vel.Y * deltaTime;
}
}
protected override void OnAfterUpdate(float deltaTime)
{
// Called after Update - cleanup, statistics, etc.
}
protected override void OnEnabled()
{
// Called when system is enabled
}
protected override void OnDisabled()
{
// Called when system is disabled
}
}
// Register with phase and order
world.AddSystem<InputSystem>(SystemPhase.EarlyUpdate, order: 0);
world.AddSystem<MovementSystem>(SystemPhase.Update, order: 10);
world.AddSystem<RenderSystem>(SystemPhase.Render, order: 0);
// System dependencies with [RunBefore] and [RunAfter]
[System(Phase = SystemPhase.Update)]
[RunAfter(typeof(InputSystem))]
[RunBefore(typeof(RenderSystem))]
public partial class AnimationSystem : SystemBase { }
// Or specify at registration time
world.AddSystem<CollisionSystem>(
SystemPhase.Update,
order: 0,
runsBefore: [typeof(DamageSystem)],
runsAfter: [typeof(MovementSystem)]);
// Run all systems (sorted by phase, then dependencies, then order)
world.Update(deltaTime);
// Run only FixedUpdate phase systems (for physics)
world.FixedUpdate(fixedDeltaTime);
// Runtime control
var system = world.GetSystem<MovementSystem>();
world.DisableSystem<MovementSystem>(); // Pauses the system
world.EnableSystem<MovementSystem>(); // Resumes the system
Command Buffer (Deferred Operations)
CommandBuffer is now in KeenEyes.Abstractions for plugin isolation, with zero reflection for 20-50x performance improvement:
using KeenEyes; // From Abstractions - no Core dependency needed!
var buffer = new CommandBuffer();
foreach (var entity in world.Query<Health>())
{
ref var health = ref world.Get<Health>(entity);
if (health.Current <= 0)
{
// Queue for later - safe during iteration
buffer.Despawn(entity);
}
}
// Execute all queued commands (delegate-based, zero reflection)
buffer.Flush(world);
Performance: Commands use delegate capture pattern instead of reflection for 20-50x faster execution.
Singletons
// Set world-level resource
world.SetSingleton(new GameConfig { Gravity = 9.8f });
// Retrieve
ref var config = ref world.GetSingleton<GameConfig>();
Entity Hierarchy
// Establish parent-child relationship
world.SetParent(child, parent);
// Query relationships
var parent = world.GetParent(child);
foreach (var child in world.GetChildren(parent))
{
// Process children
}
// Destroy entity and all descendants
world.DespawnRecursive(rootEntity);
Messaging (Inter-System Communication)
// Define message types (struct recommended for zero-allocation)
public readonly record struct DamageMessage(Entity Target, int Amount, Entity Source);
// Subscribe to messages
var subscription = world.Subscribe<DamageMessage>(msg =>
{
ref var health = ref world.Get<Health>(msg.Target);
health.Current -= msg.Amount;
});
// Send immediately to all subscribers
world.Send(new DamageMessage(target, 25, attacker));
// Or queue for deferred processing
world.QueueMessage(new DamageMessage(target, 25, attacker));
world.ProcessQueuedMessages(); // Process all queued messages
// Check if anyone is listening (optimization)
if (world.HasMessageSubscribers<ExpensiveMessage>())
{
var data = ComputeExpensiveData();
world.Send(new ExpensiveMessage(data));
}
// Unsubscribe
subscription.Dispose();
Events
// Component lifecycle events
var sub1 = world.OnComponentAdded<Health>((entity, health) =>
{
Console.WriteLine($"Health added to {entity}");
});
// Entity lifecycle events
var sub2 = world.OnEntityDestroyed(entity =>
{
Console.WriteLine($"Entity {entity} destroyed");
});
// Custom events via EventBus
world.Events.Subscribe<DamageEvent>(evt =>
{
Console.WriteLine($"Damage dealt: {evt.Amount}");
});
world.Events.Publish(new DamageEvent(target, 25));
// Cleanup subscriptions
sub1.Dispose();
sub2.Dispose();
Change Tracking
// Mark entity as dirty
world.MarkDirty<Position>(entity);
// Query dirty entities
foreach (var e in world.GetDirtyEntities<Position>())
{
SyncToNetwork(e);
}
// Clear after processing
world.ClearDirtyFlags<Position>();
// Enable automatic tracking for Set() calls
world.EnableAutoTracking<Position>();
Plugins
// Create plugin
public class PhysicsPlugin : IWorldPlugin
{
public string Name => "Physics";
public void Install(PluginContext context)
{
context.AddSystem<GravitySystem>(SystemPhase.FixedUpdate, order: 0);
context.SetExtension(new PhysicsWorld(context.World));
}
public void Uninstall(PluginContext context)
{
context.RemoveExtension<PhysicsWorld>();
}
}
// Install via WorldBuilder
using var world = new WorldBuilder()
.WithPlugin<PhysicsPlugin>()
.Build();
// Or install directly
world.InstallPlugin<PhysicsPlugin>();
// Query plugins
if (world.HasPlugin<PhysicsPlugin>())
{
var plugin = world.GetPlugin<PhysicsPlugin>();
}
// Access extensions
var physics = world.GetExtension<PhysicsWorld>();
physics.SetGravity(9.8f);
// Uninstall
world.UninstallPlugin<PhysicsPlugin>();
Prefabs
// Define reusable entity templates
var enemyPrefab = new EntityPrefab()
.With(new Position { X = 0, Y = 0 })
.With(new Health { Current = 100, Max = 100 })
.WithTag<EnemyTag>();
world.RegisterPrefab("Enemy", enemyPrefab);
// Spawn from prefab
var enemy = world.SpawnFromPrefab("Enemy").Build();
// Override components when spawning
var strongEnemy = world.SpawnFromPrefab("Enemy")
.With(new Health { Current = 200, Max = 200 })
.Build();
// Prefab inheritance
var bossEnemyPrefab = new EntityPrefab()
.Extends("Enemy")
.With(new Health { Current = 500, Max = 500 })
.WithTag<BossTag>();
world.RegisterPrefab("BossEnemy", bossEnemyPrefab);
String Tags
// Add runtime tags
world.AddTag(entity, "Enemy");
world.AddTag(entity, "Hostile");
// Check tags
if (world.HasTag(entity, "Boss"))
{
// Special boss handling
}
// Query by tag
foreach (var e in world.QueryByTag("Enemy"))
{
// Process all enemies
}
// Combine with component queries
foreach (var e in world.Query<Position>()
.WithTag("Enemy")
.WithoutTag("Dead"))
{
// Process living enemies with position
}
Component Validation
// Enforce component dependencies with attributes
[Component]
[RequiresComponent(typeof(Transform))]
public partial struct RigidBody
{
public float Mass;
}
// Mutual exclusion
[Component]
[ConflictsWith(typeof(DynamicBody))]
public partial struct StaticBody { }
// This throws - Transform is required
var entity = world.Spawn()
.With(new RigidBody { Mass = 1.0f })
.Build();
// This works
var entity = world.Spawn()
.With(new Transform())
.With(new RigidBody { Mass = 1.0f })
.Build();
// Custom validators
world.RegisterValidator<Health>((world, entity, health) =>
health.Current >= 0 && health.Current <= health.Max);
// Control validation mode
world.ValidationMode = ValidationMode.DebugOnly;
Source Generator Attributes
Reduce boilerplate with source-generated code:
using KeenEyes.Generators.Attributes;
// Generates WithPosition(float x, float y) builder method
[Component]
public partial struct Position
{
public float X;
public float Y;
}
// Generates WithPlayer() parameterless method
[TagComponent]
public partial struct Player { }
// Use generated methods
var entity = world.Spawn()
.WithPosition(x: 10, y: 20)
.WithPlayer()
.Build();
Guides
For in-depth coverage, see the documentation guides:
- Getting Started - Build your first ECS application
- Core Concepts - Understand ECS fundamentals
- Entities - Entity lifecycle and management
- Components - Component patterns and best practices
- Queries - Filtering and iterating entities
- Systems - System design patterns
- Messaging - Inter-system communication patterns
- Plugins - Modular extensions and feature packaging
- Command Buffer - Safe entity modification during iteration
- Singletons - World-level resources
- Relationships - Parent-child entity hierarchies
- Events - Component and entity lifecycle events
- Change Tracking - Track component modifications
- Prefabs - Reusable entity templates with inheritance
- String Tags - Runtime-flexible entity tagging
- Component Validation - Enforce component constraints
- Serialization - Save and load world state
Browse the namespace documentation below for detailed API information on each type.