SkillAgentSearch skills...

Polymorph

A fast and frugal entity-component-system library with a focus on code generation and compile time optimisation.

Install / Use

/learn @rlipsc/Polymorph

README

Project overview

pmf150

A lean, generative abstraction for writing programs with the entity-component-system pattern.

Goals

  • Manage complexity with declarative dispatch and run time composition.
  • Scalable, low boilerplate platform for composing data oriented designs.
  • No runtime, zero system iteration overhead.
  • Leverage static typing and metaprogramming to elide run time work.
  • Support low resource embedded devices.
  • No external dependencies.

Entity-component-system (ECS)

This pattern lets you build composite types at run time and dispatch program logic for specific sets of types.

The three elements of ECS are:

  • Entity: a handle that lets you add or remove data types.
  • Component: a data type that can be added to an entity.
  • System: logic with component parameters that runs for matching entities.

Entity-component-systems offer a way to structure programs 'bottom up' by combining data to compose system behaviour at run time.

An example ECS

import polymorph

# Create some component data types.
register defaultCompOpts:
  type
    Pos = object
      x, y: int
    Vel = object
      x, y: int

# Define some logic for when Pos and Vel are together.
makeSystem "move", [Pos, Vel]:
  all:
    pos.x += vel.x
    pos.y += vel.y

# Generate the ECS for use.
makeEcsCommit "runSystems"

# Compose Pos and Vel to trigger "move".
let
  moving = newEntityWith(
    Pos(x: 0, y: 0),
    Vel(x: 1, y: 1)
  )

# Run the "move" system a number of times.
for i in 0 ..< 4:
  runSystems()

# Confirm the updated Pos value.
let pos = moving.fetch Pos
assert pos.x == 4 and pos.y == 4

Benefits of ECS

  • The principles of SOLID
  • Inversion of control
  • Naturally data oriented and data driven
  • Remove ambiguities, coupling, dependencies and slow virtual calls of inheritance trees
  • Maintain design agility and rapid prototyping by composing behaviour at run time
  • Avoid data coupling and the 'conceptual crystallisation' of top down design
  • Encourage decoupled and isolated logic that's easy to reuse, extend, and maintain
  • High performance through machine friendly batch processing with uniform lists
  • Natively asynchronous

ECS contrasted with Object Oriented Design

Objects in OOD describe is a relationships with hierarchies of types. Subtyping and encapsulation naturally fit a top down design process, where a general overview of a task is split into sub-tasks. The mechanics of execution is often bespoke to each solution.

By contrast, entities in ECS describe has a relationships with sets of types. Mutable composition lends itself more to a bottom up design process, where behaviour is built by composing tasks. Systems dispatch over matching entities automatically in a fixed order.

For a view of ECS from an OOP perspective, see here.

Polymorph: a generative approach to a queryless, system oriented ECS.

Traditionally, ECS implementations orient their data model from the perspective of components (aggregate data) or entities (data compositions).

In order to perform work in these models, a system must query a management layer for live data to process. The efficiency of this process can become a key factor in complex designs.

Polymorph instead orients its data model from the perspective of systems (execution); systems hold component state for matching entities, and are updated when entities add or remove components.

By avoiding the disconnect between execution and state, systems are always available to run without any iteration overhead.

Entity operations are transactional system state changes, and the component types involved infer the systems affected.

This allows entity operations to be entirely generated at compile time, guided by system/component relationships to emit pared down system updates that perform the minimum run time work possible.

The output is statically dispatched with a linear execution flow (no need for callbacks), consisting of simple loops over incrementally updated component data.

Compile time focus

Polymorph takes extensive advantage of Nim's metaprogramming features to shift as much work to compile time as possible.

Functionality such as building entities from blueprints, cloning entities, and debugging utilities are also fully generated from your types and system design at compile time.

The more that state can be determined at compile time, the less run time work is needed. Creating a new entity with a set of components fully specifies the entity state, and systems are unconditionally matched at compile time. Any system updates required are then generated as direct, static updates, without any run time speculative work.

Adding and removing multiple components at once is also minimised at compile time, outputting single pass inline operations.

Features

  • Design driven: code generation directly from component/system interactions.
  • Zero system overhead: no queries or iteration overhead for systems.
  • Cheap to change components: freely evolve entities with wildly disparate components without moving memory.
  • Sequential code flow: flatten run time composition, declarative code
View on GitHub
GitHub Stars149
CategoryDevelopment
Updated17d ago
Forks8

Languages

Nim

Security Score

100/100

Audited on Mar 19, 2026

No findings