raylib examples in Jolt

raylib-jlt.b12n.app · 2026-08-20 · by Long Nguyen ·generic
b12n-raylib-jlt — raylib examples in Jolt. A community suite of raylib examples written in native Clojure, calling libraylib directly over jolt.ffi.

raylib examples in Jolt

A few of them

Tetris — falling tetrominoes stacking in a well bb tetris Boids — a flock steering by separation, alignment and cohesion bb boids A Sun, Earth and Moon orbiting via the rlgl matrix stack bb rlgl-solar-system A chain of rotating circles tracing a square wave bb fourier-epicycles A chaotic double pendulum drawing a trail bb double-pendulum A P3 Penrose rhombus tiling built by golden-ratio deflation bb penrose-tiling A row of 3D cubes each spinning with a phase offset bb spinning-cubes Asteroids — a ship rotating, thrusting and splitting asteroids bb asteroids

games 10 · core 9 · shapes 32 · text 5 · 3d 12 · generative 7 — every one of them, full size.

Why this is interesting

raylib passes structs by value everywhere, and Chez's `foreign-procedure` cannot. Nothing here works around that with a C shim — instead each struct gets the treatment its size and contents actually earn on the ABI. Three facts drive every distinctive decision in the binding layer:

  • #### Color → a packed :uint
  • `Color` is 4 bytes of `u8`, and a 4-byte all-integer struct travels in one general-purpose register — exactly like a `uint32`. So every draw call passes color as an int, and no struct marshaling happens at all.
  • #### Camera2D / Camera3D → by pointer
  • A composite larger than 16 bytes is passed indirectly on AArch64 — the caller allocates a copy and passes its address. So the 24-byte `Camera2D` and 44-byte `Camera3D` are built in native memory and bound as `[:pointer]`. This one is AArch64-specific, and the guide says so plainly rather than pretending it ports.
  • #### Vector2 / Vector3 → rlgl immediate mode
Small float structs go in floating-point registers, which the pointer trick does not cover. So geometry that takes a `Vector2` or `Vector3` by value is drawn with rlgl's scalar immediate mode instead — `rlVertex3f`, `rlColor4ub`, and the matrix stack for nested transforms.

How it fits together

flowchart LR subgraph ex["75 example namespaces"] e["pong · boids · tetris camera-3d · penrose-tiling · …"] end subgraph shared["net.b12n.raylib-jlt.raylib — one shared layer"] kw["keyword-argument drawing API text! · rect! · circle! · cube!"] fb["jolt.ffi/defcfn binds positional, mirroring C"] kw --> fb end lib["system libraylib dlopened at runtime, C ABI"] e --> kw fb -->|"Color as a packed :uint"| lib fb -->|"Camera2D/3D by pointer"| lib fb -->|"rlgl scalar immediate mode"| lib Every example is a small namespace over that one shared layer. Adding one touches exactly four places — the source namespace, a `deps.edn` alias, a `check.clj` require, and a `bb.edn` registry row.

What's here

#### One binding layer

All the FFI binds, the keyword-argument drawing API, and the named color palette live in a single namespace. Examples stay small enough to read in one sitting.

#### Reads like Clojure, not like C

`(rl/circle! :x 400 :y 225 :radius 50 :color rl/MAROON)` — positional binds at the boundary, keyword wrappers on top.

#### Provable without a display

`RAYLIB_APP_AUTO_QUIT_MS` closes the window on a timer and `RAYLIB_APP_SHOT` dumps a frame to PNG — so a windowed example can prove itself unattended.

#### A compile gate over all 75

`bb check` requires every example namespace headlessly. No window, no JVM, and it catches a broken binding across the whole suite at once.

#### clj-kondo taught the FFI

A hook rewrites each `defcfn` into an equivalent `defn`, so call sites get arity- and return-type-checked instead of producing \~500 false positives.

#### Not only raylib

The two clock examples call plain libc `time()` / `localtime()`, reading `struct tm` straight out of native memory. Nothing about `jolt.ffi` is raylib-specific.

Quickstart

bb lib:check       # is the native libraylib installed for this OS/arch?
bb lib:install     # …install it via brew / pacman / apt / dnf / zypper / apk

bb info # grouped cheat-sheet of every example bb tetris # run one (opens a window) bb run-all 10 # demo reel: every example, 10s each bb check # headless compile-check of all 75, no window

Needs `jolt` (tested against v0.7.16) and a system `libraylib`. babashkais optional but gives every example a friendly task; without it each one is a `joltc -M:<alias>` away. Released under the zlib/libpng license — the same one raylib itself uses.

raylib-jlt.b12n.app · 8 images · 14 links

Comments (0)

No comments yet