diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-18 09:51:55 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-18 09:51:55 -0500 |
| commit | b0db5e842d93564b1cb2e4b142ba0a0de1843fbd (patch) | |
| tree | e1d8a0ccdfc07a1339d64f387200e7766bda28be | |
| parent | 3da976bd0287ebb632b0d8475f2e780d1b10e1b8 (diff) | |
| download | archsetup-b0db5e842d93564b1cb2e4b142ba0a0de1843fbd.tar.gz archsetup-b0db5e842d93564b1cb2e4b142ba0a0de1843fbd.zip | |
fix(gallery): split-flap defaults are paper cards, Helvetica, 100ms
The default skin is the white card with dark lettering, not white ink on black, and the default face is Helvetica. Both list first in their chip rows with the alternatives a click away. The base flap rate moves to 100ms. The probe pins all three defaults, and its cascade windows widen to match the slower base so worst-case travel keeps its margin.
| -rw-r--r-- | docs/prototypes/panel-widget-gallery.html | 8 | ||||
| -rw-r--r-- | docs/prototypes/widgets.js | 10 | ||||
| -rw-r--r-- | tests/gallery-probes/probe.mjs | 43 |
3 files changed, 31 insertions, 30 deletions
diff --git a/docs/prototypes/panel-widget-gallery.html b/docs/prototypes/panel-widget-gallery.html index 5db6fab..9eaf18a 100644 --- a/docs/prototypes/panel-widget-gallery.html +++ b/docs/prototypes/panel-widget-gallery.html @@ -1578,8 +1578,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)=>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,skin:'white'}), - '<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: white ink on black (default), the kit cream, the ivory board, or white cards with dark lettering; face in Berkeley Mono or Helvetica. The slider sets the flap rate.'); + (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,skin:'paper',font:'helv'}), + '<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: white cards with dark lettering (default), white ink on black, the kit cream, or the ivory board; face in Helvetica (default) or Berkeley Mono. 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.'); @@ -1829,10 +1829,10 @@ 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','white'],['font','font','mono']]); +styleChips('N20',GW.splitFlap.STYLES,[['skin','skin','paper'],['font','font','helv']]); (()=>{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="85" style="width:70px;accent-color:var(--gold);vertical-align:middle"><span class="lab fms">85ms</span>'; + gr.innerHTML='<span class="lab">flap</span><input type="range" min="30" max="160" value="100" style="width:70px;accent-color:var(--gold);vertical-align:middle"><span class="lab fms">100ms</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);})(); diff --git a/docs/prototypes/widgets.js b/docs/prototypes/widgets.js index 0126949..8af2666 100644 --- a/docs/prototypes/widgets.js +++ b/docs/prototypes/widgets.js @@ -3659,9 +3659,9 @@ GW.nixie = function (host, opts = {}) { Contract (everything a consumer needs; no page globals touched): opts: rows (1) x cells (4) grid; chars (flap order, default space+A-Z+0-9); - flapMs (85, per-cell rate jittered 0.8x-1.35x so letters finish + flapMs (100, per-cell rate jittered 0.8x-1.35x so letters finish at different times, base mutable via setFlapMs); animate (true); - skin ('white'|'dark'|'light'|'paper', card default white); font ('mono'|'helv'); + skin ('paper'|'white'|'dark'|'light', card default paper); font ('helv'|'mono', card default helv); words (the demo pool, at least rows+1 entries: next() sends every row to a different random word, mutually distinct; set(i) pins the top row for determinism); onChange(idx|-1, top word) fires at @@ -3680,7 +3680,7 @@ GW.splitFlap = function (host, opts = {}) { const cells = opts.cells || 4; const chars = opts.chars || ' ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; const clampMs = ms => Math.min(400, Math.max(20, ms | 0)); - let flapMs = clampMs(opts.flapMs || 85); + let flapMs = clampMs(opts.flapMs || 100); const ci = ch => Math.max(0, chars.indexOf(ch)); const fit = (str, w) => String(str).padEnd(w, ' ').slice(0, w); @@ -3824,15 +3824,15 @@ GW.splitFlap.STYLES = { // dot: the board colour; the gallery card letters each chip in the skin's // ink so the swatch is a miniature flap cell, not an ambiguous colour dot skin: { + paper: { cls: 'flap-paper', dot: '#ffffff' }, white: { cls: 'flap-white', dot: '#141210' }, dark: { cls: '', dot: '#141210' }, light: { cls: 'flap-light', dot: '#f3e7c5' }, - paper: { cls: 'flap-paper', dot: '#ffffff' }, }, // typeface: the kit's Berkeley Mono, or the grotesque real boards wore font: { - mono: { cls: '', dot: '#0d0c0b' }, helv: { cls: 'flap-helv', dot: '#0d0c0b' }, + mono: { cls: '', dot: '#0d0c0b' }, }, }; diff --git a/tests/gallery-probes/probe.mjs b/tests/gallery-probes/probe.mjs index 051d575..e394316 100644 --- a/tests/gallery-probes/probe.mjs +++ b/tests/gallery-probes/probe.mjs @@ -890,7 +890,7 @@ try { // anywhere, and every command cascades (there is deliberately no teleport // path). setText is the deterministic seam; next() is random by design. await evl(`document.querySelector('#card-N20').gw.setText('SYSTEM\\nVOLUME\\nSIGNAL')`); - await sleep(5400); + await sleep(6500); // Start a cascade and sample the displayed reading every 15ms until stable. await evl(`(() => { @@ -908,7 +908,7 @@ try { window.__n20.anims++; }, 15); })()`); - await sleep(5400); + await sleep(6500); const n20 = await evl(`(() => { clearInterval(window.__n20.timer); const h = document.querySelector('#card-N20').gw; @@ -938,7 +938,7 @@ try { window.__n20r.timer = setInterval(() => window.__n20r.samples.push(h.reading()), 15); h.setText('SIGNAL\\nRECORD\\nONLINE'); setTimeout(() => h.setText('RECORD\\nONLINE\\nSTEREO'), 180); })()`); - await sleep(5800); + await sleep(7000); const n20b = await evl(`(() => { clearInterval(window.__n20r.timer); const h = document.querySelector('#card-N20').gw; @@ -1000,44 +1000,45 @@ try { const h = document.querySelector('#card-N20').gw; if (typeof h.setStyle !== 'function' || !GW.splitFlap.STYLES || !GW.splitFlap.STYLES.skin) return 'no skin axis'; const skins = Object.keys(GW.splitFlap.STYLES.skin); - if (skins[0] !== 'white') return 'white must list first, got: ' + skins.join(','); + if (skins[0] !== 'paper') return 'paper must list first, got: ' + skins.join(','); if (!['dark','white','light','paper'].every(k => skins.includes(k))) return 'skins are: ' + skins.join(','); const ink = () => getComputedStyle(document.querySelector('#card-N20 .fh')).color; const lum = c => { const m = c.match(/[0-9]+/g).map(Number); return m[0] + m[1] + m[2]; }; - const white = ink(); // the card's default skin is white ink - if (white !== 'rgb(255, 255, 255)') return 'default ink is not white: ' + white; + const paperDef = ink(); // the card's default skin is the white card, dark letters + if (lum(paperDef) >= 300) return 'default ink is not dark-on-paper: ' + paperDef; + if (!document.querySelector('#card-N20 .flap').classList.contains('flap-paper')) return 'default skin class is not paper'; + h.setStyle('skin', 'white'); + const white = ink(); + if (white !== 'rgb(255, 255, 255)') return 'white skin ink is ' + white; h.setStyle('skin', 'dark'); const cream = ink(); h.setStyle('skin', 'light'); const light = ink(); const gotClass = document.querySelector('#card-N20 .flap').classList.contains('flap-light'); h.setStyle('skin', 'paper'); - const paper = ink(); - const paperClass = document.querySelector('#card-N20 .flap').classList.contains('flap-paper'); - h.setStyle('skin', 'white'); const back = ink(); if (!gotClass) return 'light skin class missing'; - if (!paperClass) return 'paper skin class missing'; - if (!(lum(cream) > 400 && lum(cream) < 760 && lum(light) < 300 && lum(paper) < 300)) return 'inks wrong: ' + cream + ' / ' + light + ' / ' + paper; - if (back !== white) return 'did not restore the white default: ' + back; + if (!(lum(cream) > 400 && lum(cream) < 760 && lum(light) < 300)) return 'inks wrong: ' + cream + ' / ' + light; + if (back !== paperDef) return 'did not restore the paper default: ' + back; return 'ok'; })()`); - ok('N20 skins: white default first, cream, ivory board, white board — all switch and restore', n20e === 'ok', n20e); + ok('N20 skins: paper default first, white ink, cream, ivory — all switch and restore', n20e === 'ok', n20e); const n20fnt = await evl(`(() => { const h = document.querySelector('#card-N20').gw; if (!GW.splitFlap.STYLES.font) return 'no font axis'; const fam = () => getComputedStyle(document.querySelector('#card-N20 .fh')).fontFamily; + const helv = fam(); // the card's default face is Helvetica + if (!/helvetica/i.test(helv)) return 'default face is not helvetica: ' + helv; + h.setStyle('font', 'mono'); const mono = fam(); h.setStyle('font', 'helv'); - const helv = fam(); - h.setStyle('font', 'mono'); const back = fam(); - if (!/helvetica/i.test(helv)) return 'helv did not apply: ' + helv; - if (!/berkeley|mono/i.test(mono) || back !== mono) return 'mono wrong or not restored: ' + mono + ' / ' + back; + if (!/berkeley|mono/i.test(mono) || /helvetica/i.test(mono)) return 'mono did not apply: ' + mono; + if (back !== helv) return 'did not restore the helv default: ' + back; return 'ok'; })()`); - ok('N20 font switches between Berkeley Mono and Helvetica', n20fnt === 'ok', n20fnt); + ok('N20 face: Helvetica default, Berkeley Mono one click away', n20fnt === 'ok', n20fnt); const n20f = await evl(`(() => { const chips = [...document.querySelectorAll('#card-N20 .famchips .fc, #card-N20 .famchips [title]')].map(c => c.title || c.textContent); return chips.length ? chips.join(',') : 'no chips'; @@ -1058,7 +1059,7 @@ try { const h = document.querySelector('#card-N20').gw; if (typeof h.setFlapMs !== 'function' || typeof h.flapMs !== 'function') return 'no speed api'; const before = h.flapMs(); - if (before !== 85) return 'default flap rate is ' + before + ', want 85'; + if (before !== 100) return 'default flap rate is ' + before + ', want 100'; h.setFlapMs(120); if (h.flapMs() !== 120) return 'setFlapMs did not take: ' + h.flapMs(); const slider = document.querySelector('#card-N20 input[type=range]'); @@ -1083,7 +1084,7 @@ try { }, 50); h.set(0); })()`); - await sleep(9000); + await sleep(10500); const dwell = await evl(`(() => { const d = window.__n20dwell; clearInterval(d.timer); return { settleAt: d.settleAt, delta: d.changeAt ? d.changeAt - d.settleAt : -1 }; @@ -1102,7 +1103,7 @@ try { if (new Set(skins).size !== 4) return 'skin previews not distinct: ' + skins.join(' '); if (chips.slice(0, 4).some(c => getComputedStyle(c, '::after').content === 'none')) return 'skin chip has no ink letter'; const fams = chips.slice(4).map(c => getComputedStyle(c, '::after').fontFamily); - if (!/helvetica/i.test(fams[1]) || fams[0] === fams[1]) return 'font previews wrong: ' + fams.join(' vs '); + if (!fams.some(f => /helvetica/i.test(f)) || fams[0] === fams[1]) return 'font previews wrong: ' + fams.join(' vs '); const size = parseFloat(getComputedStyle(chips[0]).width); return size >= 15 ? 'ok' : 'chips too small to read: ' + size; })()`); |
