Skip to main content

Entity Component System (ECS)

Hyperscape uses a component-based Entity Component System for managing all game objects. This architecture separates data (Components) from logic (Systems), enabling modular, maintainable game development.
The ECS implementation lives in packages/shared/src/ and runs on both client and server for consistency.

Core Concepts

Entities

Entities are the fundamental game objects. Each entity has:
  • Unique ID (string) - UUID for identification
  • Type - player, mob, item, npc, resource, static
  • Three.js Node - 3D representation in the scene
  • Components Map - Attached data containers
  • Network State - Synchronization flags

Entity Hierarchy

Entities follow an inheritance hierarchy for specialized behavior:

Entity Lifecycle

  1. Constructor - Creates entity with initial data/config
  2. spawn() - Called when entity is added to world
  3. update(delta) - Called every frame for visual updates
  4. fixedUpdate(delta) - Called at fixed timestep (30 FPS) for physics
  5. destroy() - Cleanup when entity is removed

Components

Components are pure data containers attached to entities. They store state but contain no logic.

Base Component Class

Built-in Components

Adding Components to Entities

Component Events

When components are added/removed, events are emitted:

Systems

Systems contain game logic that operates on entities with specific components. They run during the game loop.

System Organization

Systems are organized by domain in packages/shared/src/systems/shared/:

System Base Class

All systems extend SystemBase:

Example: Skills System


World Class

The World class is the central container for all game state. It manages systems, entities, and the game loop.

Core Properties

Game Loop

System Registration


Network Synchronization

Entities automatically synchronize between server and clients.

Network Dirty Flag

Serialization


Best Practices

1

Keep Components Data-Only

Components should only store data. Put logic in Systems.
2

Use Type Guards

Use helper functions like isMobEntity() for safe type narrowing.
3

Emit Events for Cross-System Communication

Use the EventBus instead of direct system-to-system calls.
4

Mark Network Dirty When State Changes

Call entity.markNetworkDirty() after modifying replicated state.