24 raygui examples written in Jolt,
native Clojure on Chez Scheme, no JVM. They call raygui directly over
its C ABI through jolt.ffi: no wrapper library, no codegen,
no C shim. Unlike its sibling, raygui is header-only:
there is no library to install, so this repo vendors the header and
builds lib/libraygui.dylib itself.
basics 4 · inputs 5 · collections 5 · containers 4 · dialogs 2 · color 2 · styling 2. See every one of them.
raygui's API is 61 functions that nearly all share one shape: a
bounding Rectangle passed by value, application
state through a pointer, an int result. Exactly one struct
crosses that ABI by value anywhere in the control surface, which is
rare enough to be worth explaining outright:
Every control takes its bounds as a 16-byte Rectangle
by value. jolt's [:by-value ...] copies those bytes
into caller-owned native memory at call time and never retains the
pointer, so one module-level scratch Rectangle,
rewritten immediately before each call, is safe for all 24
examples. No example allocates or frees a Rectangle
inside a frame.
The only raygui function taking two by-value
Rectangles in a single call: its own bounds and the
size of the content behind it. Clojure evaluates arguments left to
right, so writing both through the same scratch buffer would let
the second write clobber the first before the call ever happens.
scroll-panel gets a second buffer for exactly this.
Every preview on this site is a real capture, not a mockup:
RAYGUI_APP_AUTO_QUIT_MS closes the window on a timer
and RAYGUI_APP_SHOT dumps a frame to PNG first, so a
windowed example proves itself unattended. raygui is mouse-driven
by definition and synthetic clicks don't actuate a real
raylib/GLFW window, so this pair is the only way to verify a
control headlessly, not just the convenient one.
flowchart LR
subgraph ex["24 example namespaces"]
e["basic-controls · sliders · tab-bar
style-selector · scroll-panel · …"]
end
subgraph shared["net.b12n.raygui-jlt.raygui: one shared layer"]
kw["keyword-argument control API
button! · slider! · panel! · …"]
fb["jolt.ffi/defcfn binds
positional, mirroring C"]
kw --> fb
end
lib["lib/libraygui.dylib
built from the vendored header"]
rl["system libraylib
already loaded by the jolt process"]
e --> kw
fb -->|"Rectangle by value, one scratch buffer"| lib
lib -->|"GetMousePosition, DrawRectangle, …"| rl
Every example is a small namespace over that one shared layer. Adding
one touches exactly five places: the source namespace, a
deps.edn alias, a check.clj require, a
registry row in scripts/examples_registry.clj, and a
bb.edn task.
raygui ships one header, not a compiled library: no brew install, no package to find. bb lib:build compiles the vendored raygui.h into lib/libraygui.dylib, linked dynamically against the same raylib the process loads.
All the FFI binds, the keyword-argument control API, and cell handling for all eight cell types live in a single namespace. Examples stay small enough to read in one sitting.
(rg/button! :x 24 :y 24 :w 120 :h 30 :text "Save"): positional binds at the boundary, keyword wrappers on top.
RAYGUI_APP_AUTO_QUIT_MS closes the window on a timer and RAYGUI_APP_SHOT dumps a frame to PNG, so a windowed example can prove itself unattended.
bb check requires every example namespace headlessly. No window, no JVM, and it catches a broken binding across the whole suite at once.
A control drawn at the wrong bounds, or a style that never loaded, compiles perfectly and passes bb check. Looking at the actual PNG is the gate that catches it.
bb lib:check # is raylib installed, and is libraygui already built?
bb lib:build # …compile the vendored header into lib/libraygui.dylib
bb info # grouped cheat-sheet of every example
bb style-selector # run one (opens a window)
bb check # headless compile-check of all 24, no window
Needs jolt and a system libraylib (raygui
links against it dynamically at build time).
babashka
is optional but gives every example a friendly task; without it each one
is a jolt -M:<alias> away.
raygui.h is vendored at 5.0-9-gfbf5d95, zlib licensed, the
same license this repo ships under.