@chestnutlabs/gcode-model-renderer 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/model-viewer.d.ts +15 -2
- package/dist/model-viewer.d.ts.map +1 -1
- package/dist/model-viewer.js +30 -7
- package/dist/render-model-still.d.ts +8 -6
- package/dist/render-model-still.d.ts.map +1 -1
- package/dist/render-model-still.js +26 -3
- package/dist/scene-model.d.ts +23 -0
- package/dist/scene-model.d.ts.map +1 -1
- package/dist/scene-model.js +84 -0
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,6 @@ export type { ModelLoader, ModelLoadOptions, ModelSourceInput } from './loaders.
|
|
|
20
20
|
export { computeCacheKey, defaultEnvId } from './cache-key.js';
|
|
21
21
|
export { DEFAULT_LIMITS, resolveLimits, ModelParseError } from './limits.js';
|
|
22
22
|
export type { ModelLimits, ResolvedLimits } from './limits.js';
|
|
23
|
-
export { IDENTITY_MAT4 } from './scene-model.js';
|
|
24
|
-
export type { ModelScene, ModelObject, ModelMaterial, ModelPlateSummary, MeshGeometry, ModelBounds, RGB, Mat4 } from './scene-model.js';
|
|
23
|
+
export { IDENTITY_MAT4, applyRenderScope } from './scene-model.js';
|
|
24
|
+
export type { ModelScene, ModelObject, ModelMaterial, ModelPlateSummary, MeshGeometry, ModelBounds, RenderScope, RGB, Mat4 } from './scene-model.js';
|
|
25
25
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACnG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAC5G,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC3G,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,qBAAqB,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAChH,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7E,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACnG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAC5G,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC3G,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,qBAAqB,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAChH,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7E,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACnE,YAAY,EACV,UAAU,EACV,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,WAAW,EACX,GAAG,EACH,IAAI,EACL,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -14,4 +14,4 @@ export { parse3mf } from './three-mf.js';
|
|
|
14
14
|
export { stlLoader, threeMfLoader, DEFAULT_MODEL_LOADERS, isModelScene, resolveModelScene } from './loaders.js';
|
|
15
15
|
export { computeCacheKey, defaultEnvId } from './cache-key.js';
|
|
16
16
|
export { DEFAULT_LIMITS, resolveLimits, ModelParseError } from './limits.js';
|
|
17
|
-
export { IDENTITY_MAT4 } from './scene-model.js';
|
|
17
|
+
export { IDENTITY_MAT4, applyRenderScope } from './scene-model.js';
|
package/dist/model-viewer.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { type CameraMode, type CameraState, type CameraView, type GLRendererLike, type InteractiveStageOptions, type LoadProgress, type RenderTargetCanvas } from '@chestnutlabs/gcode-renderer-three';
|
|
1
|
+
import { type CameraMode, type CameraState, type CameraView, type CaptureOptions, type GLRendererLike, type InteractiveStageOptions, type LoadProgress, type RenderTargetCanvas } from '@chestnutlabs/gcode-renderer-three';
|
|
2
2
|
import type { Confidence } from '@chestnutlabs/toolpath-core';
|
|
3
3
|
import { type ModelLoader, type ModelSourceInput } from './loaders.js';
|
|
4
4
|
import { type ModelLimits } from './limits.js';
|
|
5
5
|
import type { ModelBackground, PresentationView } from './model-renderer.js';
|
|
6
|
-
import { type ModelBounds, type ModelPlateSummary } from './scene-model.js';
|
|
6
|
+
import { type ModelBounds, type ModelPlateSummary, type RenderScope } from './scene-model.js';
|
|
7
7
|
export interface ModelViewerOptions {
|
|
8
8
|
/** Loader registry (open `kind`). Default: `[stlLoader, threeMfLoader]`. */
|
|
9
9
|
loaders?: readonly ModelLoader[];
|
|
@@ -21,6 +21,8 @@ export interface ModelViewerOptions {
|
|
|
21
21
|
createRenderer?: (canvas: RenderTargetCanvas) => GLRendererLike;
|
|
22
22
|
/** Injected orbit controls (tests). Default: three `OrbitControls` via the stage. */
|
|
23
23
|
createControls?: NonNullable<InteractiveStageOptions['createControls']>;
|
|
24
|
+
/** Initial render scope (DD-030 D2) — e.g. `{ plateId: 3 }`. Omit to render the whole source. */
|
|
25
|
+
renderScope?: RenderScope;
|
|
24
26
|
/**
|
|
25
27
|
* Staged loading-progress callback (DD-024): typed `stage`/`done`/`total`/`unit` events (no human copy),
|
|
26
28
|
* each tagged with the load `generation` so a consumer drops events from a superseded `setSource`. The
|
|
@@ -86,6 +88,17 @@ export interface ModelViewer {
|
|
|
86
88
|
resize(width: number, height: number): void;
|
|
87
89
|
/** Re-fit the camera to the current model bounds. */
|
|
88
90
|
frame(): void;
|
|
91
|
+
/**
|
|
92
|
+
* Render only a subset of the current source (DD-030 D2): `{ plateId }`, `{ objectIds }`, or an
|
|
93
|
+
* `{ instanceFilter }`; `null` restores the whole source. Rebuilds and reframes to the subset. Gate a
|
|
94
|
+
* `{ plateId }` on the ready info's `plates` being present — an unmatched scope renders empty.
|
|
95
|
+
*/
|
|
96
|
+
setRenderScope(scope: RenderScope | null): void;
|
|
97
|
+
/**
|
|
98
|
+
* Capture the current view as an image `Blob` (DD-030 D1) — for an operator-selected thumbnail or a
|
|
99
|
+
* large-file fallback. Rejects with `E_CAPTURE_UNSUPPORTED` when the renderer is unavailable.
|
|
100
|
+
*/
|
|
101
|
+
capture(opts?: CaptureOptions): Promise<Blob>;
|
|
89
102
|
onEvent(cb: (e: ModelViewerEvent) => void): () => void;
|
|
90
103
|
dispose(): void;
|
|
91
104
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-viewer.d.ts","sourceRoot":"","sources":["../src/model-viewer.ts"],"names":[],"mappings":"AAeA,OAAO,
|
|
1
|
+
{"version":3,"file":"model-viewer.d.ts","sourceRoot":"","sources":["../src/model-viewer.ts"],"names":[],"mappings":"AAeA,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC5B,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACxB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAA4C,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjH,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EAEtB,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IACjC,oEAAoE;IACpE,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,oFAAoF;IACpF,kBAAkB,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACpC,0DAA0D;IAC1D,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,gEAAgE;IAChE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,2GAA2G;IAC3G,eAAe,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;IAClD,2FAA2F;IAC3F,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,cAAc,CAAC;IAChE,qFAAqF;IACrF,cAAc,CAAC,EAAE,WAAW,CAAC,uBAAuB,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACxE,iGAAiG;IACjG,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;CAC/C;AAED,yFAAyF;AACzF,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,UAAU,CAAC;IACtB,MAAM,EAAE,WAAW,CAAC;IACpB;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAEzD;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAEjC,MAAM,WAAW,WAAW;IAC1B,4FAA4F;IAC5F,SAAS,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5D,sEAAsE;IACtE,OAAO,CAAC,IAAI,EAAE,gBAAgB,GAAG,UAAU,GAAG,IAAI,CAAC;IACnD,gGAAgG;IAChG,cAAc,IAAI,WAAW,GAAG,IAAI,CAAC;IACrC,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IACzC,aAAa,CAAC,EAAE,EAAE,eAAe,GAAG,IAAI,CAAC;IACzC,qBAAqB,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,CAAC;IAClD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,qDAAqD;IACrD,KAAK,IAAI,IAAI,CAAC;IACd;;;;OAIG;IACH,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAAC;IAChD;;;OAGG;IACH,OAAO,CAAC,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACvD,OAAO,IAAI,IAAI,CAAC;CACjB;AAMD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,EAAE,OAAO,GAAE,kBAAuB,GAAG,WAAW,CA0K3G"}
|
package/dist/model-viewer.js
CHANGED
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
* Interactive is a browser concern — headless/offscreen stills stay `renderModelStill` (DD-018 §4.3).
|
|
14
14
|
*/
|
|
15
15
|
import { Color, Scene } from 'three';
|
|
16
|
-
import { InteractiveStage, createDefaultGLRenderer } from '@chestnutlabs/gcode-renderer-three';
|
|
16
|
+
import { CaptureUnsupportedError, InteractiveStage, createDefaultGLRenderer } from '@chestnutlabs/gcode-renderer-three';
|
|
17
17
|
import { ModelContent } from './model-content.js';
|
|
18
18
|
import { DEFAULT_MODEL_LOADERS, resolveModelScene } from './loaders.js';
|
|
19
19
|
import { ModelParseError } from './limits.js';
|
|
20
|
-
import { sceneInstanceCount } from './scene-model.js';
|
|
20
|
+
import { applyRenderScope, sceneInstanceCount } from './scene-model.js';
|
|
21
21
|
function backgroundColor(bg) {
|
|
22
22
|
return bg === 'transparent' ? null : new Color(bg);
|
|
23
23
|
}
|
|
@@ -48,7 +48,11 @@ export function createModelViewer(canvas, options = {}) {
|
|
|
48
48
|
const content = new ModelContent(scene);
|
|
49
49
|
// Retained so context-loss recovery can rebuild meshes from the last-set scene.
|
|
50
50
|
let currentScene = null;
|
|
51
|
+
// Active render scope (DD-030 D2); applied to `currentScene` on build/reframe/restore. Null = whole source.
|
|
52
|
+
let currentScope = options.renderScope ?? null;
|
|
51
53
|
let disposed = false;
|
|
54
|
+
/** The scene to actually build/render = the full source narrowed by the active scope. */
|
|
55
|
+
const scopedScene = () => currentScene === null ? null : currentScope ? applyRenderScope(currentScene, currentScope) : currentScene;
|
|
52
56
|
// Monotonic token for last-wins overlapping setSource (stale async results are discarded).
|
|
53
57
|
let sourceToken = 0;
|
|
54
58
|
let stage = null;
|
|
@@ -65,8 +69,9 @@ export function createModelViewer(canvas, options = {}) {
|
|
|
65
69
|
onContextRestored: () => {
|
|
66
70
|
// GPU resources are gone; rebuild meshes from the retained scene and reframe, mirroring the
|
|
67
71
|
// toolpath renderer's recovery.
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
const shown = scopedScene();
|
|
73
|
+
if (shown !== null && stage !== null) {
|
|
74
|
+
content.setScene(shown);
|
|
70
75
|
const f = content.framing;
|
|
71
76
|
if (f !== null)
|
|
72
77
|
stage.frameTo(f.center, f.radius);
|
|
@@ -114,10 +119,11 @@ export function createModelViewer(canvas, options = {}) {
|
|
|
114
119
|
// Last-wins: a newer setSource (or a dispose) superseded this one — discard without mutating.
|
|
115
120
|
if (my !== sourceToken || disposed || stage === null)
|
|
116
121
|
return info;
|
|
117
|
-
const total = parsed.objects.length;
|
|
118
|
-
progress({ stage: 'building-geometry', done: 0, total, unit: 'objects' });
|
|
119
|
-
content.setScene(parsed, (done) => progress({ stage: 'building-geometry', done, total, unit: 'objects' }));
|
|
120
122
|
currentScene = parsed;
|
|
123
|
+
const shown = scopedScene(); // parsed just set → non-null
|
|
124
|
+
const total = shown.objects.length;
|
|
125
|
+
progress({ stage: 'building-geometry', done: 0, total, unit: 'objects' });
|
|
126
|
+
content.setScene(shown, (done) => progress({ stage: 'building-geometry', done, total, unit: 'objects' }));
|
|
121
127
|
const f = content.framing;
|
|
122
128
|
if (f !== null)
|
|
123
129
|
stage.frameTo(f.center, f.radius);
|
|
@@ -160,6 +166,23 @@ export function createModelViewer(canvas, options = {}) {
|
|
|
160
166
|
if (f !== null)
|
|
161
167
|
stage?.frameTo(f.center, f.radius);
|
|
162
168
|
},
|
|
169
|
+
setRenderScope(scope) {
|
|
170
|
+
currentScope = scope;
|
|
171
|
+
const shown = scopedScene();
|
|
172
|
+
if (shown === null || stage === null)
|
|
173
|
+
return; // no source yet — applied on the next setSource
|
|
174
|
+
content.setScene(shown);
|
|
175
|
+
const f = content.framing;
|
|
176
|
+
if (f !== null)
|
|
177
|
+
stage.frameTo(f.center, f.radius);
|
|
178
|
+
stage.render();
|
|
179
|
+
},
|
|
180
|
+
capture(opts) {
|
|
181
|
+
if (stage === null) {
|
|
182
|
+
return Promise.reject(new CaptureUnsupportedError('model viewer renderer unavailable'));
|
|
183
|
+
}
|
|
184
|
+
return stage.capture(opts);
|
|
185
|
+
},
|
|
163
186
|
onEvent(cb) {
|
|
164
187
|
listeners.add(cb);
|
|
165
188
|
if (pending.length > 0) {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import type { Confidence } from '@chestnutlabs/toolpath-core';
|
|
14
14
|
import type { GLRendererLike, RenderTargetCanvas } from '@chestnutlabs/gcode-renderer-three';
|
|
15
15
|
import { type ModelBackground, type PresentationView } from './model-renderer.js';
|
|
16
|
-
import { type ModelPlateSummary, type ModelScene } from './scene-model.js';
|
|
16
|
+
import { type ModelPlateSummary, type ModelScene, type RenderScope } from './scene-model.js';
|
|
17
17
|
import type { ModelLimits } from './limits.js';
|
|
18
18
|
/**
|
|
19
19
|
* A source model: STL bytes, 3MF bytes, or a pre-built `ModelScene`. This concrete union is the
|
|
@@ -45,6 +45,13 @@ export interface RenderModelStillOptions {
|
|
|
45
45
|
filamentPalette?: readonly (string | undefined)[];
|
|
46
46
|
/** Override the environment id folded into the cache key (default: the `three` revision). */
|
|
47
47
|
envId?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Render only a subset of a multi-plate / multi-object source (DD-030 D2) — e.g. `{ plateId: 3 }` to
|
|
50
|
+
* render just plate 3 of a project, framed to that plate. Omit to render the whole project (default).
|
|
51
|
+
* `{ plateId }` is meaningful only when the source declares plates (`plates: 'known'`); on a source
|
|
52
|
+
* without plate structure it matches nothing and renders empty (the honest result).
|
|
53
|
+
*/
|
|
54
|
+
renderScope?: RenderScope;
|
|
48
55
|
}
|
|
49
56
|
export interface RenderModelStillResult {
|
|
50
57
|
canvas: RenderTargetCanvas;
|
|
@@ -76,10 +83,5 @@ export interface RenderModelStillResult {
|
|
|
76
83
|
/** Stable identity for caching: `hash(source) + options + envId`. */
|
|
77
84
|
cacheKey: string;
|
|
78
85
|
}
|
|
79
|
-
/**
|
|
80
|
-
* Render one presentation still. Async because the 3MF path unzips with the container reader
|
|
81
|
-
* (`DecompressionStream`); the STL and pre-built-`ModelScene` paths resolve promptly. Mirrors the
|
|
82
|
-
* async `renderStill` on the toolpath side.
|
|
83
|
-
*/
|
|
84
86
|
export declare function renderModelStill(source: ModelSource, options: RenderModelStillOptions): Promise<RenderModelStillResult>;
|
|
85
87
|
//# sourceMappingURL=render-model-still.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-model-still.d.ts","sourceRoot":"","sources":["../src/render-model-still.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7F,OAAO,EAAiB,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEjG,OAAO,
|
|
1
|
+
{"version":3,"file":"render-model-still.d.ts","sourceRoot":"","sources":["../src/render-model-still.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7F,OAAO,EAAiB,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEjG,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;GAIG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAAA;CAAE,GAChD,UAAU,CAAC;AAEf,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mGAAmG;IACnG,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,qCAAqC;IACrC,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,cAAc,CAAC;IAChE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;OAIG;IACH,eAAe,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;IAClD,6FAA6F;IAC7F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,sGAAsG;IACtG,SAAS,EAAE,UAAU,CAAC;IACtB;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAkCD,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,sBAAsB,CAAC,CA+CjC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ModelRenderer } from './model-renderer.js';
|
|
2
2
|
import { isModelScene, resolveModelScene } from './loaders.js';
|
|
3
|
-
import { sceneInstanceCount } from './scene-model.js';
|
|
3
|
+
import { applyRenderScope, sceneInstanceCount } from './scene-model.js';
|
|
4
4
|
import { computeCacheKey } from './cache-key.js';
|
|
5
5
|
async function toScene(source, limits, filamentPalette) {
|
|
6
6
|
if (isModelScene(source)) {
|
|
@@ -18,13 +18,27 @@ async function toScene(source, limits, filamentPalette) {
|
|
|
18
18
|
* (`DecompressionStream`); the STL and pre-built-`ModelScene` paths resolve promptly. Mirrors the
|
|
19
19
|
* async `renderStill` on the toolpath side.
|
|
20
20
|
*/
|
|
21
|
+
/** Counter that makes an opaque `instanceFilter` scope's cache key unique (never a false cache hit). */
|
|
22
|
+
let scopeKeyCounter = 0;
|
|
23
|
+
/** A stable, serializable cache-key fragment for a render scope (DD-030 D2). */
|
|
24
|
+
function scopeCacheKey(scope) {
|
|
25
|
+
if (!scope)
|
|
26
|
+
return undefined;
|
|
27
|
+
if ('plateId' in scope)
|
|
28
|
+
return { p: scope.plateId };
|
|
29
|
+
if ('objectIds' in scope)
|
|
30
|
+
return { o: [...scope.objectIds].sort() };
|
|
31
|
+
return { fn: ++scopeKeyCounter }; // opaque predicate → non-cacheable, unique each call
|
|
32
|
+
}
|
|
21
33
|
export async function renderModelStill(source, options) {
|
|
22
34
|
const { canvas } = options;
|
|
23
35
|
const width = options.width ?? canvas.width;
|
|
24
36
|
const height = options.height ?? canvas.height;
|
|
25
37
|
const background = options.background ?? 'transparent';
|
|
26
38
|
const view = options.view ?? 'iso';
|
|
27
|
-
const { scene, sourceBytes } = await toScene(source, options.limits, options.filamentPalette);
|
|
39
|
+
const { scene: fullScene, sourceBytes } = await toScene(source, options.limits, options.filamentPalette);
|
|
40
|
+
// DD-030 D2: narrow to the requested plate/object subset (framing follows the filtered bounds).
|
|
41
|
+
const scene = options.renderScope ? applyRenderScope(fullScene, options.renderScope) : fullScene;
|
|
28
42
|
const renderer = new ModelRenderer({
|
|
29
43
|
canvas,
|
|
30
44
|
background,
|
|
@@ -35,7 +49,16 @@ export async function renderModelStill(source, options) {
|
|
|
35
49
|
renderer.resize(width, height);
|
|
36
50
|
renderer.setScene(scene);
|
|
37
51
|
renderer.render();
|
|
38
|
-
const optionsJson = JSON.stringify({
|
|
52
|
+
const optionsJson = JSON.stringify({
|
|
53
|
+
width,
|
|
54
|
+
height,
|
|
55
|
+
background,
|
|
56
|
+
view,
|
|
57
|
+
palette: options.filamentPalette,
|
|
58
|
+
// Fold the scope so plate-1 and plate-2 thumbnails key distinctly. An opaque `instanceFilter` can't
|
|
59
|
+
// be serialized — such a still is marked non-cacheable (consumers should not reuse it by key).
|
|
60
|
+
scope: scopeCacheKey(options.renderScope)
|
|
61
|
+
});
|
|
39
62
|
const cacheKey = computeCacheKey(sourceBytes, optionsJson, options.envId);
|
|
40
63
|
return {
|
|
41
64
|
canvas,
|
package/dist/scene-model.d.ts
CHANGED
|
@@ -118,6 +118,29 @@ export interface ModelScene {
|
|
|
118
118
|
plates: Confidence;
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* A render-scope selector (DD-030 D2): which objects/placements of a scene to render. Generic and
|
|
123
|
+
* vendor-neutral — a plate is one way to derive the subset. `{plateId}` is sugar over the placement's
|
|
124
|
+
* {@link ModelObject.plateIds} (meaningful only when `capabilities.plates === 'known'`; on a scene with
|
|
125
|
+
* no plate structure it matches nothing → an empty scene, the honest result of selecting a plate that
|
|
126
|
+
* isn't declared). `{objectIds}` and `{instanceFilter}` need no capability (ids are always known).
|
|
127
|
+
*/
|
|
128
|
+
export type RenderScope = {
|
|
129
|
+
objectIds: string[];
|
|
130
|
+
} | {
|
|
131
|
+
plateId: number;
|
|
132
|
+
} | {
|
|
133
|
+
instanceFilter: (objectId: string, placementIndex: number) => boolean;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Return a filtered copy of `scene` containing only the objects/placements the scope selects, with
|
|
137
|
+
* `bounds` recomputed from the kept placements (so a consumer frames just the selected plate/subset).
|
|
138
|
+
* Pure and three-free. Objects with no kept placement are dropped; an empty result (nothing matched) is
|
|
139
|
+
* a valid, honest scene — a `{plateId}` that matches nothing renders empty by design (gate on
|
|
140
|
+
* `capabilities.plates === 'known'`). `scene.plates`/`capabilities` are preserved (the source's declared
|
|
141
|
+
* structure is unchanged; only what is *rendered* is narrowed).
|
|
142
|
+
*/
|
|
143
|
+
export declare function applyRenderScope(scene: ModelScene, scope: RenderScope): ModelScene;
|
|
121
144
|
/** The identity transform (column-major), for single-object sources. */
|
|
122
145
|
export declare const IDENTITY_MAT4: Mat4;
|
|
123
146
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scene-model.d.ts","sourceRoot":"","sources":["../src/scene-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,0BAA0B;AAC1B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE3C,iGAAiG;AACjG,MAAM,MAAM,IAAI,GAAG,SAAS,MAAM,EAAE,CAAC;AAErC,4FAA4F;AAC5F,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,GAAG,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,wGAAwG;AACxG,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,SAAS,EAAE,YAAY,CAAC;IACxB,kFAAkF;IAClF,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,iEAAiE;IACjE,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,gGAAgG;AAChG,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AAED,wCAAwC;AACxC,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,QAAQ,EAAE,YAAY,CAAC;IACvB,iGAAiG;IACjG,SAAS,EAAE,IAAI,CAAC;IAChB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;IACnB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,uGAAuG;IACvG,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oHAAoH;IACpH,WAAW,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,uGAAuG;AACvG,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,MAAM,EAAE,WAAW,CAAC;IACpB;;;;;OAKG;IACH,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,0EAA0E;IAC1E,YAAY,EAAE;QACZ,iFAAiF;QACjF,SAAS,EAAE,UAAU,CAAC;QACtB,sFAAsF;QACtF,UAAU,EAAE,UAAU,CAAC;QACvB,+DAA+D;QAC/D,WAAW,EAAE,UAAU,CAAC;QACxB;4FACoF;QACpF,SAAS,EAAE,UAAU,CAAC;QACtB;gFACwE;QACxE,MAAM,EAAE,UAAU,CAAC;KACpB,CAAC;CACH;AAED,wEAAwE;AACxE,eAAO,MAAM,aAAa,EAAE,IAAuD,CAAC;AAEpF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAI5D"}
|
|
1
|
+
{"version":3,"file":"scene-model.d.ts","sourceRoot":"","sources":["../src/scene-model.ts"],"names":[],"mappings":"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"}
|
package/dist/scene-model.js
CHANGED
|
@@ -1,3 +1,87 @@
|
|
|
1
|
+
/** Local axis-aligned bounds of a geometry's positions. */
|
|
2
|
+
function geometryAABB(positions) {
|
|
3
|
+
const min = [Infinity, Infinity, Infinity];
|
|
4
|
+
const max = [-Infinity, -Infinity, -Infinity];
|
|
5
|
+
for (let i = 0; i + 2 < positions.length; i += 3) {
|
|
6
|
+
for (let a = 0; a < 3; a++) {
|
|
7
|
+
const v = positions[i + a];
|
|
8
|
+
if (v < min[a])
|
|
9
|
+
min[a] = v;
|
|
10
|
+
if (v > max[a])
|
|
11
|
+
max[a] = v;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return { min, max };
|
|
15
|
+
}
|
|
16
|
+
/** Transform a point by a column-major (three `Matrix4.elements`) affine Mat4. */
|
|
17
|
+
function applyMat4(m, x, y, z) {
|
|
18
|
+
return [
|
|
19
|
+
m[0] * x + m[4] * y + m[8] * z + m[12],
|
|
20
|
+
m[1] * x + m[5] * y + m[9] * z + m[13],
|
|
21
|
+
m[2] * x + m[6] * y + m[10] * z + m[14]
|
|
22
|
+
];
|
|
23
|
+
}
|
|
24
|
+
/** Union of the world AABBs of the given placements of an object's geometry, into `acc`. */
|
|
25
|
+
function accumulatePlacementBounds(geom, placements, acc) {
|
|
26
|
+
const { min: lmin, max: lmax } = geometryAABB(geom.positions);
|
|
27
|
+
if (lmin[0] > lmax[0])
|
|
28
|
+
return; // empty geometry
|
|
29
|
+
const mut = acc;
|
|
30
|
+
for (const m of placements) {
|
|
31
|
+
for (let cx = 0; cx < 2; cx++) {
|
|
32
|
+
for (let cy = 0; cy < 2; cy++) {
|
|
33
|
+
for (let cz = 0; cz < 2; cz++) {
|
|
34
|
+
const w = applyMat4(m, cx ? lmax[0] : lmin[0], cy ? lmax[1] : lmin[1], cz ? lmax[2] : lmin[2]);
|
|
35
|
+
for (let a = 0; a < 3; a++) {
|
|
36
|
+
if (w[a] < mut.min[a])
|
|
37
|
+
mut.min[a] = w[a];
|
|
38
|
+
if (w[a] > mut.max[a])
|
|
39
|
+
mut.max[a] = w[a];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Return a filtered copy of `scene` containing only the objects/placements the scope selects, with
|
|
48
|
+
* `bounds` recomputed from the kept placements (so a consumer frames just the selected plate/subset).
|
|
49
|
+
* Pure and three-free. Objects with no kept placement are dropped; an empty result (nothing matched) is
|
|
50
|
+
* a valid, honest scene — a `{plateId}` that matches nothing renders empty by design (gate on
|
|
51
|
+
* `capabilities.plates === 'known'`). `scene.plates`/`capabilities` are preserved (the source's declared
|
|
52
|
+
* structure is unchanged; only what is *rendered* is narrowed).
|
|
53
|
+
*/
|
|
54
|
+
export function applyRenderScope(scene, scope) {
|
|
55
|
+
const matches = (o, i) => {
|
|
56
|
+
if ('objectIds' in scope)
|
|
57
|
+
return scope.objectIds.includes(o.id);
|
|
58
|
+
if ('plateId' in scope)
|
|
59
|
+
return o.plateIds?.[i] === scope.plateId;
|
|
60
|
+
return scope.instanceFilter(o.id, i);
|
|
61
|
+
};
|
|
62
|
+
const objects = [];
|
|
63
|
+
const bounds = { min: [Infinity, Infinity, Infinity], max: [-Infinity, -Infinity, -Infinity] };
|
|
64
|
+
for (const o of scene.objects) {
|
|
65
|
+
const placements = o.instances ?? [o.transform];
|
|
66
|
+
const kept = [];
|
|
67
|
+
for (let i = 0; i < placements.length; i++)
|
|
68
|
+
if (matches(o, i))
|
|
69
|
+
kept.push(i);
|
|
70
|
+
if (kept.length === 0)
|
|
71
|
+
continue;
|
|
72
|
+
const keptPlacements = kept.map((i) => placements[i]);
|
|
73
|
+
const next = {
|
|
74
|
+
...o,
|
|
75
|
+
transform: keptPlacements[0],
|
|
76
|
+
instances: keptPlacements.length > 1 ? keptPlacements.slice() : undefined,
|
|
77
|
+
plateIds: o.plateIds ? kept.map((i) => o.plateIds[i]) : undefined
|
|
78
|
+
};
|
|
79
|
+
objects.push(next);
|
|
80
|
+
accumulatePlacementBounds(o.geometry, keptPlacements, bounds);
|
|
81
|
+
}
|
|
82
|
+
const finalBounds = objects.length === 0 ? { min: [0, 0, 0], max: [0, 0, 0] } : bounds;
|
|
83
|
+
return { ...scene, objects, bounds: finalBounds };
|
|
84
|
+
}
|
|
1
85
|
/** The identity transform (column-major), for single-object sources. */
|
|
2
86
|
export const IDENTITY_MAT4 = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
|
3
87
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chestnutlabs/gcode-model-renderer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Three.js presentation renderer for source models (STL/3MF) — clean thumbnails/cards, distinct from toolpath inspection (DD-018).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"3d-printing",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"test": "vitest run"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@chestnutlabs/gcode-containers": "0.
|
|
55
|
-
"@chestnutlabs/gcode-renderer-three": "0.
|
|
56
|
-
"@chestnutlabs/toolpath-core": "0.
|
|
54
|
+
"@chestnutlabs/gcode-containers": "0.18.0",
|
|
55
|
+
"@chestnutlabs/gcode-renderer-three": "0.18.0",
|
|
56
|
+
"@chestnutlabs/toolpath-core": "0.18.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/three": "0.178.0"
|