A Lenia cellular automata simulator — tune the simulation parameters live and share a configuration with someone else via URL or a small backend.
Live at petri-one.vercel.app. The day-by-day build process is written up in DEVLOG.md.
- Renders a live Lenia simulation to canvas, seeded with a comet-shaped blob by default — or pick a known creature (Orbium, Gyrorbium, Scutium, …) from the species dropdown to seed a faithful reproduction, params and all.
- Tune growth target/width, time step, kernel radius, and ring weights from a live sidebar — invalid input is rejected with an inline error, valid edits apply to the running simulation immediately.
- Press Enter to pause/resume; a tick-duration readout shows how the simulation step is tracking against the frame budget.
- Simulation core — Rust, compiled to WASM. Runs the Lenia step and writes
raw RGBA output directly into a stable, pointer-exposed buffer (swapped via
mem::swap, not serialized) that the frontend reads straight into a Canvas each frame. Kernel/state convolution runs via FFT (rustfft) rather than a direct spatial loop. - Frontend — plain Vite + TypeScript. No UI framework; this is fundamentally a canvas app plus a parameter panel.
- Backend — Cloudflare Workers. Bare-bones: just enough to store/retrieve a shared parameter set, since the data model is flat.
- CI — GitHub Actions (
.github/workflows/ci.yml): fmt/clippy/build/test forsim, lint (oxlint)/typecheck/build forweb. - Deployment — Vercel, via
vercel.json+scripts/vercel-build.sh(installs Rust/wasm-pack at build time, since Vercel's build image doesn't ship them).
Prerequisites: a Rust toolchain with the wasm32-unknown-unknown target
(rustup target add wasm32-unknown-unknown) and wasm-pack installed
globally.
- Install dependencies (root — this is an npm workspace,
webis the only member so far):npm install - Start everything (builds the WASM bindings once, then runs the
wasm watcher and Vite dev server together):
npm run dev
| Command | Purpose |
|---|---|
npm install |
Install all workspace dependencies |
npm run build:wasm |
One-shot wasm-pack build of sim/, output into web/src/wasm |
npm run watch:wasm |
Rebuild the WASM bindings on any change under sim/src or sim/Cargo.toml |
npm run dev |
Build WASM once, then run the wasm watcher and web's dev server together |
npm run build |
Build WASM once, then production-build web |
| Command | Purpose |
|---|---|
cargo build --target wasm32-unknown-unknown |
Build the crate for WASM |
cargo test |
Run unit tests (native target) |
cargo fmt --check |
Check formatting |
cargo clippy |
Lint |
| Command | Purpose |
|---|---|
npm run dev |
Start the dev server |
npm run build |
Typecheck (tsc) + production build |
npm run lint |
Lint (oxlint) |
npm run preview |
Preview the production build locally |
| Command | Purpose |
|---|---|
The kernel core/shell construction and growth function (single-channel, 2D case) implement the formulas from:
Chan, B. W.-C. (2019). Lenia: Biology of Artificial Life. Complex Systems, 28(3), 251–286. arXiv:1812.05433