Cella

Cella is a Rust toolkit for cellular automata (CA): grids of cells that change step by step according to simple local rules, like Conway's Game of Life. It has four layers, each usable on its own:
- An engine for 1D and 2D rule-based CAs, with multi-threaded stepping and JSON configs you can save, share and resume.
- A plugin seam (
ExternalModel) for replacing the built-in rules with your own transition code. A wildfire spread model ships as the worked example. - An Explore module that runs any rule or model many times (ensembles), searches for good settings (evolution) and maps the range of behaviors a rule family can produce (MAP-Elites).
- A GUI workbench (egui) and a small CLI demo menu on top of all of it.
It is for people who want to play with CA rules, build a model on a fast grid engine, or study how a stochastic (random-element) model behaves across many runs.
Wildfire disclaimer. The wildfire model and the scoring tools in
validation/ are a personal-interest project.
They must not be used to model or predict real fires.
Features
- 1D Wolfram-style rules (any code, any radius) and 2D neighborhood-count rules (Moore, Von Neumann, Langton, StraightLine, Knight), with multi-state cells and optional per-rule randomness.
- Deterministic results: the same config and seed give the same run, on any thread count.
- JSON configs: load, save, and resume a run part-way through.
- Plugin models: implement
ExternalModelin your own crate and tag it withtypetag. Configs then load it by name, and the engine and Explore drive it with no changes to Cella. To use it in the GUI, link your crate into thecellabinary. - Explore: Monte Carlo ensembles (probability maps), genetic-algorithm evolution, novelty search and MAP-Elites, for any rule or model.
- GUI: live rule editor, paint/stamp tools, zoom and pan, population charts, per-type colors, GIF export, and an Explore tab.
- Wildfire example model with a validation pipeline that scores it against
observed fires, including null baselines (see
validation/).
Quick start
Prerequisites
- Rust. Install via rustup. The GUI crates
(
eframe/egui0.35) require Rust 1.92 or newer.cella_libalone uses the 2024 edition, so it needs at least 1.85. The project is developed on recent stable. - Linux desktop libraries for the GUI.
eframeneeds the usual X11 or Wayland and OpenGL development packages.rfd, which draws the file open/save dialogs, needsxdg-desktop-portalorzenity. On Debian or Ubuntu,sudo apt install zenitycovers the dialogs. - WSL users: without a desktop session the "Load Config JSON..." button
silently does nothing. Install
zenity, or skip the dialog by passing a config on the command line (next section). Details are in docs/app.md, "Troubleshooting". - Python 3 is only needed for the data-conversion scripts in
validation/. It is not needed to build or run Cella.
Build and run
# Build the binary (first build downloads and compiles dependencies)
# Launch the GUI
# Launch the GUI with a config already open (also the WSL workaround)
# Launch the CLI demo menu
The Cargo package is named cella_gui (the name cella is taken on
crates.io), but the program it builds is still called cella, so the
release build ends up at target/release/cella. Use --package cella_gui
if a Cargo command asks which package you mean.
Window size is optional:
If only --width or --height is given, the other is computed for a 16:9
window.
CLI demo menu
Without --gui, the binary shows a numbered menu and prints results to the
terminal:
Cella demos (CLI):
1) 2D Game of Life (approx)
2) 1D Wolfram Rule 30 (n=1)
3) 1D Wolfram n=2 demo
4) 1D Custom (Wolfram code + n)
5) Load from configuration file (JSON)
6) Langton's ant (placeholder)
7) 1D three-state cycle demo
8) 2D three-state cycle demo
9) 2D StraightLine neighborhood demo
0) Exit
Option 6 is a placeholder: it only prints a "not yet implemented" message, because Langton's ant needs a moving agent and the engine has none.
To run a config file, pick option 5:
Select an option: 5
Enter path to JSON config: configs/life.json
Enter number of steps to run [10]: 20
Ready-made configs are in configs/: Life, Rule 30, multi-state
cycles, other neighborhoods, wildfire demos, and Explore setups.
Documentation map
| Document | Contents |
|---|---|
| Application guide | CLI, GUI workbench tour, editing, Explore tab, config guide, troubleshooting |
| Library README | Using cella_lib in your own crate: install, code samples, bundled examples |
| Library guide | Architecture, module reference, rule system, external models, serialization, threading |
| Explore guide | Ensembles, evolution and MAP-Elites for any rule or model; how to read results honestly |
| Primer: Monte Carlo | Plain-language: why run a simulation many times, probability maps, particle filters, seeds |
| Primer: Genetic Algorithms | Plain-language: populations, selection, mutation, novelty search, MAP-Elites |
| Validation README | Scoring the wildfire model against real fires; start with ANALYSIS.md |
| Performance review | Developer notes: engine internals, optimizations, known issues |
| Roadmap | Developer notes: GUI and plugin-UI work plan, with status per phase |
Rust API docs: run cd cella_lib && cargo doc --open for the library.
(make doc documents only the cella_gui package, because cella_lib is
a separate build root; see "Building and testing".)
Using cella_lib as a library
The engine is its own crate, cella_lib, which you can use in your own
programs without the GUI. Its README covers installation, code samples
(Game of Life from a config, Rule 30 in the terminal), plugging in your own
model, and the bundled example programs:
cella_lib/README.md.
Thread count
The engine steps grids in parallel. To set the worker count, create a
cella.properties file in the directory you run from (the repo root has
one already):
# Number of worker threads for grid stepping. 1 disables parallelism.
Without the file, the engine uses std::thread::available_parallelism(),
usually the number of logical CPUs.
Config format
A config is a JSON file with a "dim" field ("1d" or "2d"), a size, an
initial list of cell types, and a rule made of subrules. A subrule says
"a cell of type A, seeing at least N neighbors of type B, becomes type C".
(The "..." entries stand in for the full list in the real files. In JSON
wolfram_code is a string; in the Rust API it is a number.)
2D subrule notes: op ("lt"/"gt"/"eq") is inclusive for gt and
lt ("at least" / "at most"). neighborhood is one of "Moore",
"VonNeumann", "Langton", "StraightLine", "Knight". An optional
"limit" turns gt/lt into an inclusive between-range (for example
"count":2, "op":"gt", "limit":3 means "survive with 2 to 3 neighbors").
"randomness" and "limit" may be omitted.
The full field guide, plus the optional model, colors, snapshot,
ensemble and evolve blocks, is in
docs/app.md, "Config file guide" and
docs/lib.md.
Building and testing
The Makefile wraps the common commands (each target has a one-line
comment above it):
| Command | What it does |
|---|---|
make build / make build-release |
Build the cella binary |
make run / make run-gui |
Run the CLI menu / the GUI at 1024x768 |
make clippy |
Lint everything with warnings as errors (the lint gate) |
make fmt / make fmt-check |
Format / check formatting |
make test |
Fast tests: non-ignored cella_lib tests plus the wildfire_smc example tests |
make test-all |
Also runs the slow #[ignore]d tests |
make coverage |
Line coverage for cella_lib (needs cargo install cargo-llvm-cov) |
cella_lib is its own Cargo build root. The root Cargo.toml depends
on it by path but does not list it as a workspace member. In practice:
- A bare
cargo testat the repo root tests only thecellabinary, not the library. The library tests run withcd cella_lib && cargo test, which is whatmake testdoes for you. cella_libhas its owntarget/directory and its own copy of the release profile, so it builds separately from the root.- Its examples (
cella_lib/examples/) are built and run from insidecella_lib/, for examplecd cella_lib && cargo run --release --example explore.
Before sending a change, run make clippy and make test. More on test
environment variables, snapshots and benchmarks is in
docs/lib.md, "Building and testing".
Project layout
cella/
├── Cargo.toml # `cella_gui` package (builds the `cella` app)
├── Makefile # build / lint / test shortcuts
├── cella.properties # Thread count
├── configs/ # Ready-made JSON scenarios
├── docs/ # Guides (see the documentation map above)
├── src/ # Binary crate
│ ├── main.rs # Entry point: CLI menu or --gui
│ ├── demos/ # CLI demos
│ └── gui/ # egui workbench (app, panels, explore, export, ...)
├── cella_lib/ # Library crate (its own Cargo build root)
│ ├── src/
│ │ ├── grid1d.rs, grid2d.rs, rules.rs # Grids and rule system
│ │ ├── config.rs, state.rs # JSON configs, save/resume
│ │ ├── external.rs # ExternalModel plugin seam
│ │ ├── explore/ # Ensembles, evolution, MAP-Elites
│ │ └── wildfire/ # Worked-example model (not engine code)
│ ├── examples/ # explore, wildfire_validate, wildfire_smc, ...
│ └── tests/ # Integration and snapshot tests
└── validation/ # Scoring the wildfire model against real fires
The full module map for the library is in docs/lib.md; for the GUI, in docs/app.md.
License
MIT — see LICENSE.