# glimmer-jvui The **jvui** backend for [glimmer](https://github.com/jolt-lang/glimmer), the reactive GUI toolkit for [jolt](https://github.com/jolt-lang/jolt). glimmer owns the portable half — reactive cells, the component model, the reconciler — and knows nothing about any toolkit. This project supplies the other half out of [`../../jvui`](../../jvui), which is dvui's shape written in jolt on SDL3. Requiring `glimmer-jvui.core` registers it, and components that render as GTK widgets under [glimmer-gtk](https://github.com/jolt-lang/glimmer-gtk), as egui under [glimmer-vidya](../glimmer-vidya) and as text under [glimmer-tui](../glimmer-tui) render here as jvui. ```clojure (ns myapp (:require [glimmer.ratom :as ra] [glimmer.core :as ui] [glimmer-jvui.core])) ; installs this backend (defn counter [] (let [n (ra/atom 0)] (fn [] [:card {} [:title {:label "Counter"}] [:label {:label (str "Count: " (ra/deref n))}] [:hbox {:spacing 8} [:button {:label "- 1" :on-click #(ra/swap! n dec)}] [:button {:label "+ 1" :kind :primary :on-click #(ra/swap! n inc)}]]]))) (defn -main [& _] (ui/run counter {:title "myapp" :max-width 420})) ``` ```bash jolt test # headless: no window, no SDL, no font, no display jolt counter # a window jolt counter --shot ``` ## The smallest of the four backends A glimmer backend usually has to supply everything a toolkit would have done for it. [glimmer-gfx](../glimmer-gfx) writes its own measure, place, paint and hit test, because there is nothing underneath it. [glimmer-vidya](../glimmer-vidya) keeps a node arena in Rust behind a second C ABI, because egui hands a reconciler nothing to hold. Here none of that is needed, because jvui is a toolkit rather than an ABI. What is left is the one thing an immediate-mode library does not have — somewhere to put a widget between frames — and it is thirty lines of atoms: src/glimmer_jvui/core.clj the tree, the walk, the loop `create!` makes an atom, `append-child!` conjes onto a vector, and once a frame `emit!` walks that tree and calls the jvui widget each node names. Layout, clipping, focus, capture and painting are jvui's. ## Three things worth knowing **The walk is the closure.** glimmer-vidya's README explains why its tree lives in Rust: egui's `ScrollArea` and `Frame` take an `FnOnce(&mut Ui)` and keep their begin/end private, so a push/pop ABI cannot scroll a page. jvui's containers take a body function for the same reason — and here the recursion *is* that function. `emit!` on a container hands `emit-children!` over as the body and the nesting takes care of itself, which is why there is no push/pop anywhere in this file. **Every node carries a key.** jvui identifies a widget by its parent and its index among its siblings, unless it is given a `:key`, which *replaces* the index. A reconciler reorders children, and an identity built on the index would hand every widget after the moved one the caret, the scroll offset and the drag of whichever widget used to sit at its index. So each node takes a serial number at creation and passes it as its key, and identity follows the node rather than its position. That is the bug class [zvui](../../zig/jolt-zvui)'s README describes from the backend side, closed here at the other end — and `jolt test` reorders a list and checks it. **A re-render is queued, never inline.** A handler fires in the middle of the walk, and a ratom change would have the reconciler patch the tree while it is being walked — half the frame old, half new. `:schedule` queues the work and jvui's `:before` hook drains it at the top of the next frame, before anything is placed. ## What renders Containers: `:page` `:card` `:frame` `:vbox` `:box` `:hbox` `:scroll`. Widgets: `:title` `:label` `:dim-label` `:button` `:checkbox` `:slider` `:entry`/`:text-entry` `:progress` `:separator` `:spacer`/`:gap`. Props are the vocabulary the other backends share — `:label`/`:text`, `:spacing`, `:padding`, `:margin`, `:orientation`, `:max-width`, `:kind`, `:checked`, `:value`/`:min`/`:max`, `:placeholder`, `:dim`, `:size`, `:on-click`, `:on-change`. An unknown tag is a container rather than an error, so a tree written against a richer backend still shows its contents — the same bargain jolt-zvui makes. ## Not done Everything jvui has not got, and nothing else: one font style, no text selection, vertical scrolling only, no animation clock, no menus or dialogs. `:sensitive`, `:multiline` and `:fill-height` are accepted and ignored.