app
Base Scaffold Control Panel
Public Made by Adomby adom
The Base Scaffold System's control panel: electrical specifications and the connect/disconnect interface between a base scaffold and the workcell ecosystem.
← Commit history
scaffold hover: part numbers + ratings, CPL-exact regions (USB-C, per-rail jumpers), Descriptions toggle
1 file changed
+68−29
README.html+68−29@@ -159,68 +159,107 @@ else { const paint = () => { g.classList.toggle('on', groundOn); l.classList.toggle('on', viewer.getBottomLightState()); }; g.onclick = () => { groundOn = !groundOn; viewer.setGroundVisible(groundOn); paint(); }; l.onclick = () => { viewer.setBottomLight(!viewer.getBottomLightState()); paint(); };- paint(); ctl.style.display = 'flex';- // ---- block hover descriptions (scaffold) ----+ paint(); ctl.style.display = 'flex'; // ---- block hover descriptions (scaffold) ---- try { const scene = viewer.getScene(); const tip = document.createElement('div'); tip.style.cssText = 'position:absolute;display:none;z-index:20;pointer-events:none;' +- 'background:rgba(22,27,34,.95);border:1px solid rgba(240,246,252,.15);border-radius:8px;' +- 'padding:8px 11px;max-width:260px;color:#e6edf3;font-size:12.5px;line-height:1.45;' ++ 'background:rgba(22,27,34,.96);border:1px solid rgba(240,246,252,.15);border-radius:8px;' ++ 'padding:8px 11px;max-width:290px;color:#e6edf3;font-size:12.5px;line-height:1.45;' + "font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif"; const tipT = document.createElement('div'); tipT.style.fontWeight = '600'; const tipB = document.createElement('div'); tipB.style.color = '#9aa4b2'; tipB.style.marginTop = '2px'; tip.appendChild(tipT); tip.appendChild(tipB); document.body.appendChild(tip);- const root = scene.transformNodes.concat(scene.meshes).find(n => (n.name||'').indexOf('control-panel_scaffold') === 0);+ let tipsOn = true;+ const dBtn = document.createElement('button');+ dBtn.type = 'button'; dBtn.textContent = 'Descriptions'; dBtn.className = 'on';+ ctl.appendChild(dBtn);+ dBtn.onclick = () => { tipsOn = !tipsOn; dBtn.classList.toggle('on', tipsOn); if (!tipsOn) tip.style.display = 'none'; };++ const T = {+ mini: ['RP2350A Mini (user MCU)', 'RP2350A: dual Cortex-M33 / RISC-V @ 150 MHz, 520 KB SRAM, PIO; W25Q16JV 2 MB flash. 26 USER_IO (PWM, PIO, 4\u00d7 ADC), USB 2.0 FS dual-role. Red D1 = power, blue D2 = status.'],+ usbc: ['USB-C (J1)', 'G-Switch GT-USB-7090C (LCSC C3019716). USB 2.0 dual-role, power delivery 3.0 A; VBUS sourced from PS2 \u2014 PD unavailable while PS2 floats.'],+ usbpath: ['USB VBUS power path', 'TPS25940 smart eFuse (2.7\u201318 V, 5 A limit), TUSB321 CC controller, TPD2EUSB30 USB ESD, AO3401A P-FET back-feed block.'],+ bulk: ['VBUS bulk capacitance', 'C5 150 \u00b5F electrolytic + C4 47 \u00b5F ceramic on the switched 5 V rail.'],+ pwrfield: ['Power contact field (MC1\u2013MC30)', 'PS1 0\u201360 V / 12 A, PS2 5 V / 10 A, PS3 user rail + returns. Medium machine contacts, ~6.4 A each (80% derated), 24 AWG solid-core mating wire.'],+ iofield: ['USER_IO contact field (MC31\u2013MC56)', '26 RP2350 USER_IO lines. Medium machine contacts ~6.4 A, 2 mm pitch; interleaved MC57\u2013MC65 are ground returns.'],+ gndmc: ['Ground contacts (MC57\u2013MC65)', 'Return-path contacts interleaved with the USER_IO rows.'],+ jp1: ['PS1 ground bond (JP1)', 'Large machine-pin jumper bonds the PS1 return to ground. Remove to float PS1.'],+ jp2: ['PS2 ground bond (JP2)', 'Bonds the PS2 isolated return to ground; floated, it may ride up to \u00b12.5 V from common.'],+ jp3: ['PS3 ground bond (JP3)', 'Large machine-pin jumper bonds the PS3 return to ground. Remove to float PS3.'],+ jp4: ['USB return bond (JP4)', 'Ground bond for the USB return path beside the USB-C port.'],+ ccj: ['CC jumper (CCJ)', 'Place when VBUS is broken out through machine pins without CC termination satisfied.'],+ led: ['Power LED (D1)', 'Red 0402 (LCSC C130719) \u2014 scaffold power indicator.'],+ dock: ['ET60T blade dock', 'Samtec ET60T blade set: PS1/PS2/PS3 + returns, USB 2.0, SWD/UART debug, MCU boot/reset \u2014 mates to the workcell each dock.'],+ ghost: ['Control Panel: Workcell (ghost)', 'The workcell half shown mated above: CM5 carrier and power-distribution hub.'],+ posts: ['Ground jumper posts', '12\u00d76 machine-pin jumper stock for the rail ground bonds.'],+ board: ['Control Panel: Scaffold', 'User power and I/O dock board for the base scaffold.'],+ }; const NAME_RULES = [- [/^(U2|Molecule_RP2350A_Mini|mini-D|MINI_)/, ['RP2350A Mini (user MCU)', '26 USER_IO with PWM, PIO and 4 ADC channels; USB 2.0 dual-role. Red = power LED, blue = status LED.']],- [/^(WIRE_MC|MC\d)/, null],- [/^JP\d/, ['Ground-bond jumpers', 'Large machine-pin jumpers bond each rail return to ground. Remove to float a supply.']],- [/^CCJ/, ['CC jumper', 'Place when VBUS is broken out through machine pins without CC termination.']],- [/^(D1$|D1_glow|D1_cone)/, ['Power LED (red)', 'Scaffold power indicator.']],- [/^(ETT|ETS)/, ['ET60T blade dock', 'Power and signal blades that mate to the workcell each dock.']],- [/^GHOST/, ['Control Panel: Workcell (ghost)', 'The workcell half, shown mated above the scaffold.']],- [/^GNDSPACER/, ['Ground spacer', 'Return path to the base scaffold plate.']],+ [/^(U2$|Molecule_RP2350A_Mini|mini-D|MINI_)/, 'mini'],+ [/^J1$/, 'usbc'],+ [/^(U1$|U3$|U4$|Q1$)/, 'usbpath'],+ [/^(C4$|C5$)/, 'bulk'],+ [/^JP1/, 'jp1'], [/^JP2/, 'jp2'], [/^JP3/, 'jp3'], [/^JP4/, 'jp4'],+ [/^(JMP|Adom_Jumper)/, 'posts'],+ [/^CCJ/, 'ccj'],+ [/^(D1$|D1_glow|D1_cone)/, 'led'],+ [/^(WIRE_MC|MC)(\d+)/, (m) => { const k = +m[2]; return k >= 57 ? 'gndmc' : (k >= 31 ? 'iofield' : 'pwrfield'); }],+ [/^(ETT|ETS)/, 'dock'],+ [/^GHOST/, 'ghost'],+ [/^GNDSPACER/, 'posts'], ]; const REGIONS = [- [0.150, 0.192, -0.088, -0.046, ['RP2350A Mini (user MCU)', '26 USER_IO with PWM, PIO and 4 ADC channels; USB 2.0 dual-role.']],- [0.125, 0.141, -0.068, -0.052, ['USB-C 2.0 (user)', 'Dual-role host/device, power delivery 3.0 A. VBUS sourced from PS2.']],- [0.104, 0.141, -0.079, -0.056, ['USB power path', 'Protected VBUS switch and CC controller behind the USB-C port.']],- [0.043, 0.101, -0.096, -0.079, ['Power contact field', 'PS1 / PS2 / PS3 rails and returns land on machine contacts MC1 to MC30.']],- [0.101, 0.196, -0.096, -0.080, ['USER_IO contact field', 'MC31 to MC56: 26 RP2350 USER_IO lines for the project.']],- [0.043, 0.103, -0.078, -0.046, ['Rail ground jumpers', 'Per-rail return-to-ground bonds; each rail is an explicit grounding choice.']],+ [0.1135, 0.1260, -0.0880, -0.0760, 'usbc'],+ [0.1100, 0.1180, -0.0930, -0.0880, 'jp4'],+ [0.0520, 0.0660, -0.0840, -0.0760, 'jp1'],+ [0.0700, 0.0840, -0.0840, -0.0760, 'jp2'],+ [0.0880, 0.1020, -0.0840, -0.0760, 'jp3'],+ [0.0850, 0.0970, -0.1360, -0.1240, 'ccj'],+ [0.1220, 0.1280, -0.0710, -0.0650, 'led'],+ [0.1230, 0.1370, -0.0770, -0.0610, 'usbpath'],+ [0.1030, 0.1110, -0.0870, -0.0770, 'bulk'],+ [0.1600, 0.1800, -0.0860, -0.0500, 'mini'],+ [0.0430, 0.1020, -0.0950, -0.0830, 'pwrfield'],+ [0.1020, 0.1960, -0.0950, -0.0830, 'iofield'], ]; const inv = new window.BABYLON.Matrix();+ const root = scene.transformNodes.concat(scene.meshes).find(n => (n.name||'').indexOf('control-panel_scaffold') === 0); function describe(pick) {- let n = pick.pickedMesh, names = [];- while (n) { names.push(n.name || ''); n = n.parent; }- for (const [re, txt] of NAME_RULES) {- if (names.some(nm => re.test(nm))) { if (txt) return txt; break; }+ let n = pick.pickedMesh;+ while (n) {+ const nm = n.name || '';+ for (const [re, key] of NAME_RULES) {+ const m = re.exec(nm);+ if (m) return T[typeof key === 'function' ? key(m) : key];+ }+ n = n.parent; } if (root && pick.pickedPoint) { root.getWorldMatrix().invertToRef(inv); const p = window.BABYLON.Vector3.TransformCoordinates(pick.pickedPoint, inv);- for (const [x0, x1, y0, y1, txt] of REGIONS) {- if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1) return txt;+ for (const [x0, x1, y0, y1, key] of REGIONS) {+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1) return T[key]; }- if (p.y < -0.098) return ['ET60T blade dock', 'Power and signal blades that mate to the workcell each dock.'];- return ['Control Panel: Scaffold', 'User power and I/O dock board for the base scaffold.'];+ if (p.y < -0.098) return T.dock;+ return T.board; } return null; } let raf = 0; wrap.addEventListener('pointermove', (ev) => {- if (raf) return;+ if (!tipsOn || raf) return; raf = requestAnimationFrame(() => { raf = 0;+ if (!tipsOn) return; const pick = scene.pick(scene.pointerX, scene.pointerY, m => m.isEnabled() && (m.name||'') !== 'ground'); const d = pick && pick.hit ? describe(pick) : null; if (d) { tipT.textContent = d[0]; tipB.textContent = d[1]; tip.style.display = 'block'; const r = wrap.getBoundingClientRect();- tip.style.left = Math.min(ev.clientX - r.left + 14, r.width - 280) + 'px';+ tip.style.left = Math.min(ev.clientX - r.left + 14, r.width - 300) + 'px'; tip.style.top = Math.max(ev.clientY - r.top - 10, 46) + 'px'; } else tip.style.display = 'none'; });