Skip to content

sparkles:ui backends — Feature Requirements (TGT)

Status: partial · Date: 2026-08-05 · Scope: the isCanvas seam, the shipped render targets, per-target declared capabilities, and the rules that keep additional backends droppable-in.

Design & rationale

A backend supplies target adaptation, not semantic behavior. It translates native input into the shared vocabulary, measures and paints in device terms, reports capabilities and owns device caches. Decisions about widget composition, semantic state and transitions belong to the toolkit. The drawing contract is a capability concept checked structurally, not an interface: attributes infer correctly, there is no dispatch cost, and a backend need not inherit anything to qualify.

Backends genuinely differ in what they can render, and the honest response is to declare those differences rather than document them in prose and hope. A cell grid cannot draw a corner radius; a fixed-size bitmap font cannot honour a font scale; static HTML cannot express a drag. Each of those is a capability, and a target that cannot serve one should say so where the toolkit can act on it.

This is the boundary PRN8 draws: semantic state and transitions are defined once above the backend. A backend still owns native-input translation, measurement, painting and device caches, and may report a declared degradation; none of those responsibilities licenses a second selection, scroll or activation model.

The canvas seam (TGT1TGT2)

IDRequirementStatusTraces to
TGT1A canvas must satisfy a structural capability concept providing exactly: filled rectangle, text run, single glyph, stroked line, and text measurement. Attributes must be left to infer so a backend needing @system still qualifies.fullcanvas.d isCanvas
TGT2The display list must carry, per operation, both the semantic slot and the resolved appearance, plus the clip state, so a backend never needs to consult the theme or the widget tree.partialcanvas.d DrawOp; display_list.d

Shipped targets (TGT3TGT6)

IDRequirementStatusTraces to
TGT3An immediate interpreter must walk the display list and issue draw calls per frame.fullinterp/immediate.d
TGT4An HTML target must serialize the tree to markup and CSS, with semantic class names and an external stylesheet, and must express tier-0 interactivity in pure CSS with no script.full (9314a49b)interp/html_semantic.d (classes + stylesheet + :hover-reveal/<details>); interp/html.d stays the inline-style parity oracle
TGT5Every target must declare its capabilities — which chrome features it honours and which input tiers it serves — as data the toolkit can inspect, so degradation is reported rather than silent.partial (IXB10)sparkles.input.capability InputCapabilities; RaylibEvents.capabilities, PosixEvents.capabilities. Chrome half not started
TGT6Concrete canvases must live in sibling packages (sparkles:ui-tui, sparkles:ui-raylib), so the toolkit stays backend-free and a consumer links only what it uses.full (2c8356e1, 6b0c9714)libs/ui-tui (GridCanvas), libs/ui-raylib (RaylibCanvas + RaylibEvents)

Current degradations

Honest inventory, to become TGT5 declarations:

FeatureCell targetGPU targetHTML target
corner radiusdropped (box-drawing corners)approximatednative
drop shadowdroppedapproximatednative
single-side accent borderdroppednativenative
dashed / dotted strokeapproximated by underline styleapproximatednative
wavy underlinecurly underline where supporteddrawnnative
font role / scalen/a (single cell metric)dropped (single-size font)native
sub-cell positioningn/aavailablenative
tier-1 inputservedservedunavailable (no script)
hoverservedserved (mouse) / absent (touch)served (:hover)
sub-cell pointerabsent (whole cells)servedn/a
multi-pointerabsent (one pointer)absent (mouse) / served (touch)absent

Forward compatibility (TGT7TGT9)

An additional GPU backend (for example a Skia-class renderer) must drop in beside the existing ones without editing sparkles:ui. That holds only if:

IDRequirementStatusTraces to
TGT7No backend-specific concept — atlas management, a font-set type, a backend's own style bit layout — may appear in the toolkit's vocabulary.fullcanvas.d; style.d
TGT8The visual vocabulary must express intent, not any one backend's workarounds. Radius, shadow and dash style stay first-class even while a backend fakes them by hand; a richer backend renders them natively.fullstyle.d Decoration, Shadow
TGT9The cells→device mapping belongs to the canvas. Layout stays integer-cell (LAY3); a pixel backend may position sub-pixel. Font role and scale must be retained in the vocabulary even where a current backend drops them.partialcanvas scale factors; style.d

Parity harness

IDRequirementStatusTraces to
TGT10The same widget tree must be renderable through every target in a test, with the HTML target usable as a browser ground-truth oracle and a recording canvas as the GL-free assertion seam.partialRecordingCanvas; interp/html.d
TGT11Where a target's appearance mirrors a stylesheet, the values must be asserted in lockstep so drift fails the build.fulltwoslash CSS lockstep tests

Milestones

MilestoneScopeStatusRequirements
B0Adapter packages extracted from their current consumerfull (2c8356e1, 6b0c9714)TGT6
B1Clip state carried through the display listnot startedTGT2
B2HTML target: semantic classes, stylesheet, pure-CSS tier 0not startedTGT4
B3Declared capabilities, with reported degradationpartial — input axes declared and consumed (IXB10); chrome features still proseTGT5
B4Parity harness across every targetpartialTGT10

Module coverage

Source fileRequirements
libs/ui/src/sparkles/ui/canvas.dTGT1, TGT2, TGT7
libs/ui/src/sparkles/ui/display_list.dTGT2
libs/ui/src/sparkles/ui/interp/immediate.dTGT3
libs/ui/src/sparkles/ui/interp/html.dTGT4, TGT10
libs/input/src/sparkles/input/capability.dTGT5
libs/ui-tui/src/TGT5, TGT6
libs/ui-raylib/src/TGT5, TGT6, TGT9

Relationship to existing specs

PieceRole
layout.md LAY3, LAY5the integer-unit rule and the injected measurement primitive
input.md INP6INP9the input half of a target's capabilities and its adapters
theme.md THM3the resolved appearance a canvas consumes
principles.md PRN8, PRN9the shared-semantics and semantic-state boundary
open-issues.md UI-O3the missing native pointer grab in the window/input backend
sparkles:tui, sparkles:raylib-textthe drawing substrates the adapters wrap

Overview · Layout · Input