Choosing a trait¶
A Henad model is const metadata plus pure functions. Allocation, double buffering, chunking, RNG seeding, parameter storage, the views and the runner interface all belong to the engine, and your code never has to mention a thread, a buffer or a frame.
Five traits cover three topologies. Grids and agents each have a CPU trait and a GPU trait, and networks have a CPU trait only.
| CPU | GPU | |
|---|---|---|
Grid — cellular automata over u8 cells |
GridModel |
GpuGridModel |
| Agents — a population, optionally over a field | AgentModel |
GpuAgentModel |
| Network — nodes joined by edges | NetworkModel |
Pick the topology first. A model holding one value per cell of a fixed lattice is a grid model. If your state is a population moving through space, you want an agent model, and that still holds when those agents read and write a grid underneath themselves, since a field covers that case. If your state is a population whose members interact along edges that last from one tick to the next, you want a network model.
Then pick the backend, and start on the CPU.
A CPU model is ordinary Rust, so dbg! and a test work on it.
The GPU version is WGSL plus a declared list of passes, and every GPU model in the repository was written after its CPU counterpart already worked.
Each one starts from that counterpart's tick 0 bit for bit, which keeps the pair comparable.
Porting a model to the GPU picks up from there.
SimState is not a sixth path
SimState belongs to the runner, which drives a state through it.
Implement one of the five traits above and leave SimState to the engine.
The five declarations¶
Whichever trait you pick, your model supplies the same five things.
Identity. The NAME, ID and DESCRIPTION consts, read by the app and by henad-cli --list.
Parameters. Descriptors carrying an id, a kind, a default, a range and whether an edit applies live or on reload.
The engine prepends the parameters every CPU model of that topology needs, and a GridModel therefore never declares its own width and height.
Statistics. A STATS list naming the series the history chart plots, together with a stats function that returns bare values in that order.
An initial state. An init that fills the grid or the lanes from the parameters and a seed.
A network model's init also adds the edges.
A step. The kernel itself, which stays pure apart from the RNG it receives.
Every model but a GPU agent model also declares a PALETTE, and palettes and views covers what the renderer does with it.
A GPU agent model colours its agents from its own colour buffer.
Where to start¶
If you have not written a model before, the three CPU tutorials each build one end to end, and you can come back to this section as the reference.
-
Builds Game of Life, from an empty directory to an entry in the dropdown.
-
Builds a foraging population over a pheromone field, the one composite model in the repository.
-
Builds Virus on a Network, a virus spreading along the edges of a random graph.
Then¶
Once your model runs, register it so that it appears in the app and the CLI, test it, check it against the determinism contract, and read writing fast models before you scale it up.