| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
| |
The oldest way to type without a keyboard, and the first card where selecting and committing are separate acts. One hand walks a stylus over a printed plate, the other pulls a lever, and only the lever prints. You can hunt across every character and nothing happens until the second hand moves. Every other control in the kit fires on contact.
The keyboard follows the same rule: typing selects, Enter is the lever. A keypress that printed would make this the ABC keypad with a nicer plate, which is the one thing it must not be. It also does no case folding, where the keypad must. This plate carries both cases as distinct cells, so Shift does exactly the work a shift key would on a machine that hasn't got one.
KEYS and ACTIONS are derived from the layout table rather than kept beside it, so rewriting the table relays the plate, the keymap and the allowlist together. A binding aimed at a character the plate no longer carries isn't expressible.
After the AEG Mignon Model 4, keeping the two things worth keeping: the extended set a keyboard skips, and both cases with no shift key. Its frequency order goes. Reading the plate is the interaction, and P U G Q / V I N A B isn't something you can read your way around, so ours is alphabetical with capitals beside lowercase at the same column offset. I expect to revisit the keys, so the layout is a table the geometry computes itself from. I built it at four, five and nine rows to check the gutter survives a rewrite in either direction.
There's no space cell yet, so Space isn't ours and still scrolls the page. The real machine has a separate space key.
|
| |
|
|
|
|
| |
probe-fams.mjs had no try/finally, so a throw skipped chrome.kill() and left the headless browser alive on its port. The next run connected to that survivor and reported results from a stale page: old widgets.js, chips already clicked. It cost me a debug loop today, insisting a card's default ink was green and another's chips were missing, neither of which was true of the page on disk.
A probe that answers from the previous run is worse than one that crashes. Its two siblings already had the guard.
|
| |
|
|
|
|
|
|
|
|
| |
Twenty clicks for a passphrase was always the wrong answer. The plate takes focus on click and reads the keyboard now: lowercase normalises, Space maps to SPC and shows as ␣, Backspace to DEL, Enter to ENT. Every key routes through the same press() a click does, so the two paths can't drift.
press() is where the filter belongs, not the keydown handler. I had it in the handler first, which guards the web and leaves the Emacs port wide open, since that port installs KEYS into a keymap and calls press directly with no handler in the stack. It gates on ACTIONS rather than KEYS because they're different sets: CLR is a real key on the plate that no keystroke reaches.
The focus ring uses :focus, not :focus-visible. Chrome won't match :focus-visible on a mouse-driven focus of a non-text element, and clicking the plate is how it takes focus, so the ring would have shown only when tabbed to. On a 110-card page that means typing into a card with no sign it was listening.
The window is a screen like the scope's or the marquee's, so it takes the screen families through the --scr-* vars with the shipped colours as fallbacks: nothing moves until a chip is clicked. Glass and ink both recolour, because a screen that changes its text and keeps its backlight isn't a screen. It offers all six families where its siblings carry five, since a passphrase window has no reason to prefer one phosphor.
|
| |
|
|
|
|
|
|
| |
The kit already held both halves of the answer without stating it. GW.slideRule takes arrow keys bound to its own focusable element, which is why it never fights the gallery's global Escape handler: the browser arbitrates focus. But Emacs can't work that way. The SVG region is an image and never sees a keypress, so there the mode's keymap owns delivery.
That's the same split as the tick contract, so I put it beside it. The target owns focus and delivery, the builder declares what it accepts through a KEYS table. Deliberately a table rather than a function over a DOM event: the Emacs port installs it into a keymap and never sees a keydown, so a function would force it to re-derive the widget's intent and the two bindings would drift.
The five rules are each a bug someone ships otherwise. Never listen on document. Spend preventDefault only where there's a default worth killing. Let Tab and Escape bubble. press filters rather than trusts. Click and key both route through press.
|
| |
|
|
| |
It fails about one run in six: the synthetic drag lands before the zoom relayout has settled, so the press misses the fader and the readout never moves. I filed it rather than fixing it, because the tempting fix is raising the sleep, which hides the race instead of removing it.
|
| |
|
|
|
|
|
|
|
|
| |
The kit entered digits three ways and text no way at all, so the panels that need a WiFi password had nothing to reach for. R57 takes free alphanumeric text. A-Z is laid out alphabetically rather than QWERTY, the industrial convention wherever the operator isn't assumed to touch-type, and what makes this a faceplate instead of a keyboard.
I followed two reference plates and departed from both, arguing each departure at its site. Their letters are blue and the kit has no blue control colour, so letters take the standard pale cap and digits a darker one: the photos' two-tone grouping without the foreign hue. Letters sit left and digits right so the alphabet reads down one unbroken block. With the digits on the left it stops column-aligning with itself halfway down.
DEL is new, because without a backspace one mistyped character costs the whole entry. It sits beside the digits in amber while CLR is exiled to the corner in red. DEL is constant and costs a character, CLR is rare and costs everything, so the safe key gets the good spot and the colour grades the cost before the legend is read. CANCEL is gone: on a plate that is the whole terminal it has a transaction to abandon, but here it did exactly what CLR does.
The window draws spaces as ␣. SVG collapses whitespace, and past the truncation boundary there are no pad dots left for a space to displace, so SPACE was a keypress with no feedback at all. The buffer keeps the real character.
|
| |
|
|
|
|
|
|
| |
The button said "copied" and nothing reached the clipboard. From a file:// origin Chrome refuses both programmatic paths: navigator.clipboard.writeText rejects NotAllowedError, and execCommand('copy') returns true while writing nothing. The truthy return is what let the page claim a success it never had.
A hand-typed Ctrl+C works, so nothing about the clipboard is broken. I checked the rest of the chain: a Wayland-set clipboard crosses to X11, and Emacs reads it back correctly against a sentinel. So the page's only job is to hand the text over selected, and the reader's own copy does the rest.
The comment I shipped earlier had this backwards, claiming Chrome couldn't write the clipboard at all. It's replaced.
|
| |
|
|
|
|
|
|
|
|
| |
Crossing Foley's elemental tasks against cardinality over the kit finds two empty cells: selecting one of a dynamic set (the device and network lists) and alphanumeric text entry (a WiFi password). Panels that already exist want both.
The cross needed an axis the note didn't carry. Cardinality lumps all one-of-N together, so a chicken-head selector and a WiFi list share a cell that then reads as covered. Set stability is what separates them. The axis is invisible from inside hardware, where every option set is engraved at manufacture. That's why a catalogue modelled on period gear goes blind exactly where its software consumers live.
The period answer to a changing set was never a control but a re-labelable slot: jukebox title strips, Rolodex cards, scribble strips. The slot is manufactured, the label isn't.
Reference photos supersede the teletype for text entry. They're all ABC-order industrial keypads, whose colour-coded CANCEL, CLEAR/NO and ENTER/YES land on the palette untranslated. A survey adds two idioms unlike a keypad: the index typewriter, which selects on one control and commits on another, and the chorded keyset, which has no key per letter at all.
|
| |
|
|
|
|
|
|
| |
Console keys read SCAN before LIVE, and LIVE is green. The palette already defines --pass as "run lamps, gear greens, monitor bars, LIVE lamps", so the widget contradicted the language it draws from. Its note asserted the old colours too. The per-key `red` boolean became a `tone` field, since a boolean can't express three states.
The slide toggle gains red and warn on its `on` axis, so the engaged state can be the notable one (mute, record, airplane mode). Red was reachable only on the `off` axis before, which paints the disengaged state: the opposite claim. A new onText axis makes the ON ink reachable at all. `on` had bundled background and ink together, so "dark pill, green legend" couldn't be expressed.
Presets name a combination (panel, run, armed, caution, dark), which is what a consumer reaches for. The axes are how one gets built.
|
| |
|
|
|
|
|
|
| |
The validation walk's per-card state lived only in browser localStorage, so a cache clear would lose it and the other machine never saw it. VSTATUS now carries the record in source, read as a fallback behind localStorage. The live walk wins on the machine doing it, and a deliberate un-check beats a baked green, because 'off' is a stored value like any other.
I build the export's text by hand rather than through JSON.stringify, which hoists canonical integer keys ('12' ahead of '01') and would reshuffle the whole block on every bake.
Copying it out never touches the clipboard. navigator.clipboard is denied outright on file://, and execCommand returns true while writing nothing. So the export lands in a selected textarea instead: a selection is readable as the PRIMARY selection, and that's the one path that works here.
|
| |
|
|
| |
probe-fams.mjs writes fams.png into the test directory on every run, so it sat untracked and one `git add -A` from being committed.
|
| |
|
|
| |
I renamed the handoff and the ZBM photo when I marked them processed, which broke both links in the boot-recovery task. The files stay on disk because that task still needs them.
|
| |
|
|
| |
Velox won't boot after an interrupted kernel upgrade left /boot without a kernel. The recovery task carries the ZBM pre-pacman-snapshot rollback steps. The retrospective task tracks the missing post-upgrade /boot assertion in maint's upgrade path.
|
| | |
|
| | |
|
| | |
|
| |
|
|
| |
The org-capture float cap and the doctor realtime lamps close as DONE (dotfiles 9c4dc2f, 0318a91). The zfs VM failure is diagnosed and externally blocked: OpenZFS 2.3.3 tops out at kernel 6.15 against our 6.18 LTS, and archzfs hasn't published 2.4.x yet. The lyricsgenius recheck logged the same structural LICENSE.txt pin. Both evidence reports are linked from their parents (dotfiles 260752a, archsetup 78081e4), and the pre-existing panel-smoke state-word failure is filed as its own bug.
|
| |
|
|
| |
Per package: description, requirer, install date, bucketed into candidates (30), dependency-pulled (6), orphaned libraries (7), and structural (21). The include/ignore pass reads the candidates bucket; rerun make package-diff after to confirm the count drops.
|
| |
|
|
| |
None were killed or re-graded. The stow-conflicts task moved: ratio's calibre check closed (the config dir is a folded stow symlink, so the first-launch gap never existed there) and the waypaper canonical is decided and applied (dark-lion, dotfiles fea3e93), leaving only the velox sweep. The dotfiles-audit task gained a solo child for the evidence report so the legwork can run unattended. The rest were confirmed as-is.
|
| | |
|
| |
|
|
| |
Two new tasks from the maint/net feedback pass: the live-refresh hairline replacement (the "updates too often / unclear line" report resolved to the 3s countdown hairline, so it's a design task with candidate replacements) and net-panel speedtest history. The panel keybinding family moves [#C] to [#B] with maintenance as the priority chord, since that's the panel I reach for without one.
|
| |
|
|
| |
The maint probe now reads network.tailscale_health_ignore before grading the tailscale lamp. This ships the fleet default: tailscaled's permanent DNS-unreachable complaint under systemd-resolved, which kept the lamp amber while DNS worked.
|
| |
|
|
| |
I restamped all seven. The popup bug now names the org-capture float, records the fix shape (a maxsize windowrule in the dotfiles hyprland config), and picks up :quick: and :solo:. The net-doctor heading now names the remaining work (VM live verification) instead of the shipped spec build. The audio-doctor mic task loses :solo: while its spec is still DRAFT with open decisions.
|
| |
|
|
| |
Wrap cleanup moved the closed net/bt panel tasks into the archive. Two reference photos (weather-station comfort meter, SWR forward/reflected meter) are filed for the next catalogue pass — both look N13-covered.
|
| |
|
|
|
|
|
|
| |
Clicks compared e.clientX (visual px, scaled by the size toggle's CSS zoom) against layout-px mark coordinates, so at M or L size nearest-mark snapping picked the wrong stop, usually the far end — the dial felt impossible to select. The click handler now divides the zoom out (offsetWidth over rect width), and the widget shows a subtle outline on click focus so it reads as armed for arrow keys.
The printed numerals are now majors with minor ticks at the integer units between them, all selectable: click a numeral, a mark, or between marks, and arrows step one unit instead of one numeral. The spec sheet claimed drag-only input, which was never true; it now names the click and key idioms.
The face rides new --tn-* vars and GW.slideRule gains opts.skin plus setStyle backed by GW.slideRule.STYLES: warm backlit (shipped default), chrome with dark ink, 80s black glass with an LED-red needle, and marantz blue with a pale needle. Card 25 joins the styleChips rig.
|
| |
|
|
|
|
| |
The lit segment rides new --seg-on-* vars with the shipped amber as the stylesheet fallback, and GW.segmented gains opts.accent plus setStyle backed by GW.segmented.STYLES, the same shape as the slide toggle.
Card 06 is the third chips demo rig, so the per-card IIFEs collapse into one styleChips(no, STYLES, AXES) helper serving cards 01, R05, and 06.
|
| |
|
|
|
|
|
|
| |
The index panel gains a Validation section: done / in progress / not done counts with a total, each row carrying a mini lamp dot in the matching state color. Every lamp click recounts, so the tally always mirrors the cards.
Clicking a row starts an audit of that state: the page jumps to the first matching card and a pill docks bottom-right showing the position (2/5 · next). Clicking the pill advances through the rest without scrolling back to the index, the x or Esc dismisses it, and the card list re-reads on every step so lamp changes mid-audit are picked up.
setV fires while its card is still detached from the document, so the running count lags the last card by one during the build. A final recount after all cards land closes the gap.
|
| |
|
|
| |
ca006d8 removed the cream cap color, but the parchment to retire was the lab panel skin. The panel axis is now silver / studio with silver as the default, and cream returns to the cap-color axis.
|
| |
|
|
|
|
| |
Bare metal needs no painted stripe, so the chrome cap shape in the chrome finish renders lineless. Other shapes keep their index line in every finish.
The cream finish is gone from the color axis along with its now-unused gradient. The stripe set stands at black, red, green, blue, amber, plus the chrome body.
|
| |
|
|
|
|
|
|
| |
The old card was a sketch: eight bare tracks and flat teal arrows floating on the card background. Real slider banks (the Vieltronix filter, the Pioneer SG-9500, the Technics SH-8065, the Zaxcom Oasis) have a faceplate, dual dB rails, dense bands, and caps that read as machined parts.
The rebuilt bank draws twelve bands on a screwed faceplate with tick rails both sides. Skins ship as constructor opts backed by GW.filterBank.STYLES on three independent axes: panel (lab parchment / silver aluminum / studio black), cap shape (tall block fader / short ribbed / chrome T), and cap color (black white-index / red, green, blue, amber stripes / chrome / cream). Shape and color are separate axes so any finish applies to any cap. opts.style picks a native trio. setStyle(axis, name) restyles a live instance with values preserved. The card grows chip groups driving setStyle, the same demo-rig pattern as the slide toggle.
Values shorter than a custom freqs list now pad instead of placing caps at NaN. I filed the Oasis reference alongside the others.
|
| |
|
|
| |
Dated history line for the finished extraction, the extraction acceptance criterion checked, the appendix's demand-matrix label corrected from Phase 1 to Phase 2 (a leftover from the pre-review phase order), and the consumer design notes that widget CSS ships inside widgets.js via GW_CSS.
|
| | |
|
| |
|
|
| |
README gains a widget-library section covering the GW builder contract, GW_CSS styling, the tick contract for live meters, named style options, and the CDP probes. The stray waybar-redesign bullet moves back to the prototypes list. todo.org Phase 1 closes as a dated entry.
|
| |
|
|
| |
The four style axes (on/off track, off engraving, thumb) move from a page-side chip rig into named constructor opts backed by GW.slideToggle.STYLES, with a setStyle handle method for live restyling. The gallery chips stay as a demo rig driving that method. Defaults match the stylesheet fallbacks, so a bare GW.slideToggle renders unchanged.
|
| |
|
|
| |
Widget-internal rules and the pulse/flipdrop keyframes now inject via ensureCss, so widgets.js consumers get styling without the gallery stylesheet. The page-side reelspin injector became a plain GW_CSS rule. The gallery keeps page furniture, option-chip capsules, tokens, and the reduced-motion guard.
|
| | |
|
| |
|
|
| |
builders
|
| | |
|
| | |
|
| |
|
|
| |
The heading-bug servo chase and the chart recorder's day clock are widget-owned animations, so they move into their builders with the reduced-motion gates intact (reduced motion paints the recorder's full day once). This completes the Meters section — all 28 extracted.
|
| |
|
|
| |
The VU ballistics chase stays page-side and drives mcVu.set(t); the R17 trace animation is widget-owned so it moves into the builder with its reduced-motion gate. The R17 face gradient keeps instance-local defs because its stops read screen-family vars from the widget subtree; probe-fams selectors follow the retired rcrt ids to the card handle.
|
| |
|
|
| |
Scope, EQ bars, and strip chart take value-driven handles (set samples / push); the eqBands oscillator and the demo signal stay page-side. The N11 screen-family chips now reach the scope through the card handle instead of the retired scopep id.
|
| |
|
|
| |
The page keeps the clock and demo signal; live meters (VU pair, mini signal, sparkline, waveform strip) expose value-driven handles — set/push repaint synchronously and fire onChange like every other builder. Peak-hold and history buffers move into the builders. fastTick and paintStatic now drive card handles.
|
| |
|
|
| |
Rotary telephone dial, circuit breaker panel, DSKY, cam-timer drum, knife switch, decade box, two-hand safety, and voice-loop keyset — the Controls section is now fully extracted. The dial keeps its wind-and-return animation (reduced-motion path included); the cam timer and voice loop keep their gated self-advance and activity-flicker intervals inside their builders. DSKY and voice loop are the first HTML-based builders with structural CSS still gallery-side. Behavioral pass now 118 checks; both probes green.
|
| |
|
|
| |
Winged gain selector, rotary disc switch, guarded toggle, mechanical timer dial, four-way rocker, four-way toggle selector, pin routing matrix, and dead-man button. The timer dial keeps its reduced-motion-gated 1 Hz wind-down inside the builder — it's widget behavior, not a gallery meter loop. discRed moves to the shared defs so the guarded toggle renders standalone. Behavioral pass now 96 checks; both probes green.
|
| |
|
|
| |
Entry keypad, thumb-slide pair, waveform region editor, drum roller, LED program row, three-position slide, spun knob, and stomp switch. The drum roller's per-instance clip paths get a uid() helper so two instances can coexist; the region editor's screen-family chips now reach the widget through the card handle (card.gw.el) instead of a stage id, and probe-fams drives its post-recolor check through the handle's set(). Behavioral pass now 78 checks; both probes green.
|
| |
|
|
| |
First SVG-widget batch: vernier dial, bat toggle, fluted knob, filter bank, chicken-head, slot fader, spade knob, and multi-band dial. widgets.js gains the shared-defs mechanism — document-scoped gradients (nutG, chromeG, spadeKnob, sfScrew, ...) now live in one hidden defs svg, created idempotently by whichever builder needs them first, so cross-widget url(#id) references survive extraction and any widget renders standalone. Probes green; behavioral pass now 60 checks.
|
| |
|
|
| |
Rocker, transport cluster, preset bank, dual knob, encoder, key switch, crossfader, thumbwheel, DIP bank, and jog wheel move into widgets.js; their inline onclick globals (transport/preset/keyTurn/dip) become listeners inside the builders. Transport takes an explicit animate option so reduced-motion behavior is the consumer's call; its initial paint leaves reel play-state to CSS, matching load behavior. Probes green plus the per-widget behavioral pass (43 checks).
|
| |
|
|
| |
Eleven CSS-form controls (slide toggle, console keys, both faders, knob, segmented, chip, arm-to-fire, lamp row, rotary selector, slide-rule dial) move into widgets.js as parameterized builders returning handles; card() now accepts a builder function in place of stage HTML, so these cards are declarative records wiring GW.* onChange into their readouts. Probes green plus a per-widget behavioral pass over all eleven.
|
| |
|
|
| |
First componentization batch per the component-generation spec: widgets.js is a classic script exposing the GW namespace (svgEl, polar, drag helpers, seg7, buildBars, VU law, SCREEN_FAMS) plus a css-injection scaffold that grows as builders move in. The gallery loads it via a relative script src and destructures the helpers, so file:// keeps working. Probes green.
|