Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c041209
Add StlDef and ThreeMfDef FileDef subclasses for 3D model files
FadhlanR Jul 31, 2026
79d3028
Fix fflate runtime shim and glint template type error
FadhlanR Jul 31, 2026
531ef3d
Render live WebGL 3D viewer in embedded/isolated
FadhlanR Jul 31, 2026
cbee366
Fix cross-origin CORS on model viewer byte fetch
FadhlanR Jul 31, 2026
0c50c37
Add STL/3MF example files to experiments realm
FadhlanR Jul 31, 2026
c88878a
Match handoff-realm isolated styling for model FileDefs
FadhlanR Jul 31, 2026
c0aa212
Box the isolated inspector with per-row separators
FadhlanR Jul 31, 2026
35f4473
Render live 3D in fitted (client-side), lazy + non-interactive
FadhlanR Jul 31, 2026
e2e16f3
Address review: bounded parsers, size cap, dedup, unit tests
FadhlanR Jul 31, 2026
808e947
Add end-to-end file-extract acceptance test for STL/3MF
FadhlanR Jul 31, 2026
4514529
Fix test-assets build: move silhouettePath to a card-api-free module
FadhlanR Jul 31, 2026
3073b30
Simplify 3D previews: static cube fitted, header-only extraction, cli…
FadhlanR Aug 3, 2026
b97f29e
Gate the 3D viewer on prerender-vs-live; release WebGL contexts off-s…
FadhlanR Aug 3, 2026
2d96c8c
Add the GLB and glTF 3D model FileDef families
Aug 13, 2026
cd4adf3
Merge remote-tracking branch 'origin/cs-12053-cs-12054-model-filedef-…
lukemelia Aug 17, 2026
3ddb1c0
Merge remote-tracking branch 'origin/main' into cs-12243-3d-model-for…
Aug 18, 2026
39e7c53
Make the glTF bounding box model-space and tighten the parse guards
lukemelia Aug 19, 2026
d79b7bd
Keep the 3D card for unreadable GLB containers; drop stray samples
Aug 19, 2026
fa2265c
Merge remote-tracking branch 'origin/main' into cs-12243-3d-model-for…
Aug 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/base/file-formats/file-shell-isolated.gts
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ export class FileIsolatedShell extends GlimmerComponent<FileIsolatedShellSignatu

get hasModel3d() {
let m = this.args.model?.model3d;
return Boolean(m?.meshes || m?.triangles);
return Boolean(m?.meshes || m?.triangles || m?.vertices || m?.dimensions);
}

get hasFontMetadata() {
Expand Down
43 changes: 36 additions & 7 deletions packages/base/file-formats/metadata-fields.gts
Original file line number Diff line number Diff line change
Expand Up @@ -1165,13 +1165,14 @@ export class HtmlMetadataField extends FieldDef {
// `3D model` inspector section, the same way `encoding` serves audio and video.
//
// Every fact here is read from the file's HEAD at index time (see the
// `*-meta-extractor` modules). The true geometry — transform-correct dimensions,
// full triangle counts — is deliberately left to the live client-side viewer
// (`Model3DPreview`), which already loads and measures the mesh; paying for a
// full geometry scan at index time would duplicate that for no gain. So a value
// is present here only when it sits cheaply in the header: a binary STL's facet
// count, a slicer 3MF's configured face/part counts, the package's materials and
// provenance.
// `*-meta-extractor` modules). A value is present only when it sits cheaply in
// the header: a binary STL's facet count, a slicer 3MF's configured face/part
// counts, the package's materials and provenance, or — for glTF, which
// describes its own scene graph — the vertex count and the transform-composed
// bounding box. What is *not* read here is geometry a header doesn't already
// summarize (an STL/3MF's true extent, a full triangle scan); that is left to
// the live client-side viewer (`Model3DPreview`), which already loads and
// measures the mesh, so a full scan at index time would duplicate it for no gain.
export class Model3dMetadataField extends FieldDef {
static displayName = '3D Model Metadata';
static icon = CubeIcon;
Expand All @@ -1185,9 +1186,21 @@ export class Model3dMetadataField extends FieldDef {
// Triangle/facet count where the header carries it (a binary STL's facet
// count, a slicer 3MF's summed configured face count); absent otherwise.
@field triangles = contains(NumberField);
// Summed across a glTF's mesh-primitive POSITION accessors; other formats'
// headers carry no vertex count.
@field vertices = contains(NumberField);
@field materials = contains(NumberField);
@field materialNames = containsMany(StringField);
@field unit = contains(StringField);
// Scene-graph facts a glTF header enumerates directly.
@field nodes = contains(NumberField);
@field animations = contains(NumberField);
@field textures = contains(NumberField);
// Model-space bounding box, "X × Y × Z", from a glTF's POSITION accessor
// bounds placed through its scene-graph node transforms (so a scaled or
// instanced mesh reports the size it renders at). Unitless: glTF distances are
// nominally meters, but files routinely ignore that.
@field dimensions = contains(StringField);
// Authoring/slicer application (3MF) or the binary STL header string.
@field generator = contains(StringField);
@field solidName = contains(StringField);
Expand Down Expand Up @@ -1219,9 +1232,25 @@ export class Model3dMetadataField extends FieldDef {
{{#if @model.triangles}}
<div class='row'><dt>Triangles</dt><dd>{{@model.triangles}}</dd></div>
{{/if}}
{{#if @model.vertices}}
<div class='row'><dt>Vertices</dt><dd>{{@model.vertices}}</dd></div>
{{/if}}
{{#if @model.dimensions}}
<div class='row'><dt>Size</dt><dd>{{@model.dimensions}}</dd></div>
{{/if}}
{{#if @model.unit}}
<div class='row'><dt>Units</dt><dd>{{@model.unit}}</dd></div>
{{/if}}
{{#if @model.nodes}}
<div class='row'><dt>Nodes</dt><dd>{{@model.nodes}}</dd></div>
{{/if}}
{{#if @model.animations}}
<div class='row'><dt>Animations</dt><dd
>{{@model.animations}}</dd></div>
{{/if}}
{{#if @model.textures}}
<div class='row'><dt>Textures</dt><dd>{{@model.textures}}</dd></div>
{{/if}}
{{#if @model.materialNames.length}}
<div class='row'><dt>Materials</dt><dd
>{{this.materialList}}</dd></div>
Expand Down
Loading
Loading