raygui → keyboard
Many official shapes examples build their UI with raygui sliders and checkboxes. jank-raylib-sys doesn't wrap raygui, so those examples get a keyboard-driven port: sliders become held-key adjustments, checkboxes become toggle keys, and the raygui panel becomes plain DrawText lines showing live values. The pattern was established by easings_testbed.jank and refined across ring_drawing.jank, circle_sector_drawing.jank, rounded_rectangle.jank, and recursive_tree.jank.
The adj helper
One small clamp helper covers every slider:
(defn adj
"Adjust v by step while dn/up are held, clamped to lo..hi."
[v dn up step lo hi]
(let [v (if dn (- v step) v)
v (if up (+ v step) v)]
(if (< v lo) lo (if (> v hi) hi v))))
Call it once per slider in the frame let, feeding IsKeyDown (continuous, slider-like) or IsKeyPressed (stepped, for coarse values like a depth of 1..10):
(let [sa (adj sa (cpp/IsKeyDown cpp/KEY_LEFT) (cpp/IsKeyDown cpp/KEY_RIGHT) 2.0 -450.0 450.0)
segs (adj segs (cpp/IsKeyDown cpp/KEY_O) (cpp/IsKeyDown cpp/KEY_P) 0.5 0.0 100.0)
depth (adj depth (cpp/IsKeyPressed cpp/KEY_Z) (cpp/IsKeyPressed cpp/KEY_X) 1.0 1.0 10.0)]
...)
Pick the step so a slider's full range takes ~2–4 seconds of holding at 60 fps (range / step / 60).
Checkboxes → toggle keys
ring? (if (cpp/IsKeyPressed cpp/KEY_R) (not ring?) ring?)
The panel → text lines
Keep the C's panel geometry (the divider line and tinted rectangle), and replace each GuiSliderBar with a DrawText line naming the value, its current reading, and its keys:
(cpp/DrawText (str "StartAngle: " (fmt1 sa) " (LEFT/RIGHT)") 560 40 10 cpp/DARKGRAY)
(cpp/DrawText (str "[R] Draw Ring: " (if ring? "ON" "OFF")) 560 320 10 cpp/DARKGRAY)
fmt1/fmt2 are the small decimal formatters (there's no format in jank — see jvm-surface-gaps.md). Keep derived readouts from the C, like the MANUAL/AUTO segments mode, including its color switch: (if (>= segs min-segs) cpp/MAROON cpp/DARKGRAY).
Key allocation conventions
- LEFT/RIGHT and DOWN/UP for the two most-adjusted values (angles, primary size).
- A/S, Z/X, O/P as additional +/- pairs (down-key on the left of the physical keyboard pair).
- Single letters for toggles, echoing the raygui checkbox label (
[R] Draw Ring,[B] Bezier). - Q quits — the repo-wide convention — UNLESS the example needs Q or types free text: -
easings_testbed.jankkeeps the C's Q/W duration keys, so only ESC quits there. Document that clearly in every registry surface. -input_box.jankaccepts typed characters, so it quits on Q only while the mouse is OUTSIDE the box. - Always list the full mapping in three places: the namespace docstring, the
bb/helpers.cljcontrols string, and the README table row. Drift between those surfaces is a real failure mode a code review caught (the root README's easings-testbed row omitted the quit key while helpers said "ESC quit").
Porting checklist for a 🎛️ example
- Map every
GuiSliderBarto a key pair +adjcall (note range and a sensible step). - Map every
GuiCheckBoxto a toggle key. - Keep the panel background/divider, replace controls with text lines.
- Preserve derived readouts (mode text, computed minimums) and their colors.
- Check Q is actually free before binding it to quit.
- Smoke-test, registering, committing per porting-workflow.md.