← Commit history

scaffold hover: part numbers + ratings, CPL-exact regions (USB-C, per-rail jumpers), Descriptions toggle

Caleb ·e02bbc5432 ·2mo ago ·parent 2f6bd41
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';           });