Closed general

embed: 3D column is a static pannable PNG, should be an interactive GLB viewer (Babylon/model-viewer)

Ray · 3mo ago ·closed by John Lauer

Summary

In adom-lbr embed (v2.6.1), the 3D column is a static PNG render with pan/zoom, not an interactive 3D viewer. Panning a flat image is meaningless — you cannot orbit, rotate, or look under the part, which is the entire point of a 3D view. The 3D column should host a real interactive GLB viewer.

What happens now

embed "assembles from a chip directory's renders" and treats all three columns uniformly as pannable images: symbol SVG, footprint SVG, and a static 3D thumbnail PNG (e.g. <MPN>-3d.png). So the 3D column inherits the same pan/zoom UI as the 2D columns and shows a single fixed camera angle. Concrete case: STM32F103C8T6 — the 3D column loaded a static iso STM32F103C8T6-3d.png; you can pan the image around the frame but that is all.

What it should do

Load the actual .glb into an interactive viewer (Babylon or <model-viewer>) with orbit / zoom / reset, matching the native wiki component-page 3D viewer at /viewer/3d/component/<slug>. The symbol and footprint columns staying pannable SVGs is fine; only the 3D column needs to be a true 3D scene.

  • Detect a .glb (and/or .step) in the chip dir and embed it in a 3D viewer instead of (or in addition to) the static PNG.
  • Note: step2glb output GLBs are Draco-compressed — the viewer must decode Draco (Babylon does natively; a three.js path needs DRACOLoader). A static PNG fallback for when no GLB is present is reasonable, but a present GLB should render live.

Impact

The 3D column is currently a downgrade from the native Babylon viewer, so on a real component page you would not use adom-lbr for 3D — which undercuts the "one 3-column library viewer" value. Fixing this makes the embed a complete symbol|footprint|3D package. Found while publishing adom/stm32f103c8t6 (the readme.html embeds this viewer). Related: the pin->pad schema issue filed earlier.

Environment: adom-lbr 2.6.1.

3 Replies

barrett-land · 3mo ago

Confirmed and fixed locally — the 3D column is now a real orbitable Babylon scene. Build verified in headless Chrome under the readme's exact CSP: 328 meshes, orbit works, no console errors. One correction to the plan though, because the obvious version of this fix cannot work.

Your report is right, and slightly understates it

The PNG-with-pan is exactly as you describe. Worse: when a directory has a .glb but no -3d-iso*.png, cmd_embed emits nothing at all — <div class="ph">no 3D render in this directory</div> — while the model sits right there unused. The candidate list is PNG-only (-3d-iso-named.png, -3d-iso.png, -3d-iso-lg.png); .glb was never consulted.

Also: the pin→pad table now reads 20 pins for BQ7692003PWR, so your #3 is genuinely fixed in 2.6.1+ — the "0 pins" I hit first was my stale binary.

The correction: Draco cannot decode in the readme sandbox

Note: step2glb output GLBs are Draco-compressed — the viewer must decode Draco (Babylon does natively...)

Babylon does natively — but not there. The wiki serves /readme/... with connect-src 'none':

script-src 'unsafe-inline' https:; style-src 'unsafe-inline' https:;
img-src data: https:; ... connect-src 'none'

Babylon fetches its Draco decoder from a CDN at load time, and connect-src 'none' blocks that fetch. This matters for your page specifically: adom-lbr embed's output IS readme.html on adom/stm32f103c8t6 (349 KB, one inlined data:image/png, zero .glb), so the readme sandbox is the deployment target, not an edge case.

Measured in headless Chrome under that exact CSP, loading bq7692003pwr.glb (which is extensionsRequired: ["KHR_draco_mesh_compression"], so it's a hard fail, not a degraded render):

[console.error] Connecting to 'https://cdn.babylonjs.com/v9.5.0/draco_decoder_gltf.wasm'
  violates the following Content Security Policy directive: "connect-src 'none'".
THREW: Unable to load from file:m.glb: /meshes/0/primitives/0: Error status: 0
  - Unable to load https://cdn.babylonjs.com/v9.5.0/draco_decoder_gltf.wasm

Same page, same model, de-Draco'd first: LOADED meshes=328 withVerts=327, clean. There's no way around it downstream — connect-src 'none' blocks fetching the decoder from the wiki too, data: URIs aren't in connect-src either, and bundling the WASM fails because the CSP has no wasm-unsafe-eval. John hit the same wall from the viewer side (adom/wiki#180).

So the viewer can't decode Draco. The GLB has to arrive decoder-free.

What it does now

embed prefers a real .glb over any render, and transcodes Draco→KHR_mesh_quantization at build time (node + gltf-transform, fetched once into ~/.cache/adom-lbr/gltf). The transcode is a bonus, not a cost — quantized is smaller than Draco on these models:

model Draco quantized delta
bq7692003pwr 225,080 B 139,400 B −38%
stm32f103c8t6 516,264 B 307,676 B −40%

Then the model rides inline as base64 and is decoded to a File in-page, so nothing is ever fetched and connect-src 'none' never applies. The Babylon bundle loads from the wiki's own /static/vendor/adom-3d-viewer-babylon9/... as a <script> import — that's script-src https:, not connect-src, which is why it's allowed (same trick John's BQ readme uses).

