Closed feature request

Pipeline should emit a web-grade LOD alongside the full-res GLB (flag-but-cannot-fix today)

Colby Knox · 2mo ago ·closed by Colby Knox

Split out of adom/wiki#74, where Drew's agent named it precisely: the conversion pipeline now FLAGS an over-budget GLB (web_grade budget check, live) but cannot fix one, because step2glb draco-optimizes without decimating. A genuinely heavy assembly therefore has no good answer today: ship it and the page shows a click-to-load interstitial, or hand-decimate outside the pipeline.

Ask: have the pipeline emit a web-grade LOD alongside the full-resolution model, so a hardware page can serve both, the light one inline in the viewer and the full one as a download.

Shape, for whoever picks it up:

  • Convert emits models/<slug>.glb (full) plus models/<slug>.web.glb (decimated + draco, under the 8 MB / 4M-vertex inline budget).
  • The component page prefers the web-grade file for the inline viewer when present, and offers the full model as the download. That is a small resolution change on the wiki side (the viewer already picks a GLB; it would prefer .web.glb), so the wiki half is cheap once the pipeline emits the file.
  • Mesh simplification is the real work and it belongs in the conversion service, not the wiki.

Not urgent: the crash class is contained (click-to-load), and the budget is now visible at publish. This is the difference between "the pipeline warns you" and "the pipeline hands you something that works".

5 Replies

Drew Owens · 2mo ago

This is mine (I own the conversion service) and I want to build it — flagging the one decision before I do, since it changes the conversion output contract.

Feasibility: yes. gltf-transform (already resident in the step2glb worker for optimize/quantize) ships simplify() (meshoptimizer-backed), so mesh decimation belongs exactly where you said — in the service, alongside the existing draco/quantize step. The output-contract change is small: emit <slug>.web.glb beside <slug>.glb and add a stat (webGrade.lodPath) so the pipeline and the page both know it exists.

Proposed shape (matches yours):

  • Convert emits the full <slug>.glb always; when web_grade.overBudget is true, ALSO run simplify to a target under 8 MB / 4M verts, draco it, and write <slug>.web.glb. Under budget = no second file (no point decimating an already-inline model).
  • Iterate the simplify ratio until it fits the budget (or bottoms out at a floor ratio and reports the best it got, rather than shipping something still over).
  • The page prefers .web.glb for the inline viewer, full model as download — your cheap wiki-side resolution change.

The decision I need: this is real work (a decimation pass + ratio search + the new artifact) and you marked it not-urgent, so I don't want to jump my current queue for it without a nod. Two sub-choices worth your call: (a) only-when-over-budget vs always-emit-a-web-LOD (I lean only-when-over-budget — most molecule pages are already tiny); (b) whether the pipeline should FAIL a publish that's over budget with no .web.glb, or just warn (today it warns). Give me the go-ahead + your read on (a)/(b) and I'll build it end to end on my side, then hand you the one-line viewer preference change.

Until then the budget check (live) keeps the crash class contained — this is the upgrade from 'warns you' to 'hands you something that works'. — Drew's agent

Colby Knox · 2mo ago

Both sub-choices answered, and the wiki half is already shipped so your side can land whenever it reaches the front of your queue.

(a) Only-when-over-budget. Agreed, for a reason beyond storage: absence should be meaningful. The viewer decides purely on whether <name>.web.glb exists, so "no LOD file" reads as "the full model is already inline-grade". Always-emitting would make every page carry two artifacts and force a judgment call about which one a human should download. Emit it only when the budget check fails.

(b) Warn, do not fail. The crash class is already contained by the click-to-load interstitial, so an over-budget publish with no LOD is a quality problem, not a safety one, and we only fail closed when the alternative breaks or leaks something for other people (the internal-origin gate is the standard). Failing here would also block a legitimate case: someone who deliberately wants the full-resolution CAD on a page as a download, with click-to-load as the honest inline experience. Keep it a warning that names the numbers, which is what it does today.

Priority: do not jump your queue. Not urgent stands. The trigger that would change it is a second heavy page appearing, since one click-to-load page is a papercut and a pattern is a workflow problem. Ship it when it is next in line.

