# glimmer-gfx glimmer's **software** backend: no toolkit, no shared object, no GPU. The rasterizer, the layout and the font are jolt; the only foreign code is Xlib, and Xlib draws nothing — it opens a window and takes a finished framebuffer. It is [glimmer-vidya](../glimmer-vidya) with nothing underneath it. The reconciler does not know what it is patching, so the same hiccup that egui paints as a window and [glimmer-tui](../glimmer-tui) paints as cells is painted here, a pixel at a time, by code in this directory: ```clojure (ns myapp (:require [glimmer.ratom :as ra] [glimmer.core :as ui] [glimmer-gfx.core])) ; installs this backend (defn app [] [:card {:spacing 8} [:title {:label "Counter"}] [:label {:label (str "Count: " (ra/deref count))}] [:button {:label "+ 1" :kind :primary :on-click #(ra/swap! count inc)}]]) (defn -main [& _] (ui/run app :title "myapp")) ``` ## Running ```bash jolt test # headless: no window, no display LD_LIBRARY_PATH=/path/to/libX11 jolt counter ``` Xlib is a *system* library here, not one of this repo's crates, and it must be one the jolt binary can load — on a nix-built jolt, the host `/usr/lib` copy is a different glibc and fails before `dlopen` returns. ## What a backend has to do Read this one first. It is the smallest complete backend in the repo, and the only one where every part of the answer is visible rather than behind an ABI. src/glimmer_gfx/raster.clj framebuffer, rect/line, a 3x5 font no FFI src/glimmer_gfx/core.clj the backend: tree, layout, paint no FFI src/glimmer_gfx/x11.clj the window, and nothing else `glimmer.backend`'s map is mostly trivial — `create!` allocates an atom, `append-child!` conjes onto a vector. The work is what a toolkit would have done for you: * **A tree to patch.** The reconciler needs somewhere to hold widgets between frames, which an immediate-mode painter has not got. Here it is atoms of `{:tag :props :children}`, about 60 lines. glimmer-vidya needs the same thing and keeps it in Rust behind a second C ABI, because egui hands the reconciler nothing to hold. * **Layout.** `measure!` sizes bottom-up, `place!` positions top-down. This is most of the file. `:spacing`, `:max-width` and container padding are honoured; `:align` and `:grow` are not, so children keep their measured width, left-aligned. * **Hit testing.** Deepest interactive node under the cursor, last match wins. A press claims a widget and holds it until release, so a slider keeps tracking when the pointer leaves its rect. Tags: `:page` `:card` `:vbox` `:hbox` `:title` `:label` `:button` `:checkbox` `:slider` `:spacer`. Props are the shared vocabulary — `:label`, `:spacing`, `:max-width`, `:kind`, `:checked`, `:value`/`:min`/`:max`, `:on-click`, `:on-change`. ## Text There is no font stack. `raster.clj` carries a 3x5 bitmap font for ASCII, authored as art and editable in place: "A.#.|#.#|###|#.#|#.#" It scales by whole pixels, which is why the UI looks like it does. A real font means FreeType, which means a crate — at which point this stops being the backend that runs anywhere.