Core Entity Component System (ECS) package for Decentraland scenes. Implements a CRDT-based ECS architecture for networked scene state.
npm install @dcl/ecs
import { engine } from '@dcl/ecs'
// Create entity
const entity = engine.addEntity()
// Define and add component
const Health = engine.defineComponent(1, {
current: Number,
max: Number,
regeneration: Number
})
Health.create(entity, {
current: 100,
max: 100,
regeneration: 1
})
// Create system
engine.addSystem((dt: number) => {
for (const [entity, health] of engine.mutableGroupOf(Health)) {
if (health.current < health.max) {
health.current = Math.min(health.max, health.current + health.regeneration * dt)
}
}
})
Components are defined with a unique ID and a schema. The schema is used to:
- Generate TypeScript types
- Create binary serializers/deserializers
- Set up CRDT operations
The ECS uses CRDTs (Conflict-free Replicated Data Types) to enable deterministic state updates across multiple engine instances:
- Component updates are CRDT operations with logical timestamps
- Multiple engine instances can be synced by exchanging CRDT operations
- Conflict resolution uses timestamps and entity IDs to ensure consistency
- Binary transport format minimizes network overhead
For multiplayer scenes, the syncEntity
method marks entities that should be synchronized across peers.
In the background it creates a NetworkEntity and a SyncComponents components with all the info necessary to synchronise the entity through the network.
import { engine, NetworkEntity } from '@dcl/ecs'
// Create a networked entity
const foe = engine.addEntity()
NetworkEntity.create(foe)
// Components on this entity will be synced across peers
Health.create(foe, { current: 100, max: 100, regeneration: 1 })
Each peer maintains its own engine instance. When using NetworkEntity:
- The owner peer can modify the entity's components
- Other peers receive read-only replicas
- Updates are propagated through the network transport layer using CRDT operations
Example transport message:
{
entityId: number
componentId: number
timestamp: number
data: Uint8Array // Serialized component data
}
- Zero-allocation component iteration
- Dirty state tracking for efficient updates
- Binary serialization for network transport
- Batched component operations
# Build
make build
# Test
make test
# Clean and reinstall
make clean && make install