Skip to content
RPRichard PruittTech & Cyber
Navigation
repo://poppyup/viewer/README.md

viewer/README.md

13 KB · 126 lines · markdown · View rendered · Download from the repository page

viewer/README.md
# PoppyUp — 3D mode (interactive assembly explorer) Browser-based, offline viewer of the Phase 1 PoppyUp hardware concept: component tree, labels, exploded view, isolation, section plane, Base/Pro SKU toggle. Geometry is **generated procedurally** from the numbers in the design package; there is no CAD model in this project. ## Run ES modules need an HTTP origin (opening `index.html` from `file://` will not work in Chrome/Safari): ```bashpython3 -m http.server 8000 -d viewer# then open http://localhost:8000/``` No network access is required: three.js r186 is vendored in `vendor/three/` (MIT, licence included). Tested in Google Chrome (headless, SwiftShader) on macOS; see *Validation* below for what was and was not exercised. ## Using the viewer | Want to… | Do ||---|---|| Orbit / pan / zoom | drag · right-drag or two-finger drag · wheel or pinch || Select a part | click it (a drag never selects), or click it in the tree; double-click a tree row to focus || Standard views, fit, home | toolbar **Front / Rear / Left / Right / Top / Bottom / Iso**, **Fit all** (frames what is visible), **Reset view** (home camera), **Reset viewer** (camera + visibility + explosion + section + display) || Focus / isolate / hide / parent | buttons in the details panel, or keys `F` `I` `H` `Backspace`; **Show all** restores hidden parts, **Exit isolation** returns to the whole object, `Esc` clears the selection || Explode | slider 0–100 %, **Explode / Reassemble / Pause** (animation is interruptible; honours `prefers-reduced-motion`), **Scope** limits the explosion to one subassembly, **Explode subassemblies too** also spreads children || Labels | **Selected only / Major components / All visible (decluttered) / None**; **X-ray labels** shows occluded labels dashed || Display | **Wire** edge overlay · **Ghost** fades everything but the selection · **Section** uncapped clipping plane (axis, position, flip, reset) || SKU | **Pro** shows the ASM2464PD, NVMe, PD-C and VBUS mux; **Base** hides them and shows the empty M.2 socket || Search | by name, ID, part number, function, description; matches are highlighted with their ancestors expanded || Keyboard tree | arrows move / expand / collapse, `Enter` selects, `F` focus, `I` isolate, `H` hide, `Home`/`End` | If WebGL is unavailable the page falls back to a text table of every component with its metadata. ## Files | File | Role ||---|---|| `components.js` | **The component-aware model**: 137 components (13 top-level assemblies, parts, repeated instances, reference geometry) with ID, parent, name, description, function, part number, material, dimensions, source, confidence, SKU, explosion offset and geometry spec. Pure data, shared by the browser and the Node validator. || `geometry.js` | Turns geometry specs (box, cylinder, rounded plate with holes, rounded ring) into renderer meshes; document frame → renderer frame conversion; material palette by material family. || `explode.js` | Explosion math shared by app and validator: `position(t) = assembled + ease(t) × offset`, never accumulated. || `app.js` | Viewer: state, visibility, selection sync (scene ↔ tree ↔ details), camera framing, labels with occlusion and decluttering, section plane, picking, keyboard, fallback, `window.__poppyViewer` test API. || `validate.mjs` | Node structural validation (IDs, hierarchy, instance counts, envelope, AABB interference, explosion determinism). || `test/run.mjs` | Headless-Chrome interaction test + screenshots (`screenshots/`). | ### Coordinate convention Document frame, millimetres, identical to `docs/08-mechanical.md` and the drawings: **X** 0→190 left→right viewed from the front; **Y** 0→96 top edge (slots) → bottom edge (ports), growing downward; **Z** 0→38 front face → rear (magnesium) face. The renderer uses Y-up with the device centred at the origin; `geometry.js` does the conversion, so every number in `components.js` can be checked directly against the documents. ## Evidence register What the model is built from and how much to trust each part. Confidence is also shown per component in the details panel. | Modelled feature | Source | Status ||---|---|---|| Envelope 190 × 96 × 38, R10 plan corners | 08 §2.1 | **verified** || Z-stack front→rear (frame 2.5 · foam · cradle · 21 mm cell · main board 27.9–29.5 · 6.5 mm rear budget · skin) | 08 §3.2 table | **verified** || Slot row: 5 housings, X positions, 4 mm gaps, 163 mm row, opening sizes, insertion depths | 08 §5; `drawings/generate_drawings.py` | **verified** || Slot channel 22 × 6 mm (Z 8–30), 10 mm end caps, 170 mm shutter X 10–180 | 08 §5, §6; top-view drawing | **verified** (3° drain slope, 5° draft, drains not modelled) || Shutter: 2 slats 2 × 20 × 170, hinge pin, 8 slide pins, 2 magnets at X 55 / 150, closed positions | 08 §6.1–6.2; top-view drawing | **verified**; slat-2 corner wrap simplified to a 2 mm step || Rails: POM T-track in end caps X 7–10 / 180–183, 40 mm rear leg, one detent per track | 08 §6.1–6.2 | **derived**; R14 corner arc drawn as a straight step || Rear pocket step 2.5 mm over Y 0–42; ribs 1.5 mm at 20 mm pitch; bosses under SoM / ASM2812 / RTL8126 | 08 §3.2, §6.1, §10 | **verified** (rib count/positions derived) || Front frame apertures: lens 62 × 36, door 154 × 50, button Ø12 at X 30 Y 12, BLE window 7 × 14, Wi-Fi zones 40 × 8 | 08 §3.1; front-view drawing | **verified** — *see conflict 1* || Battery pack 144 × 44 footprint X 23–167 Y 44–88, 4 × Ø21 × 70 cells, cradle walls 0.8 | 08 §3.1–3.2 | **verified**; cell row centres and pack-PCB position **approximate** || Reader board 172 × 38 at X 9–181, Y from 8 | 09 §1; 08 §3.1 | **verified** outline — *see conflicts 2 and 3* || Main board 165 × 80, Y 12–92, Z 27.9–29.5 | 09 §1; 08 §3.1–3.2 | **verified** outline — *see conflict 4* || On-board component placement (SoM, switch, mux, bridge, PHY, M.2 ×2, EC, TPM, charger, bucks, PD ×3, USB-C ×3, RJ45) | 09 §1.1 sketch (topology only) | **approximate** — positions authored to honour the sketch's rules (bridge/mux at top edge, M.2 on the right, switchers bottom-left, RJ45 on the front face at X 167–186) || SoM outline 70 × 55 (Core-3588J) | 09 §1.1 | **approximate** — SoM undecided (D12); the exploded-view drawing uses a 60 × 26 placeholder || Package sizes of ICs (ASM2812 17 × 17, ASM2464PD 14 × 14, …) | none | **assumed** for visualisation || Thermal pads (SoM 2.0, switch/PHY 1.5, two cage bridge pads 1.5) | 08 §10 | thickness **verified**, areas **approximate** || Gaskets (frame perimeter, door, shutter) 1.5 mm section | 08 §4, §6.3 | **approximate**; wiper lip, shingle, brush seals, EMI strip not modelled || Frame screws ×14, door screws ×6 | 08 §12; front-view drawing | door positions **verified**; frame positions **approximate**; standoff/SoM/pack screws, brackets, rivets not modelled || Antenna flexes 40 × 8 at X 12–52 / 130–170, Y 30–38 | 08 §3.1 | **verified**; MHF4 cables not modelled || Vent Ø8, 1/4"-20 insert, RJ45 door | 08 §7 | **approximate** positions || Inserted CFexpress B card | 08 §5 | reference geometry, **verified** size || Part numbers | `docs/10-bom.md` | as listed there; items marked "(verify)" in the BOM stay unverified | **Not modelled / unknown:** foam, FPCs and cables, strap slots, lanyard hole, drains, port cut-outs in the bottom wall (ports pass through as separate meshes), USB-C brackets, EMI gasket, internal features of any purchased part, the fan envelope (25 × 25 × 10 reserved zone, D5), textures and coatings. ### Conflicts found in the source documents while building the model 1. **OLED module vs battery door** — module outline Y 7–43 (drawing) overlaps the door aperture Y 42–92 by 1 mm. Modelled: lens/module Y 7–42 (active area 10–40 unchanged).2. **Reader board height vs battery pack** — 172 × 38 with its top edge 8 mm below the shutter plane puts its bottom at Y 46, inside the pack (Y 44–88, Z 3.3–25.9). Modelled: Y 8–44. (09 §1's table also says 180 × 38 while its text says 172.)3. **Reader board Z vs slot centreline** — 08 §3.3 places the board at Z 14.0–15.6, but its front-face connectors would then sit at Z 7–14 while the top-view drawing puts the slot centreline at Z 15. Modelled: board at Z 17.0–18.6 (08 §3.3 notes ~4 mm of slack in the band) so the connectors and card centre on Z 15.4. **Main board X span** — the exploded-view drawing draws the 165 mm board at X 12–177, but Ports A/B/C at X 25/43/61 and the RJ45 at X 167–186 need the board to reach X ≈ 186. Modelled: X 20–185. Consequence: the BLE keep-out (docs X 12–18) sits at X 20–26 in the model.5. **Hall sensor position** — 08 §6.2 puts it on the reader board at X 95 "under the rear rim"; the top-view drawing shows it at Z 33, behind the reader board. Modelled on the reader board's rear face at its top edge, flagged approximate. None of these are resolved here; they are candidates for the next ADR revision (`docs/00` owns them). ### Explosion Offsets are authored per component in the document frame and follow the exploded-view drawing's front→rear stack: front parts move toward the front (−Z), the chassis and pads toward the rear (+Z), the shutter and rails upward, bumpers outward. Whole-object explosion moves the 13 top-level assemblies; children keep their internal arrangement unless the scope is set to their assembly or "Explode subassemblies too" is on, so each offset is applied exactly once. **The motion is illustrative**: it is not the assembly sequence in 08 §12 (shown in the explode bar) and not a validated disassembly procedure. ## Validation Run from the repo root. `test/run.mjs` needs a local Google Chrome and `puppeteer-core` (install it in any scratch directory and point `PUPPETEER_DIR` at it). ```bashnode viewer/validate.mjsPUPPETEER_DIR=/path/with/node_modules node viewer/test/run.mjs``` Results on 2026-09-27 (macOS, Node 24, Google Chrome headless with SwiftShader, 1500 × 950 then 900 × 700): | Check | Result ||---|---|| Unique IDs, parents resolve, acyclic hierarchy, geometry on every non-assembly, instance counts = definition qty (9 definitions) | PASS || Every component has source + confidence; explode vectors well-formed | PASS || All geometry inside the envelope tolerance (X 0–190, Y −4…98, Z −1…40) | PASS || No unintended AABB interference between leaf parts (pads/bosses/fasteners/reference zones/pass-through connectors excluded) | PASS after fixing 18 initial overlaps || Explosion: 0 % = assembled (max offset 0), 100 % = authored offset, deterministic over 500 cycles (drift 0), scoped explosion moves only the scope's children, whole-object explosion moves only top-level components | PASS || Loads with no page/console errors; renders (≈ 181 draw calls, ≈ 13 k triangles, 175 geometries); load ≈ 1.2 s | PASS || Scene ↔ tree ↔ details selection agree; click selects, drag does not; picking hits the front-face part at viewport centre | PASS || 100 % explosion moves the chassis by exactly its offset; children stay assembled inside the exploded assembly; 20 explode cycles return to the exact assembled transform; scoped explosion of the battery pack | PASS || Labels shown in major mode while exploded (13 shown of 36 candidates: 15 occluded, 8 decluttered) | PASS || Isolate / exit isolation, hide assembly hides parts, selection persists when hidden, hidden parts get no label, show all | PASS || Search reveals matches with ancestors; Base SKU hides Pro-only parts; section state; reset viewer; near/far sized to model; no errors after resize | PASS || Screenshots: `01-assembled-iso`, `02-exploded-100`, `03-isolated-battery-pack-scoped-explode`, `04-section-x-battery-band`, `05-small-layout` | captured, inspected | **NOT RUN:** Safari and Firefox; touch gestures on a real device; embedded webviews (a desktop headless test does not verify embedded compatibility); screen-reader pass (ARIA roles and names are present, keyboard tree operation is implemented, but not audited with VoiceOver); GPU-accelerated rendering (SwiftShader only in CI-style runs; the user's own browser will use the GPU). ## Known limitations - Section cuts are uncapped; the cut shows back faces, not modelled interiors. Purchased parts (SoM, cells, connectors) are solids with no internal detail.- Chassis walls are boxes; R8 chassis corners, drafts and the bottom-wall cut-outs are not modelled, so ports visually pass through the wall.- Labels are decluttered greedily by priority (selected › hovered › major › other); in "All visible" mode at long range only assemblies are labelled.- The model is a **visualisation**. It carries no manufacturing tolerances, no verified service sequence and no engineering approval.