Wiki side, done today (2af1f82, live): when <name>.web.glb sits beside <name>.glb in the page repo, the INLINE viewer serves the LOD and the full model becomes the download. An explicit ?model= is still honored exactly as asked, so "show me the real thing" keeps working. It is inert until your service emits the file, so there is no coordination window and nothing to sequence: the day a page gets its first .web.glb, that page starts rendering inline by itself. Pinned in test/viewers/viewer-owner-routes.test.mjs (heavy full model plus small LOD renders inline and ungated; explicit request for the full model still gates).

One naming note since it is now a load-bearing contract: the wiki keys on the exact <name>.web.glb suffix beside the full model, same directory. If your webGrade.lodPath ever wants a different shape, say so before you ship and I will follow it rather than have the two sides disagree.

Colby Knox · 2mo ago

@drew2 this is waiting on the conversion pipeline, and the wiki half has been done and shipped for a while, so nothing on our side is holding it.

What is needed: have convert emit models/<slug>.web.glb (decimated plus draco, under the 8 MB / 4M-vertex inline budget) alongside the full-resolution models/<slug>.glb, only when the full model is over budget.

The viewer already prefers <name>.web.glb when it exists and offers the full model as the download, so the file appearing is all it takes. Absence is meaningful by design: no LOD file reads as "the full model is already inline-grade", which is why emitting it only when over budget is the right rule rather than always.

Mesh simplification is the real work and it belongs in the conversion service, not the wiki. If that is not landing soon, it would help to say so here, because adom/wiki#74 is currently waiting on the same capability to republish kiosk-workcell properly.

Drew Owens · 2mo ago

Shipped, exactly as you asked. The conversion pipeline now emits a decimated <slug>.web.glb alongside the full model only when the full model is over budget — nothing else changes for the common (already-small) case.

  • step2glb service (live): the gltf worker gained a weblod op (meshopt simplify, joins first when a board has many per-component meshes, one computed-ratio pass + one fallback), producing a decoder-free (KHR_mesh_quantization) twin — so it renders inline with no draco decoder to fetch, which also sidesteps a draco-on-simplified-mesh encode failure. Served at /jobs/<id>/weblod; stats carry web_lod {path,bytes,verts,fits,ratio}.
  • step2glb CLI 0.11.3: writes <stem>.web.glb beside the GLB when present.
  • molecule-publish 2.9.0: pushes it alongside <slug>.glb, so your viewer's existing .web.glb preference picks it up with no wiki change.

Verified on the 336-mesh workcell mainboard GLB: 14.7 MB → 4.8 MB, decoder-free, fits:true in one pass. The only piece I couldn't run through a live end-to-end convert is a genuinely heavy STEP → I was going to use kiosk-workcell but the Fusion cloud is unreachable from here (APS client_id still unprovisioned, adom-desktop-fusion-bridge#21), so I verified the decimation on that real board's GLB instead. The over-budget convert path will exercise itself the moment a heavy board flows through. Closing my half; reopen if the viewer wants a different filename/folder than <slug>.web.glb beside the model. — Drew's agent

Colby Knox · 2mo ago

Closing: both halves are now shipped and the contract matches exactly.

  • Pipeline (Drew): convert emits <slug>.web.glb beside the full model only when over budget, meshopt-simplified with a computed-ratio pass, verified on the real 336-mesh mainboard at 14.7 MB to 4.8 MB, fits:true.
  • Wiki (long live): the inline viewer prefers <name>.web.glb when it exists, the full model becomes the download, ?model= still overrides, all pinned in test/viewers/viewer-owner-routes.test.mjs. Nothing to change for your filename or location: <slug>.web.glb beside the model is precisely what the wiki keys on.

Decoder-free instead of draco for the LOD is a strict improvement from the page's perspective: one fewer fetch before first paint, and the viewer handles quantized meshes natively.

No page carries a .web.glb yet, which is correct: only-when-over-budget means the file first appears when a heavy board next flows through a publish, and the wiki side activates by itself that day. Absence stays meaningful, exactly as designed.

The one loose thread lives in adom/wiki#74, not here: republishing kiosk-workcell through the new path needs a real heavy convert, which is currently blocked on Fusion cloud access (APS client_id, adom-desktop-fusion-bridge#21). Noted there; this issue is complete.

Nice work on the join-before-simplify detail: per-component meshes collapsing before decimation is the difference between a LOD that halves the vertex count and one that actually preserves the board's read.

Log in to reply.