3D preview pipeline
Ce contenu n’est pas encore disponible dans votre langue.
Artist Alley generates several preview artifacts per 3D asset so the viewer has something to show immediately and the browse feed can hover-scrub a turntable. Rendering runs in-process — there is no separate render container to deploy.
The renderer is headless Chromium on software WebGL, driven by
scripts/threejs/worker.mjs
and orchestrated by the Go ModelHandler in
app/internal/preview/model.go.
No GPU is required.
Overview
Section titled “Overview”flowchart LR upload[3D asset uploaded] --> probe["preview.3d: stage model + companions"] probe --> render["worker.mjs<br/>headless three.js"] render --> poster[poster.png] render --> frames["turntable/frame_0000..NNNN.png"] render --> views["views/top.png<br/>views/bottom.png"] poster --> col[col / preview / screen thumbnails] frames --> sheet["6×6 sprite sheet + WebVTT cues"] sheet --> hover[Browse-feed hover-scrub]
Why three.js
Section titled “Why three.js”The pipeline previously used a headless Blender container. It was replaced in v0.6.0 and Blender was removed from the image entirely in v0.7.0, halving the image from 3.64 GB to 1.82 GB.
The replacement is roughly 20–30× faster, needs no GPU, and works
on arm64 — the Blender path was amd64-only, so arm64 deployments had
no 3D previews at all before v0.6.0.
It also uses the same three.js loaders as the interactive viewer, which is the property that matters most: the offline render and the in-browser view are meant to agree.
Artifacts
Section titled “Artifacts”The worker writes a fixed on-disk layout that the Go side fans out into stored variants:
<output>/poster.png<output>/turntable/frame_0000.png … frame_{N-1}.png<output>/views/top.png<output>/views/bottom.png| Artifact | Becomes | Notes |
|---|---|---|
poster.png | col / preview / screen raster ladder | The thumbnail you see in the grid. |
turntable/frame_NNNN.png | Per-frame variants | 36 frames by default, one every 10°. |
| Sprite sheet | sprites.jpg + WebVTT cues | 6×6 grid of 160px cells — a 960×960 sheet. Same mechanism as video sprites, so the browse feed scrubs a turntable the way it scrubs a video. |
views/top.png, views/bottom.png | Reference views | Not part of the scrub. |
Each artifact is written only if missing, so a re-run after a partial failure resumes rather than re-rendering everything.
Format coverage
Section titled “Format coverage”Rendered directly by the worker:
| Extension | Loader |
|---|---|
glb, gltf | GLTFLoader |
fbx | FBXLoader |
obj | OBJLoader |
stl | STLLoader |
ply | PLYLoader |
dae | ColladaLoader |
glb / gltf / fbx / obj are also what the interactive viewer
loads. stl / ply / dae are render-only.
Converted first, then rendered: md2, md3, mdl, ms3d, mview
are decoded by pure-Go importers that emit .glb, which then takes the
normal path above.
Not currently rendered: blend, x3d, wrl, usd / usda /
usdc / usdz, abc. These have no stock three.js loader. They upload
and store fine — they just get no turntable until a converter ships as
an optional plugin
(#499).
The dispatch in render.html is the source of truth; the Go side keeps
a mirrored copy, and a smoke test renders one fixture per supported
format so the two cannot silently drift apart.
Companion files
Section titled “Companion files”3D assets routinely carry siblings: .mtl next to .obj, .bin next
to .gltf, separately-uploaded textures. The Go handler stages the model
and its companions into the same working directory before rendering,
so the loaders resolve them by relative URL with no operator
configuration.
| Flag | Default | Notes |
|---|---|---|
--input | required | Path to the source model. |
--workdir | required | Must contain the model and its companions. |
--output | required | Directory root for the artifacts above. |
--frames | 36 | Turntable frame count. 36 fills the 6×6 sprite grid exactly — changing it without changing the grid will not tile correctly. |
--res | 512 | Square render resolution for frames and views. |
--poster-res | 2048 | Poster resolution. |
Worker concurrency is bounded by the job queue rather than by these
flags; see the jobs configuration for preview.3d.
Related
Section titled “Related”- ADR 0069 — the decision to move off Blender.
- Architecture — where the preview worker sits.