sparze
Expert guidance for Sparze ECS apps including systems, queries, components, resources, events, and performance trade-offs.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Expert guidance for Sparze ECS apps including systems, queries, components, resources, events, and performance trade-offs.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | sparze |
| description | Expert guidance for Sparze ECS apps including systems, queries, components, resources, events, and performance trade-offs. |
Expert guidance for building high-performance ECS applications with Sparze.
World: ECS coordinator with compile-time component, resource, event, and group types.
const World = sparze.World(
.{ Position, Velocity, Health }, // Components
.{ DeltaTime, Score }, // Resources
.{ CollisionEvent }, // Events
.{ struct { Position, Velocity } }, // Groups
);
Entity: 32-bit handle [version:16 | index:16]. index selects dense slot; version invalidates stale handles. Use .index, .version, or getIndex() / getVersion(). Create via Entity.init(), serialize with toInt() / fromInt(u32).
Components: Data attached to entities. Tag components (empty structs) use 1 bit per entity.
Resources: Global singletons injected via Resource(T) / ResourceMut(T). Can implement init() / deinit(), or opt out with pub const auto_init = false (manual initialization required). POD resources are zero-initialized for compatibility.
Events: 1-frame delayed, double-buffered communication. Events written in frame N are read in frame N+1.
Docs: @docs/ARCHITECTURE.md, @docs/ENTITY_LIFECYCLE.md
System functions use injected parameters and must use commands: anytype for world mutation. Return void or !void.
fn mySystem(
allocator: std.mem.Allocator,
movement: Group(struct { Position, Velocity }),
health: SingleQuery(Health),
delta: Resource(DeltaTime),
score: ResourceMut(Score),
reader: EventReader(CollisionEvent),
writer: EventWriter(DamageEvent),
commands: anytype,
) !void {
// Implementation
}
Immediate (returns now):
commands.createEntity()try commands.createEntityWith(.{ Position{...}, Velocity{...} })commands.setResource(T, value) / commands.getResource(T) / commands.getResourcePtrMut(T)try commands.initResources(.{ ... })try commands.serializeToFile(path) / try commands.deserializeFromFile(path)Deferred (applied at world.endFrame()):
try commands.addComponent(e, T, value) / try commands.removeComponent(e, T)try commands.addTag(e, T) / try commands.removeTag(e, T)try commands.destroyEntity(e)Why deferred: avoids invalidating iterators or shifting dense arrays mid-iteration.
Docs: @docs/SYSTEM_PATTERNS.md
Decision guide:
fn healthSystem(query: SingleQuery(Health)) !void {
for (query.entities, query.components) |entity, *health| {
health.hp = @max(0, health.hp);
}
}
fn combatSystem(query: Query(struct { Position, Health, ?Shield })) !void {
for (query.entities) |entity| {
if (query.filter(entity)) {
const pos = query.getComponent(entity, Position);
const health = query.getComponentMut(entity, Health);
const shield = query.getOptional(entity, Shield);
_ = pos; _ = health; _ = shield;
}
}
}
const MovementGroup = struct { Position, Velocity };
const World = sparze.World(.{ Position, Velocity }, .{}, .{}, .{ MovementGroup });
fn movementSystem(group: Group(MovementGroup)) !void {
const positions = group.getMutArrayOf(Position);
const velocities = group.getArrayOf(Velocity);
for (positions, velocities) |*pos, vel| {
pos.x += vel.x;
pos.y += vel.y;
}
}
Free(Component): use in groups that do not own a component. Access via group.getComponent(entity, T) instead of array access.
fn enemySystem(query: TagQuery(struct { Enemy, ?Boss, Exclude(Dead) })) !void {
for (query.entities) |entity| {
if (query.filter(entity)) {
_ = entity;
}
}
}
Docs: @docs/QUERY_PATTERNS.md
Principles:
Frame lifecycle:
world.beginFrame();
try world.runSystem(inputSystem);
try world.runSystem(physicsSystem);
try world.runSystem(renderSystem);
try world.endFrame();
Critical: Always call endFrame() to flush deferred commands.
Initialization options:
init() / deinit() for auto-lifecyclepub const auto_init = false for manual setupSafety helpers:
isResourceInitialized(T)tryGetResource(T)initResources(.{ ... }) for bulk initFastest to slowest:
getMutArrayOf)getComponent)Best practices:
World.validateGroups()Storage notes:
getSparseSetPtrMut(T).reserve(capacity)Docs: @docs/PERFORMANCE.md, @docs/STORAGE_INTERNALS.md
| Task | API |
|---|---|
| Create entity | commands.createEntity() |
| Add component | try commands.addComponent(e, T, value) |
| Query single | SingleQuery(Health) |
| Query multi | Query(struct { Position, Velocity }) |
| Fastest iteration | Group(struct { Position, Velocity }) |
| Optional component | Query(struct { Position, ?Sprite }) |
| Exclude entities | Query(struct { Enemy, Exclude(Dead) }) |
| Read resource | Resource(DeltaTime) |
| Write resource | ResourceMut(Score) |
| Read events | EventReader(CollisionEvent) |
| Write events | EventWriter(DamageEvent) |
| Tag iteration | SingleTag(Enemy) |