Demos
Every kernel below is cljrs source. Videos were rendered by
bin/record (CPU) and bin/gpu-record (GPU).
Run any of them locally with the commands under each section.
GPU (defn-gpu-pixel)
Kernels compile to WGSL and run on wgpu: Metal on macOS, Vulkan on Linux, DX12 on Windows, WebGPU in browsers. Numbers below are render throughput on an integrated Apple M3 at 640x360.
demo_gpu/plasma.clj) · 252 fpsdemo_gpu/waves.clj) · 402 fpsdemo_gpu/mandelbrot.clj) · 150 fps with 8x SSAAdemo_gpu/raymarch3d.clj) · 494 fpsdemo_gpu/raytrace.clj) · 421 fps with reflections + shadowsdemo_gpu/clouds.clj) · 287 fpsdemo_gpu/flowfield.clj) · 135 fpscargo run --release --features gpu-demo --bin gpu-demo -- demo_gpu/plasma.clj
Edit the .clj file while the window is open, the kernel
recompiles on save. Run any of these in the browser on the
GPU page.
CPU (defn-native)
JIT-compiled to machine code via MLIR and LLVM. One call per pixel per frame, run in parallel across CPU cores with rayon.
cargo run --release --features demo --bin demo -- demo/fractal.clj
Live-coded browser demos
Edit cljrs source in the page, see the change reflected immediately. State persists across edits.
- Platformer — pause, rewind, change jump height, see the future trajectory redraw.
- Conway's Game of Life — edit birth/survive rules, neighborhood, palette; click cells to toggle.
- Synth — polyphonic subtractive synth, live-editable ADSR + filter + LFO.
- Sequencer — step sequencer wired to the synth.
- ML — four training showcases (curve fit, two-moons, MNIST-tiny, autoencoder).
- Matmul bench — cljrs CPU/GPU matmul vs numpy/JAX/PyTorch references.
- UI demo — cljrs.ui = hiccup → Preact via wasm.
- JS interop — fetch, local storage, DOM from cljrs.
- Physics — rapier-driven 2D physics playground.
Kernel ABI
CPU kernels have a fixed signature:
(defn-native render-pixel ^i64
[^i64 px ^i64 py ^i64 frame ^i64 t-ms
^i64 s0 ^i64 s1 ^i64 s2 ^i64 s3]
...body, returns 0xRRGGBB as i64...)
The host calls it once per pixel per frame, in parallel via rayon.
s0 through s3 are slider values 0 to 1000.
Time scrubbing replaces t-ms with a paused value.
Build your own
echo "(defn-native render-pixel ^i64
[^i64 px ^i64 py ^i64 frame ^i64 t-ms
^i64 s0 ^i64 s1 ^i64 s2 ^i64 s3]
(+ (* px 257) py))" > demo/stripes.clj
cargo run --release --features demo --bin demo -- demo/stripes.clj
Record to mp4
cargo run --release --features demo --bin record -- \
--kernel demo/fractal.clj \
--seconds 6 --fps 60 --size 960x540 \
--out out/fractal.mp4