Concept
Goldberry draws every pixel itself, describes a screen as data, and keeps the native code behind one boundary. This page is the idea in five parts and what each one buys.
One rendering pipeline, everywhere
Goldberry does not wrap the platform’s widgets and does not embed a browser. A button on Linux, Windows and macOS is the same button: the same CSS rule, the same Yoga layout, the same Blend2D rasterization, the same HarfBuzz-shaped text in the same embedded fonts. The platform supplies a window, input events, the clipboard and a surface to present into, through SDL3. Everything above that line is Java and runs identically on every desktop.
The result is deterministic. A frame is the same bytes on every machine, which is what lets the toolkit test itself with golden images and lets an application do the same (ADR-0002, ADR-0003).
A screen is a description
A widget is an immutable Java record with a pure build(). The toolkit calls
build(), diffs the result against the element tree it kept from the last
frame, and updates only what changed. State that must survive a rebuild, a hover
or a caret, lives on the element rather than on the widget
(ADR-0004,
ADR-0052).
The same tree can be written as KDL markup, and every built-in widget exists three ways: a record, a node name and a CSS type (ADR-0059).
row id="confirm" {
spacer
button press="dismiss" "Cancel"
button class="danger" press="delete" "Delete"
}
new Row(
new Spacer(),
new Button("Cancel", this::dismiss),
new Button("Delete", this::delete).styled("danger")
)
Markup names things and never contains code. A press= names an action, a
bind= names a value, an icon= names an icon. Each resolves against a
registry the application supplied, and a name that resolves to nothing fails
when the document is inflated rather than when the user clicks
(ADR-0062).
Data flows down, events flow up
A control never owns its value. It is handed an Observable and draws what it
reads. When the user acts, the control raises an action, the application’s
handler assigns a field, and the new value flows back down. A checkbox whose
tick will not move is a handler that did not change the state, which is where
the bug is (ADR-0063).
The model is plain Java: a class of fields marked @Bind, and methods marked
@Action. On the JVM the toolkit binds them reflectively at run time. For a
native image a build step rewrites the compiled class so that every assignment
notifies directly, with no reflection anywhere
(ADR-0155).
Model weaving is the whole story.
Real CSS, real flexbox
Styling is a genuine subset of CSS: selectors, the cascade in layers, custom properties, inheritance, transitions on a frame clock, transforms and opacity. Layout is flexbox, through Yoga bound directly rather than reimplemented (ADR-0005).
Every colour a control uses is a --gb-* token, so switching from the Nord
dark theme to the Nord light one restyles every control though no rule names a
colour. Density is three tokens on :root. Markup and stylesheets hot-reload
while the application runs (Styling).
Light to ship
The toolkit has no third-party Java dependencies. The native libraries are
statically linked into one libgoldberry per platform, shipped as a classifier
jar and bound through hand-written FFM calls that live in one module
(ADR-0007,
ADR-0010).
An application runs as a plain jar on any JDK 25, or compiles with GraalVM into one executable with the library inside it. The native showcase is 41 MiB, opens its window in about 120 ms and paints a headless frame in about a millisecond (Native image, ADR-0506).
What it is built on
| Library | Role | Where it lives |
|---|---|---|
| Blend2D | 2D rasterization, with its PNG, JPEG and QOI codecs | inside libgoldberry |
| Yoga | flexbox layout | inside libgoldberry |
| HarfBuzz | text shaping | inside libgoldberry |
| SDL3 | windows, input, clipboard, popups, tray, SDL_GPU | inside libgoldberry |
| md4c | Markdown parsing | inside libgoldberry |
| libwebp | WebP decoding | inside libgoldberry |
| FFmpeg | audio and video decoding | goldberry-media, as separate shared libraries |
| Inter, JetBrains Mono | the UI and code typefaces | inside goldberry-core |
| Lucide | 1544 icons as path data | inside goldberry-core |
| Noto Color Emoji | the emoji face | goldberry-emoji |
Everything in the table is open source, and the licences travel inside every
jar under META-INF/
(ADR-0015).