1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
#+TITLE: Panel & Waybar Design Prototypes
#+AUTHOR: Craig Jennings
Self-contained HTML/CSS design prototypes for the instrument-console panel
family and the waybar redesign. Each opens standalone in a browser (no external
assets). These are the normative visual references the specs in [[file:../specs/][docs/specs/]]
point at.
* Prototypes
- [[file:2026-07-03-instrument-console-panels-prototype.html][2026-07-03-instrument-console-panels-prototype.html]] — the net + bluetooth
pair; the approved faceplate design that shipped. Normative reference for
[[file:../specs/2026-07-03-instrument-console-panels-spec.org][the instrument-console spec]].
- [[file:2026-07-03-net-panel-rescan-prototype.html][2026-07-03-net-panel-rescan-prototype.html]] — the manual rescan/scan ⟳
affordance for the NETWORKS/NEARBY headers (busy-style throbber + list fade).
- [[file:2026-07-03-sound-panel-prototype.html][2026-07-03-sound-panel-prototype.html]] — the audio/pulsemixer console; layout
reference for [[file:../specs/2026-07-03-audio-panel-spec.org][the audio-panel spec]].
- [[file:panel-widget-gallery.html][panel-widget-gallery.html]] — the shared instrument-console
widget kit (lamps, engraved sections, console keys, needle gauges). The
living catalogue: every widget here is the visual + behavioral spec for
its reusable-component ports. All widgets build from [[file:widgets.js][widgets.js]] (below);
the gallery page is the reference consumer.
- [[file:2026-07-03-waybar-redesign-prototype.html][2026-07-03-waybar-redesign-prototype.html]] — three directions for sprucing up
waybar in the dupre instrument-console aesthetic (future work).
* Widget library ([[file:widgets.js][widgets.js]])
The whole kit lives in =widgets.js= — a classic script (no modules, no build
step) exposing the =GW= namespace with one builder per gallery card. Load it
with =<script src="widgets.js"></script>= and call builders directly.
** Builder contract
=GW.name(host, opts)= → handle ={el, get, set, ...}=. =host= is an empty
element the widget renders into. =opts.onChange(value, text)= fires on every
state change, including the initial paint; =text= is the widget's canonical
readout string. (Exception: live meters whose original init was silent — they
paint on the first =set=/=push=.)
** Styling
Widget-internal CSS ships inside =widgets.js= (the =GW_CSS= block, injected
once as =<style id="gw-css">= at load), so widgets are fully styled on any
page. The design tokens (=--gold=, =--glow-hi=, the amber family, =--mono=,
=--pulse-rate=, …) must be defined on =:root= by the consumer — the gallery's
generated =:root= block is the reference; =tokens.json= is the source.
** Tick contract (live meters)
The page owns the clock and the signal source; builders own rendering state.
Live meters expose value-driven handles that repaint synchronously and fire
=onChange=:
- =set(level)= for level meters (peak-hold logic lives in the builder)
- =push(v)= / =set(samples, current)= for history meters (the builder owns
the ring buffer)
- =set(samples, amp)= for sampled traces (samples normalized)
Widget-owned animation (the R17 scope trace, R31 radar sweep, R44 servo
chase, R52 pseudo-PC, R53 day clock, R10 TIME page) runs inside the builder,
gated on =prefers-reduced-motion=.
** Style options
Widgets with named style axes take them as constructor opts backed by a
=STYLES= table on the builder — e.g. =GW.slideToggle(host, {onStyle:'green',
thumb:'brass'})= with the axes enumerated in =GW.slideToggle.STYLES=, and
=handle.setStyle(axis, name)= to restyle a live instance. The gallery's
option chips are demo rigs driving =setStyle=.
** Verification
=tests/gallery-probes/= drives the full kit headlessly over CDP:
=probe.mjs= (every card renders + responds, size toggle, drags at zoom) and
=probe-fams.mjs= (screen-family retinting). Run with =node= against the
gallery file URL; both must pass before a gallery or widgets.js change lands.
* Design tokens (single source, three targets)
[[file:tokens.json][tokens.json]] is the source of truth for the design tokens (palette, amber
family, glows, pulse rate). [[file:gen_tokens.py][gen_tokens.py]] regenerates all three targets
(=python3 gen_tokens.py=):
- the =:root= block inside the gallery HTML (web CSS custom properties)
- [[file:tokens-waybar.css][tokens-waybar.css]] — GTK =@define-color= declarations for the waybar panels
- [[file:gallery-tokens.el][gallery-tokens.el]] — an elisp alist for svg.el renderers
[[file:gallery-widget.el][gallery-widget.el]] is the Emacs renderer (proof widget: the needle gauge,
gallery card 10) — it reads gallery-tokens.el and emits the widget as SVG via
svg.el, so the same look renders inside Emacs. Tests:
=tests/gallery-tokens/= (generator, unittest) and =tests/gallery-widgets/=
(renderer, ERT), both in =make test-unit=.
|