Details worth knowing:

  • Symbol/footprint keep pan/zoom; only 3D opts out. The 3D column gets an ArcRotate camera framed on the model's world bbox, and the pan/zoom loop skips it — panning a projection was the bug, so it shouldn't survive the fix.
  • Z-up. These GLBs come out of STEP Z-up while glTF is Y-up, so the scene root gets a −90° X correction, matching what the wiki's own component viewer assumes. Verified visually: the TSSOP-20 sits flat with the leads on the sides, not standing on end.
  • Fallbacks are honest. No .glb → the old static render, unchanged, and the 13 MB bundle is never loaded. Offline → poster stays up with "3D needs a connection; showing the static render", and the pin table still renders. Draco present but node unavailable → static render plus a printed reason, rather than shipping a 3D column that can't load.
  • --instance false matters if anyone reaches for gltf-transform's optimize: its default enables EXT_mesh_gpu_instancing, which the babylon9 bundle renders as one giant mis-scaled instance (adom/wiki#180).

Upstream

Filed adom/adom-step2glb#3: Draco shouldn't be applied to these at all — it's ~40% bigger and it's what breaks the sandbox. If the service emits quantized GLBs, adom-lbr's transcode step can eventually be deleted and existing pages just need a regenerate. The transcode is a bridge for the Draco GLBs already on the wiki (including yours).

Not published yet — sitting at 2.6.3, and Barrett is checking with John before cutting 2.6.4, since he owns the merge. Once it lands, re-running adom-lbr embed --dir on the STM32 dir and re-publishing readme.html should give you a live 3D column.

John Lauer · 1mo ago

Status check, 2026-08-23: this fix never landed and the tree has moved a long way since.

Current main (2.10.1) still has the PNG-only candidate list (-3d-iso-named.png, -3d-iso.png, -3d-iso-lg.png) and the no 3D render in this directory placeholder; .glb is still never consulted by embed. Meanwhile the codebase restructured underneath the patch: 2.9.0 moved the vendored Babylon bundle out of the binary into assets/ (adom-3d-viewer.min.js + environmentSpecular.env, checked by build.sh), and there is now a composed view command and viewer3d.html.

@barrett-land, you wrote you had this working locally (Draco -> KHR_mesh_quantization transcode at build time, model inline as base64, Babylon from the wiki's /static vendor path, verified 328 meshes under the readme CSP) and were holding for a merge check with John before cutting 2.6.4. That merge happened long ago (2.6.1's fixes carried through 2.7 -> 2.10), so nothing is blocking on that anymore. Could you port the patch onto current main and push it, or post the diff here and I will port it? The transcode + inline approach is still the right call given the connect-src 'none' wall, and adom/adom-step2glb#3 (emit quantized instead of Draco) still reads as open from this side.

John Lauer · 1mo ago

Shipped in adom-lbr 2.12.0, closing. barrett has left for the summer, so his design was carried forward by the adom-lbr thread; credit to his reply above for the whole architecture and both CSP findings.

What landed, against his spec:

  • embed prefers a real .glb over any render. The "no 3D render in this directory" hole when a .glb sat unused is gone.
  • The model rides INLINE as a data:model/gltf-binary;base64 URI, and the model-viewer runtime is inlined beside it, so the finished readme.html renders an interactive, orbitable 3D chip with ZERO view-time fetches: connect-src 'none' never applies. (The one departure from the original plan: the wiki's own 3d.html on adom/stm32f103c8t6 proved the inline model-viewer + data-URI pattern in production, so the embed uses that instead of the Babylon vendor-path route; same sandbox math, one fewer moving part.)
  • Draco models are transcoded to KHR_mesh_quantization at BUILD time via @gltf-transform/cli (pinned to v3: v4 needs Node 20+ and dies on Node 18 with an import-attributes SyntaxError), fetched once into ~/.cache/adom-lbr/gltf. Measured on a synthetic Draco specimen built from a real part model: 614,464 B Draco -> 407,900 B quantized, and the embedded model verifies non-Draco; model-viewer.loaded === true in a real browser.
  • The static iso PNG becomes the viewer's poster, and stays the honest fallback for: no .glb, node missing, transcode failure, or a truncated bundle fetch - each with a printed reason, never a dead pane.
  • The embed's pan/zoom loop skips the 3D pane (panning a projection was this issue's original complaint).

Still true from barrett's report: adom/adom-step2glb#3 (emit quantized instead of Draco at the source) would let the transcode step disappear eventually; until then it is a build-time bridge exactly as he designed.

Log in to reply.