From bc93388ddd5309476eac0a4547d6b66ab9fbb172 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 12 Jul 2026 19:06:39 -0500 Subject: feat(gallery): gallery upgrades — size/palette/screen-chips/spec-sheets, 25 new cards, grammar note MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Squash of the gallery-upgrades branch (25 commits). Usability: widget stages scale S/M/L (2.4x default), reading text at 12-13pt, a live palette section parsed from the generated :root block, screen-color families with per-card chips on the five screen widgets, and a collapsible spec sheet on every card (input model, solves, use, limits, origin, difficulty, prefer-when, period on the non-timeless). Collection grew 84 → 109 cards, all CDP-verified: reference cards R32-R36 (mechanical timer, four-way rocker, four-way toggle, day-date discs, LED dot matrix), the takuzu-survey build R37-R47 plus the N23 alarm lifecycle (pin matrix, dead-man, rotary dial, breaker panel, DSKY, cam timer, attitude indicator, heading bug, flip-disc, dekatron, landing gear), the promoted banked six R48-R53 (knife switch, decade box, two-hand control, voice-loop keyset, blinkenlights, circular chart), and the Ki-57/comfort-meter trio R54-R56 (vertical tape, twin-needle, comfort-zone crossed needles). Also: docs/design control-grammars reference note (taxonomy sources and proposed axes for the classification work), nine reference photos filed, and a component cleanup pass (dial digits above the finger wheel, legible demo defaults, unified captions). --- .../2026-07-12-control-grammars-reference.org | 48 + docs/prototypes/panel-widget-gallery.html | 1979 +++++++++++++++++++- 2 files changed, 1976 insertions(+), 51 deletions(-) create mode 100644 docs/design/2026-07-12-control-grammars-reference.org (limited to 'docs') diff --git a/docs/design/2026-07-12-control-grammars-reference.org b/docs/design/2026-07-12-control-grammars-reference.org new file mode 100644 index 0000000..4d5e028 --- /dev/null +++ b/docs/design/2026-07-12-control-grammars-reference.org @@ -0,0 +1,48 @@ +#+TITLE: Control Grammars and Interaction Taxonomies — Reference Note +#+AUTHOR: Craig Jennings +#+DATE: 2026-07-12 + +Source material for the widget-gallery classification brainstorm (todo.org "Widget gallery upgrades" → "Component classification taxonomy"). The gallery is at 100 cards; every card's spec sheet already records its input model. This note collects the vocabulary and the literature the taxonomy should build on, so the brainstorm starts from named prior art instead of re-deriving it. + +* The named control grammars + +A control grammar is the sentence structure of an interaction — what order the operator supplies action, operand, and commitment. The kit already holds an exemplar of each: + +- Verb-noun :: action first, then operand. DSKY (R41): VERB 35 ENTR. Command lines and vi's =d2w= are the software descendants. +- Noun-verb (object-action) :: select the thing, then act on it. Every modern GUI; in the kit, the waveform region editor (R19) — pick a flag, then move it. +- Modal :: the same inputs mean different things depending on a mode set elsewhere. The keyed mode switch (N06) is the hardware form; vi is the canonical software one. +- Quasimode (held state) :: the state exists only while physically maintained; release returns to baseline. Dead-man button (R38), push-to-talk, the shift key. Term coined by Raskin. +- Chorded :: simultaneous inputs form one command. Key chords; the two-hand anti-tie-down control is the safety-hardware form. +- Arm-then-commit :: a two-step grammar where the first action only enables the second. Arm-to-fire (08), guarded toggle (R29). +- Direct manipulation :: no grammar — the operand is dragged itself. Faders, the response graph (R26), the attitude indicator (R43). Shneiderman's term. + +* The literature + +No single canonical registry of control grammars exists. The concept is split across these traditions, listed by usefulness to this project: + +- Moran, "The Command Language Grammar" (1981, Int. J. Man-Machine Studies) :: origin of the phrase; models a whole interface as a layered grammar (task, semantic, syntactic, interaction levels). +- Foley, Wallace & Chan, "The Human Factors of Computer Graphics Interaction Techniques" (1984, IEEE CG&A) :: the classic six elemental interaction tasks — select, position, orient, path, quantify, text. The strongest single candidate for the taxonomy's use-axis; most of the 100 cards drop cleanly into one of the six. +- Buxton, "Lexical and Pragmatic Considerations of Input Structures" (1983) and the three-state model of graphical input (1990) :: formal state machines for hover/drag/click; the right lens for the drag-vs-click portability question (Emacs has states 0 and 2 but not smooth state-1 motion). +- Card, Mackinlay & Robertson, "A Morphological Analysis of the Design Space of Input Devices" (1991) :: a design-space grid (linear/rotary × position/force × dimensions) that classifies the physical inputs themselves. +- Raskin, *The Humane Interface* (2000) :: modes vs quasimodes, and why held state beats latched state for safety-relevant functions. +- Shneiderman, "Direct Manipulation: A Step Beyond Programming Languages" (1983, IEEE Computer) :: the case for grammar-free interaction. +- MIL-STD-1472 (Human Engineering) and NASA's Human Integration Design Handbook (HIDH, NASA/SP-2010-3407) :: the closest thing to "the definition of them all" for physical controls — catalogs of control types (toggle, rotary selector, thumbwheel, legend switch, handwheel...) with selection criteria, spacing, resistance, and coding rules. FAA HF-STD-001 is the aviation equivalent. + +* Proposed axes for the classification brainstorm + +Starting point, to be argued in the brainstorm, not settled here: + +1. Elemental task (Foley) :: select / position / orient / path / quantify / text — plus the display-side tasks the gallery adds (indicate state, indicate quantity, indicate history, indicate spatial status). +2. Input model :: none (display) / click / click-step / drag-1D / drag-2D / held / composed. Already on every spec sheet; drives Emacs portability directly. +3. Grammar :: the seven above. Orthogonal to input model — a click can belong to any grammar. +4. Cardinality of the value :: binary / one-of-N / many-of-N / many-to-many / continuous scalar / 2-axis / bitmap / compound. +5. State authority :: operator-set / system-set (breaker trip, servo needle) / co-set (heading bug vs actual). +6. Persistence :: latched / held / transient / mechanical-persistent (flip-disc). +7. Era :: the period field, where not timeless. + +The gap-finding move the brainstorm exists for: cross axes 1×4 and look for empty cells — a use-case with no component is a cell the catalogue cannot fill. + +* Related + +- Gallery: [[file:../prototypes/panel-widget-gallery.html][docs/prototypes/panel-widget-gallery.html]] (100 cards, spec sheets carry input model + period). +- Source survey: takuzu =working/research/ui-components/historical-panel-components.org= (processed 2026-07-12; build + banked + stale verdicts recorded in todo.org). diff --git a/docs/prototypes/panel-widget-gallery.html b/docs/prototypes/panel-widget-gallery.html index f8330bb..d67034b 100644 --- a/docs/prototypes/panel-widget-gallery.html +++ b/docs/prototypes/panel-widget-gallery.html @@ -44,7 +44,7 @@ /* @tokens:end */ } *{box-sizing:border-box;margin:0;padding:0} -html{background:var(--ground)} +html{background:var(--ground);font-size:130%} body{font-family:var(--mono);color:var(--silver);padding:2.4rem 2rem 5rem;line-height:1.45; background:radial-gradient(1200px 600px at 70% -10%,#1c1915 0%,transparent 60%),var(--ground)} .wrap{max-width:1320px;margin:0 auto} @@ -52,6 +52,24 @@ body{font-family:var(--mono);color:var(--silver);padding:2.4rem 2rem 5rem;line-h h1{color:var(--gold);font-size:1.5rem;margin:.35rem 0 .4rem} .masthead p{color:var(--dim);font-size:.86rem;max-width:86ch} .masthead p b{color:var(--silver)} +.szbar{display:flex;align-items:center;gap:8px;margin-top:.8rem} +.szbar .lab{color:var(--steel);font-size:.68rem;letter-spacing:.22em;text-transform:uppercase;margin-right:4px} +/* size toggle scales the widget stage only; card text stays at its own (slightly raised) size */ +body[data-size="2"] .stagew{zoom:1.7} +body[data-size="3"] .stagew{zoom:2.4} +body[data-size="2"] .grid{grid-template-columns:repeat(auto-fill,minmax(380px,1fr))} +body[data-size="3"] .grid{grid-template-columns:repeat(auto-fill,minmax(520px,1fr))} +body[data-size="2"] .wrap,body[data-size="3"] .wrap{max-width:none} + +.secnote{color:var(--dim);font-size:.74rem;margin-top:.5rem;max-width:86ch} +.palgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(176px,1fr));gap:10px;margin-top:1rem} +.swatch{background:linear-gradient(180deg,var(--raise),var(--panel));border:1px solid #262320;border-radius:9px; + padding:9px;display:flex;flex-direction:column;gap:6px} +.swatch .sw{height:44px;border-radius:6px;border:1px solid rgba(255,255,255,.08)} +.swatch .sw.txt{display:flex;align-items:center;justify-content:center;color:var(--steel);font-size:.62rem; + background:var(--well);padding:0 6px;text-align:center;overflow:hidden} +.swatch .swn{color:var(--cream);font-size:.8rem} +.swatch .swv{color:var(--dim);font-size:.74rem;font-variant-numeric:tabular-nums;overflow-wrap:anywhere} h2{color:var(--steel);font-size:.74rem;letter-spacing:.24em;text-transform:uppercase; margin:2.2rem 0 .2rem;display:flex;align-items:center;gap:12px} h2::after{content:"";height:1px;background:var(--wash);flex:1} @@ -60,16 +78,28 @@ h2::after{content:"";height:1px;background:var(--wash);flex:1} .card{background:linear-gradient(180deg,var(--raise),var(--panel));border:1px solid #262320;border-radius:12px; padding:13px 14px 12px;display:flex;flex-direction:column;gap:9px; box-shadow:inset 0 1px 0 rgba(255,255,255,.04),0 6px 14px rgba(0,0,0,.4)} -.wname{color:var(--cream);font-size:.82rem;font-weight:700;display:flex;align-items:center;gap:8px} -.wname .no{color:var(--panel);background:var(--gold);border-radius:4px;font-size:.6rem;padding:0 5px;font-weight:400} +.wname{color:var(--cream);font-size:.95rem;font-weight:700;display:flex;align-items:center;gap:8px} +.wname .no{color:var(--panel);background:var(--gold);border-radius:4px;font-size:.7rem;padding:0 5px;font-weight:400} .stagew{background:var(--well);border:1px solid #201d17;border-radius:9px;padding:14px 12px; min-height:78px;display:flex;align-items:center;justify-content:center;gap:12px;flex-wrap:wrap} -.wrd{color:var(--gold-hi);font-size:.68rem;letter-spacing:.06em;font-variant-numeric:tabular-nums; +.wrd{color:var(--gold-hi);font-size:.8rem;letter-spacing:.06em;font-variant-numeric:tabular-nums; min-height:.95rem;display:flex;align-items:center;gap:6px} -.wrd::before{content:"▸";color:var(--steel);font-size:.6rem} -.wnote{color:var(--dim);font-size:.72rem;line-height:1.4} +.wrd::before{content:"▸";color:var(--steel);font-size:.7rem} +.wnote{color:var(--dim);font-size:.85rem;line-height:1.45} .wnote b{color:var(--steel);font-weight:400} +/* per-card spec sheet (collapsible) */ +.winfo{border-top:1px dashed var(--wash);padding-top:6px;margin-top:2px} +.winfo summary{color:var(--steel);font-size:.74rem;letter-spacing:.18em;text-transform:uppercase; + cursor:pointer;list-style:none;user-select:none} +.winfo summary::-webkit-details-marker{display:none} +.winfo summary::before{content:"▸ "} +.winfo[open] summary::before{content:"▾ "} +.igrid{display:grid;grid-template-columns:max-content 1fr;gap:4px 10px;margin-top:7px} +.igrid .ik{color:var(--steel);font-size:.72rem;letter-spacing:.08em;text-transform:uppercase;padding-top:1px} +.igrid .iv{color:var(--dim);font-size:.82rem;line-height:1.45} +.igrid .iv b{color:var(--silver);font-weight:400} + /* ---- shared primitives ---- */ .lamp{width:9px;height:9px;border-radius:50%;background:var(--pass);box-shadow:0 0 6px 1px rgba(116,147,47,.55)} .lamp.gold{background:var(--gold);box-shadow:0 0 6px 1px rgba(var(--glow-lo),.6)} @@ -347,16 +377,37 @@ h2::after{content:"";height:1px;background:var(--wash);flex:1} .jog .dimple{position:absolute;left:50%;top:7px;width:8px;height:8px;margin-left:-4px;border-radius:50%; background:radial-gradient(circle at 40% 35%,#151210,#000);box-shadow:inset 0 1px 2px rgba(0,0,0,.9)} -/* oscilloscope */ +/* oscilloscope — screen-family vars with the original green as fallback */ .scope{width:176px;height:78px;border-radius:6px;position:relative;overflow:hidden; - background:radial-gradient(circle at 50% 45%,#04140a,#020a05);border:1px solid #123018; + background:radial-gradient(circle at 50% 45%,var(--scr-bgc,#04140a),var(--scr-bge,#020a05)); + border:1px solid var(--scr-brd,#123018); box-shadow:inset 0 0 16px rgba(0,0,0,.7)} .scope .grat{position:absolute;inset:0;opacity:.5; - background-image:linear-gradient(rgba(111,206,51,.18) 1px,transparent 1px),linear-gradient(90deg,rgba(111,206,51,.18) 1px,transparent 1px); + background-image:linear-gradient(var(--scr-grat,rgba(111,206,51,.18)) 1px,transparent 1px),linear-gradient(90deg,var(--scr-grat,rgba(111,206,51,.18)) 1px,transparent 1px); background-size:22px 19.5px} -.scope .grat::after{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:rgba(111,206,51,.35)} +.scope .grat::after{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:var(--scr-gratc,rgba(111,206,51,.35))} .scope svg{position:absolute;inset:0;width:100%;height:100%} -.scope polyline{fill:none;stroke:var(--phos);stroke-width:1.6;filter:drop-shadow(0 0 3px rgba(127,224,160,.8))} +.scope polyline{fill:none;stroke:var(--scr-hi,var(--phos));stroke-width:1.6;filter:drop-shadow(0 0 3px var(--scr-glow,rgba(127,224,160,.8)))} + +/* voice-loop keyset */ +.vloop{display:grid;grid-template-columns:repeat(4,1fr);gap:4px} +.vk{position:relative;font-size:7px;letter-spacing:.05em;text-align:center;padding:7px 4px 9px;cursor:pointer; + color:var(--dim);background:linear-gradient(180deg,#23211e,#191715);border:1px solid #33302b;border-radius:4px; + font-family:var(--mono)} +.vk .bar{position:absolute;left:4px;right:4px;bottom:3px;height:3px;border-radius:2px;background:#16240f} +.vk.mon{color:var(--silver)} +.vk.mon .bar{background:var(--pass);box-shadow:0 0 4px rgba(116,147,47,.6)} +.vk.mon.act .bar{background:#a8d84a;box-shadow:0 0 7px rgba(150,200,60,.9)} +.vk.tlk{color:var(--panel);background:linear-gradient(180deg,var(--amber-grad-top),var(--gold)); + border-color:var(--gold-hi);font-weight:700} +.vk.tlk .bar{background:var(--pass);box-shadow:0 0 4px rgba(116,147,47,.6)} + +/* screen-family chips (alt phosphor / tube colors per screen widget) */ +.famchips{display:flex;gap:7px;align-items:center;margin-top:1px} +.famchips .lab{color:var(--steel);font-size:.6rem;letter-spacing:.14em;text-transform:uppercase;margin-right:2px} +.famchips .fc{width:13px;height:13px;border-radius:50%;cursor:pointer; + border:1px solid rgba(255,255,255,.22);box-shadow:0 1px 3px rgba(0,0,0,.5)} +.famchips .fc.on{outline:2px solid var(--silver);outline-offset:1px} /* spectrum / EQ */ .eq{display:flex;align-items:flex-end;gap:3px;height:60px} @@ -440,6 +491,23 @@ h2::after{content:"";height:1px;background:var(--wash);flex:1} .seven .colon{align-self:center;display:flex;flex-direction:column;gap:9px} .seven .colon i{width:4px;height:4px;border-radius:50%;background:var(--sevgrn);box-shadow:0 0 4px rgba(87,211,87,.7)} +/* DSKY verb/noun panel */ +.dsky{display:flex;gap:9px;align-items:stretch;background:#1c1916;border:1px solid #060505;border-radius:8px;padding:8px} +.dsky .lampcol{display:grid;grid-template-rows:repeat(6,1fr);gap:3px;width:52px} +.dsky .sl{font-size:6.5px;letter-spacing:.04em;display:flex;align-items:center;justify-content:center;text-align:center; + background:#141210;color:#5c574c;border-radius:2px;border:1px solid #26221c} +.dsky .sl.on{background:linear-gradient(180deg,var(--amber-warn),var(--gold));color:var(--panel);font-weight:700; + box-shadow:0 0 6px rgba(var(--glow-lo),.5)} +.dsky .right{display:flex;flex-direction:column;gap:6px} +.dsky .wins{display:flex;gap:8px} +.dsky .win{display:flex;flex-direction:column;align-items:center;gap:2px} +.dsky .win .wl{font-size:6px;letter-spacing:.14em;color:var(--steel)} +.dsky .win .wd{display:flex;gap:2px;background:#0a0806;border:1px solid #231f18;border-radius:4px;padding:3px 4px} +.dsky .win .wd .seg7{width:13px;height:24px} +.dsky .win.hot .wd{border-color:var(--gold);box-shadow:0 0 5px rgba(var(--glow-lo),.4)} +.dsky .pad{display:grid;grid-template-columns:repeat(5,1fr);gap:4px} +.dsky .pad .key{padding:4px 0;font-size:8.5px;border-radius:5px;text-align:center;letter-spacing:.03em} + /* VFD marquee */ .vfdm{width:176px;height:34px;border-radius:5px;overflow:hidden;position:relative;cursor:pointer; background:linear-gradient(180deg,#04100e,#020807);border:1px solid #123028;box-shadow:inset 0 0 12px rgba(0,0,0,.6)} @@ -449,6 +517,14 @@ h2::after{content:"";height:1px;background:var(--wash);flex:1} background-image:radial-gradient(rgba(0,0,0,.6) 40%,transparent 41%);background-size:3px 3px} /* annunciator */ +.annwrap{display:flex;flex-direction:column;gap:6px} +.annbar{display:flex;gap:5px;align-items:center} +.mc{font-size:7px;letter-spacing:.08em;padding:4px 8px;border-radius:3px;background:#141210;color:#5c574c; + border:1px solid #26221c;text-align:center} +.mc.on{background:linear-gradient(180deg,#d98a6f,var(--fail));color:var(--cream);font-weight:700; + box-shadow:0 0 8px rgba(203,107,77,.5)} +.mc.on.fl{animation:pulse var(--pulse-rate) ease-in-out infinite} +.annbar .key{padding:3px 7px;font-size:7.5px;border-radius:4px} .annun{display:grid;grid-template-columns:repeat(3,1fr);gap:3px} .acell{font-size:8.5px;letter-spacing:.08em;text-align:center;color:var(--dim);padding:6px 4px;border-radius:3px;cursor:pointer; background:#141210;border:1px solid #262320;line-height:1.2} @@ -518,7 +594,7 @@ h2::after{content:"";height:1px;background:var(--wash);flex:1} @media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}} - +
archsetup · dupre panel family · live kit
@@ -530,8 +606,19 @@ h2::after{content:"";height:1px;background:var(--wash);flex:1} readouts show state or a number. Every widget is operable: drag the faders, knobs and gauges; click the switches, keys and lamps. Each card carries a live readout that tracks what you do. The trace displays run a live signal; the pointer types drive from your drag.

+
widget size + + + +
+

Palette — design tokens

+

Read live from the generated :root block (tokens.json via gen_tokens.py), so this section always shows + exactly what the widgets render with. Hex tokens get a swatch; the glow entries are rgb triples used inside + rgba() glows; mono and pulse-rate are the non-color tokens.

+
+

Controls — take input

@@ -545,10 +632,812 @@ h2::after{content:"";height:1px;background:var(--wash);flex:1} -- cgit v1.2.3