glitter-gl Guide
Why this exists
glitter-gl is glimmer-gl's geometry/matrix/shader/GL library, ported onto glitter instead of glimmer. Most of it (vectors, matrices, meshes, the shader DSL, raw GL bindings, the renderer) has no dependency on either UI library at all and ports across unchanged. The part that does (a :gl-area widget so a GL pane can live inside a glitter hiccup tree) needed real adaptation, and hit a real, live-found correction along the way. This guide covers that adaptation.
What glitter-gl is
A .clj (Jolt/Chez Scheme host, not JVM) library, split into two halves:
- Pure geometry/matrix/mesh/shader/GL code: usable from any Jolt program with an OpenGL context, glitter or not.
glitter-gl.gtk/.scene/.app, the glitter-specific layer: a:gl-areawidget, a declarative scene graph, and a reactive mount point built around glitter's single state atom.(require '[glitter.app :as app] '[glitter.core :as core] '[glitter.gtk :as gtk] '[glitter-gl.gtk]) ; registers :gl-area (defn view [_state] [:gl-area {:version [3 2] :hexpand true :vexpand true :on-realize (fn [area] ...) :on-render (fn [area] ...) :on-resize (fn [area w h] ...)}]) (app/run (fn [window] (gtk/mount! window view (atom {}))))
Every :gl-area prop key with an :on-* handler wires into a raw GTK4 signal (or, for :on-tick, a frame-clock callback) the first time it's seen; :on-render's closure is free to read whatever state it needs on each call, exactly like any other glitter view function.
Pages
Orientation
examples.md: the ten namespaces underexamples/glitter_gl/, split by what each is for:check.cljandgl_area_smoke.cljexist to fail when a regression lands (the only two wired intobb smokes),plasma_shader.cljexists to be composed and read (the shader-composition worked example), andplasma.clj,ripple.clj,orbit.clj,knot.clj,gears.clj,textured.cljandpicking.cljexist to be watched: rotating-shape, shader, texture and pointer-input demos with no assertions of their own. Also covers the six touchpoints (namespace,deps.ednalias,bb.edntask,bb.edndemos:examplesrow,scripts/demo_manifest.edngroup entry,smokesentry) a new example needs so it doesn't go silently unexercised.architecture.md: how thin the seam to glitter actually is: of 25 files undersrc/glitter_gl/, onlygtk.cljhas a literal:requireonglitter.*, andscene.cljhas none at all. Traces, against the real source, why a:gl-areakeeps redrawing (queue-renderhas exactly one call site in the whole project:gtk.clj'sgl-area-apply!tick wrapper, whichreactive-areaalways causes to be installed, and a bare stateswap!alone never triggers a repaint), plus why:gl-areabypasses glitter's uniform signal table entirely and where GL-plumbing state deliberately breaks glitter's one-atom/action-dispatch discipline.porting-and-attribution.md: the three sourcing bucketsNOTICE.mdtracks (22 verbatim glimmer-gl files, 3 adapted core files plus demo material, and what's genuinely new), and the two-hop lineage back through glimmer-gl to thi.ng/geom. Explains the Standard Verbatim Port Procedure's sed-diff check that makes "verbatim port" a checkable claim rather than an assertion, the formatting-pass exemption that lets project-wideclojure-lsp format/clean-nstouch those 22 files without violating it, and the one documented live-found correction (:gl-area's:apply-vs-:connectfix) told from the provenance angle.
The library layer
geometry-and-shaders.md: orientation, not reference, over the 22 verbatim-ported namespaces: the three groups (14 pure geometry/math, 4 mesh, 4 GL plumbing), and the two design decisions (column-major matrices, shaders as mergeable data) a new reader would otherwise have to reconstruct by hand. Traces where a mesh becomes GL data and finds a real surprise along the way:glmesh.clj's documented mesh โ GL pipeline has no caller anywhere but its own test; the shipped renderer hand-rolls the actual upload viamesh/->floatsand eleven rawgl.cljcalls instead.
GTK integration
gl-area-widget-layer.md: the:gl-areawidget's mechanics in full: the:apply-vs-:connectcorrection, traced throughcreate-node/set-attributesto the exact reason a:connectclosure never sees a real prop map under glitter's reconciler. Catalogs every GTK4 signal shape that doesn't fit glitter's uniformvoid(widget,data)path:"render"'s non-void return,"resize"'s extra int arguments,on-tick's frame-clock API that isn't a signal at all, and the controllerson-motion/on-key/on-buttonlayer onto the widget or its root window. Also documents a live-found Retina-only trap:"resize"reports device pixels whileon-motionreports logical points, and unprojecting a pointer position with the wrong one is silently wrong by the display's scale factor.scene-and-app.md:glitter-gl.scene's mini-hiccup dialect, and why it's not glitter's hiccup:[fn args...]is a first-class component invocation here, a real trap in both directions the page states plainly with a live example (plasma.clj's once-brokenshape-buttoncalls). Explains whyplanis a plain function with no reactive-cell tracking, the write-once handler contractgtk.clj'swiredatom enforces, and givesreactive-areaan honest status note: unit-tested, and now exercised live end to end byexamples/glitter_gl/orbit.clj, plus the per-tick full-view-recompute cost that demo pays.
Verify
testing-and-tasks.md: the unit suite (jolt -M:test, 178 tests / 559 assertions) and the live-GTK smoke plus headless checkbb smokesruns, plusoffscreen_test.clj's real render-to-texture round trip and its designed-to-skip behavior on a display-less machine. Documents thejolt -M:<alias>vsjolt <task>exit-code trap (reproduced acrossv0.6.3andv0.7.23, and confirmed fixed on joltmainatv0.7.27-22, though no tagged release carries the fix yet) and the quality-tooling surface (bb lint,bb lsp:*, the FFI-aware clj-kondo hook,bb verifyvs. the stricter git pre-commit hook).limitations.md: every known v1 gap, each with the reason it was left rather than fixed:"render"'s 2-argforeign-callabledeclaration against GTK4's real 3-argument signal (harmless, traced through the calling convention, not just asserted), the dev-time hiccup warning that has no application-level silencer, and why:scaleis deliberately not registered here.
See also
CONTRIBUTING.md(repo root): how to build, test, and submit changes, plus the ten numbered invariants this project does not regress (the:gl-areacorrection is invariant #2 there, in summary form).NOTICE.md(repo root): the file-by-file attribution ledger and porting summary (verbatim / adapted / new buckets).- glimmer-gl: the library this project ports from.
- glitter: the renderer this project extends; see its own
docs/guide/for the reconcile โIRender/IMemoryarchitecture and the GTK widget layer this project's:gl-areaplugs into.