diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-18 07:51:43 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-18 07:51:43 -0500 |
| commit | 4d8e8f5fc88fb09cb498b1a0a3e572aaa6e771ab (patch) | |
| tree | 96b992eaf7443050b5e932e66662b74223c257c5 /docs/prototypes/panel-widget-gallery.html | |
| parent | 872813892e98d9cc7b8253b02cf9a595b144325a (diff) | |
| download | archsetup-4d8e8f5fc88fb09cb498b1a0a3e572aaa6e771ab.tar.gz archsetup-4d8e8f5fc88fb09cb498b1a0a3e572aaa6e771ab.zip | |
feat(gallery): grow the split-flap into a randomized multi-row board with skins, faces and a flap-rate slider
The N20 card becomes a three-row, six-cell departure board. Every advance sends each row to a completely different word, drawn at random from a 24-word pool with rows kept mutually distinct, and each cell runs at its own mechanical rate (a fixed 0.8x-1.35x of the base flap time), so letters and whole words finish at genuinely different times. A slider on the card sets the base rate (setFlapMs on the handle). The board advances only after it has settled and dwelt two seconds on the reading: the builder announces settle once per command (onSettle) and the page schedules the next advance from that signal, since a fixed-interval ticker would retarget mid-cascade and the panel would never rest. The chain stays gated off under reduced motion, where the board paints once and rests.
Customization lands as two construction axes on the chip rig: skin (cream-on-black default, true-white ink, the ivory board, or white cards with dark lettering) and face (Berkeley Mono or Helvetica, the grotesque real boards wore). The skin chips are miniature flap cells, a letter in the skin's real ink on its real board colour, and the font chips letter themselves in their actual face, so every choice previews itself. The flap-rate slider rides in the chips row, and the card's amber word readout is gone: the board is the display. The deterministic seam for callers and tests is setText; randomness lives only in the demo path (next/scramble), which re-aims against the last commanded grid rather than in-flight glyphs.
The settle work caught a real ordering bug: setText assigned each cell's target and ran it in one pass, so a cell finishing synchronously saw its neighbours' stale, already-satisfied targets and announced a partial board as settled. Targets now all land before any cell runs. Review caught two more: the dwell chain had escaped the reduced-motion gate (the board self-advanced every two seconds forever under reduced motion), and the skin chips rendered blank because the STYLES entries were strings where the rig paints an object's dot swatch.
Since this is heading for extraction as a regular component, the builder got the full refactor pass: a contract comment covering every opt and the handle surface, small named helpers, no page globals, and all CSS in the one split-flap block. The same bar is filed as a sweep task for every other builder. Probe coverage grows to 78 checks: the reduced-motion rest, the live dwell measurement, the scramble contract, both style axes, the speed api and the swatch legibility.
Diffstat (limited to 'docs/prototypes/panel-widget-gallery.html')
| -rw-r--r-- | docs/prototypes/panel-widget-gallery.html | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/docs/prototypes/panel-widget-gallery.html b/docs/prototypes/panel-widget-gallery.html index 201fa0e..b8e70bc 100644 --- a/docs/prototypes/panel-widget-gallery.html +++ b/docs/prototypes/panel-widget-gallery.html @@ -188,6 +188,18 @@ h2::after{content:"";height:1px;background:var(--wash);flex:1} 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} +/* N20's chips are miniature flap cells: the board colour comes from the rig's + inline dot; the letter shows the actual ink (skins) or the actual face (fonts) */ +#card-N20 .wrd{display:none} +#card-N20 .famchips .fc{width:17px;height:20px;border-radius:4px;position:relative;border:1px solid #4a453c} +#card-N20 .famchips .fc::before{content:"";position:absolute;left:1px;right:1px;top:50%;height:1px;background:rgba(128,128,128,.35)} +#card-N20 .famchips .fc::after{position:absolute;inset:0;display:grid;place-items:center;font-size:12px;font-weight:700;line-height:1;content:"A"} +#card-N20 .fc[title="dark"]::after{color:#f3e7c5} +#card-N20 .fc[title="white"]::after{color:#ffffff} +#card-N20 .fc[title="light"]::after{color:#1b1813} +#card-N20 .fc[title="paper"]::after{color:#17181a} +#card-N20 .fc[title="mono"]::after{color:#bfc4d0;font-family:var(--mono)} +#card-N20 .fc[title="helv"]::after{color:#bfc4d0;font-family:Helvetica,'Helvetica Neue',Arial,sans-serif} @media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}} </style> </head> @@ -1565,8 +1577,8 @@ card(I,'26','Nixie tube', (st,rd)=>GW.nixie(st,{onChange:(v,t)=>rd(t)}), '<b>a single warm-glowing numeral.</b> One lit digit per tube, leading zeros dark. Click to increment the count.'); card(I,'N20','Split-flap display', - (st,rd)=>GW.splitFlap(st,{animate:!reduced,onChange:(v,t)=>rd(t)}), - '<b>flips to the new value.</b> Each card drops to the next glyph with the mechanical clack. Auto-flips; click to flip now.'); + (st)=>GW.splitFlap(st,{rows:3,cells:6,words:['SYSTEM','VOLUME','SIGNAL','RECORD','ONLINE','STEREO','STATUS','FILTER','TUNING','NEEDLE','SWITCH','TOGGLE','DIMMER','CHROME','MODULE','OUTPUT','SCREEN','COPPER','DYNAMO','PISTON','MAGNET','BEACON','RADIAL','BRIDGE'],animate:!reduced}), + '<b>flips to the new value.</b> A three-row, six-cell board; every advance sends each row to a different random word from the pool, and each cell runs at its own mechanical rate, so letters and whole words finish at different times. After settling it dwells two seconds, then advances. Click to advance now. Skins: cream-on-black (default), true white ink, the ivory board, or white cards with dark lettering; face in Berkeley Mono or Helvetica. The slider sets the flap rate.'); card(I,'N21','Seven-segment display', (st,rd)=>GW.sevenSeg(st,{onChange:(v,t)=>rd(t)}), '<b>a lit-segment number.</b> Green segments, distinct from the nixie glow. Live countdown; click to add a minute.'); @@ -1698,7 +1710,10 @@ function fastTick(){ /* indicator loops: builders own state + clicks; the page keeps the clocks and the time source (tick contract) */ function tickClock(){const d=new Date();IH.clock.set(d.getHours(),d.getMinutes(),d.getSeconds());} -function tickFlap(){IH.flap.next();} +const FLAP_DWELL_MS=2000; let flapTimer; +// The board advances only after it has settled AND dwelt on the reading — +// a fixed interval would retarget mid-cascade and the panel would never rest. +if(!reduced)IH.flap.onSettle(()=>{clearTimeout(flapTimer);flapTimer=setTimeout(()=>IH.flap.next(),FLAP_DWELL_MS);}); function tickSeven(){IH.seven.tick();} function tickT(){$('card-20').gw.tick();} function tickVfd(){IH.vfd.tick();} @@ -1721,7 +1736,7 @@ if(!reduced){ setInterval(fastTick,80); setInterval(tickMcVu,80); setInterval(tickClock,1000);tickClock(); - setInterval(tickFlap,1500); + flapTimer=setTimeout(()=>IH.flap.next(),FLAP_DWELL_MS); setInterval(tickVfd,32); setInterval(tickCounter,1600); setInterval(tickSeven,1000); @@ -1813,6 +1828,13 @@ function styleChips(no,STYLES,AXES,PRESETS,defPreset){ groups.forEach(g=>row.appendChild(g)); cardEl.querySelector('.opts').appendChild(row); } +styleChips('N20',GW.splitFlap.STYLES,[['skin','skin','dark'],['font','font','mono']]); +(()=>{const h=$('card-N20').gw,row=document.querySelector('#card-N20 .famchips');if(!h||!row)return; + const gr=document.createElement('span');gr.className='fgroup'; + gr.innerHTML='<span class="lab">flap</span><input type="range" min="30" max="160" value="70" style="width:70px;accent-color:var(--gold);vertical-align:middle"><span class="lab fms">70ms</span>'; + const sl=gr.querySelector('input'),ms=gr.querySelector('.fms'); + sl.addEventListener('input',()=>{h.setFlapMs(+sl.value);ms.textContent=sl.value+'ms';}); + row.appendChild(gr);})(); styleChips('01',GW.slideToggle.STYLES, [['on','on','amber'],['on text','onText','panel'],['off','off','dark'], ['off text','offText','white'],['thumb','thumb','light']], |
