@chestnutlabs/gcode-preview-vue 0.19.0 → 0.20.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/README.md CHANGED
@@ -34,23 +34,32 @@ const file = shallowRef<File | null>(null);
34
34
  </template>
35
35
  ```
36
36
 
37
- That is a complete viewer. The full surface is optional props with sensible defaults:
37
+ That is a complete viewer. The full surface is ~24 optional props with sensible defaults — the
38
+ frequently reached-for ones:
38
39
 
39
40
  | Prop | Purpose |
40
41
  |---|---|
41
42
  | `source` | `Uint8Array \| ArrayBuffer \| File` — changing it re-parses |
42
43
  | `parse-options` | wire options (limits, dialects, containers, plate selection) |
44
+ | `renderer` | `'3d'` (Three.js) or `'2d'` (Canvas fallback) — construction-time |
43
45
  | `build-volume` | consumer-configured plate — wins over file-discovered geometry; discovery is then emitted, not applied |
44
- | `quality` | `'auto' \| 'lines' \| 'tubes'` |
45
- | `color-mode` | single / by-tool / by-feature (feature coloring is capability-gated — listen for `error`) |
46
- | `layer-range` / `scrub` / `show-travel` | clipping controls |
46
+ | `quality` / `quality-mode` | `'auto' \| 'lines' \| 'tubes'`; render-quality budget (`'full' \| 'adaptive' \| 'fast'`) |
47
+ | `color-mode` | single / by-tool / by-feature (feature coloring is capability-gated — check `state.availableColorModes` or listen for `error`) |
48
+ | `theme` | viewer theme (background, bed, toolpath palette) |
49
+ | `camera-mode` / `view` / `camera-state` / `frame-content` | perspective/orthographic, named view, saved camera, framing target |
50
+ | `layer-range` / `scrub` / `scrub-time` | clipping / time-based scrub controls |
51
+ | `show-travel` / `show-wipe` / `show-retractions` / `show-volume-cage` | move-class and overlay visibility toggles |
52
+ | `hidden-feature-roles` | hide feature roles (e.g. Skirt, Brim) — declarative form of `controls.setFeatureRoleVisible`; gate on `capabilities.featureRoles` |
47
53
  | `progress` | a DD-006 `ProgressObservation` — drives the honest live-progress overlay (marker for byte-exact, uncertainty band for approximate, gray when stale) |
48
54
  | `create-worker` | worker factory escape hatch (see below) |
49
55
 
50
- Emits: `ready`, `parse-error`, `parse-cancelled`, `parse-progress`, `build-complete`,
51
- `quality-fallback`, `machine-geometry-mismatch`, `machine-geometry-discovered`,
56
+ Emits (13): `ready`, `camera-change`, `parse-error`, `parse-cancelled`, `parse-progress`, `stage`,
57
+ `build-complete`, `quality-fallback`, `machine-geometry-mismatch`, `machine-geometry-discovered`,
52
58
  `progress-presentation-changed`, `disclosure`, `error`. The underlying handle is exposed for
53
- template refs (`ref.preview`).
59
+ template refs (`ref.preview`); its `controls` reach the imperative surface — `getRenderStats()`
60
+ (render diagnostics), `pickSegment(ndcX, ndcY, threshold?)` (source-mapping / picking),
61
+ `isColorModeAvailable(mode)`, and `capture(opts?)` (image `Blob`, also `handle.capture`). The handle
62
+ `state` carries capability-aware UI data (`availableColorModes`, `hasRetractions`, `hasColorChanges`).
54
63
 
55
64
  ## Headless composable (build your own controls)
56
65
 
@@ -89,6 +98,48 @@ Linked-workspace development note: Vite consumers using `file:` links should add
89
98
  `@chestnutlabs/*` package the worker pulls in to `optimizeDeps.exclude` (installed tarballs/registry
90
99
  packages need no configuration).
91
100
 
101
+ ## Model viewing (Prepare side)
102
+
103
+ The `/model` subpath ships a `<ModelViewer>` — the **Prepare**-side counterpart to `<GcodePreview>`.
104
+ Where `<GcodePreview>` draws the toolpath (how a print runs), `<ModelViewer>` draws the **source
105
+ model** (an `.stl` / `.3mf` mesh) — the object before slicing.
106
+
107
+ ```vue
108
+ <script setup lang="ts">
109
+ import { ModelViewer } from '@chestnutlabs/gcode-preview-vue/model';
110
+
111
+ const source = { kind: '3mf' as const, bytes };
112
+ </script>
113
+
114
+ <template>
115
+ <div style="height: 70vh">
116
+ <ModelViewer :source="source" @ready="(info) => console.log(info.objectCount, info.materials)" />
117
+ </div>
118
+ </template>
119
+ ```
120
+
121
+ `@ready` carries the honest material-colour tier: `info.materials` is `'known'` / `'approximated'`
122
+ when the file declared colours the render used, and `'unavailable'` when it declared none (a neutral
123
+ default, never faked). The kebab props (`:view`, `:background`, `:render-scope`, …), matching emits,
124
+ and the `useModelViewer` composable mirror the toolpath component. See
125
+ [`docs/manual/adapters.md`](../../docs/manual/adapters.md) "Two viewers: Preview and Prepare" for the
126
+ cross-adapter tour, and `tools/example-vue/model.html` for a runnable minimal page.
127
+
128
+ ## Examples
129
+
130
+ `tools/example-vue` in the repository is a Vite app with two tiers, both driving this published
131
+ package (no raw renderer or parser imports):
132
+
133
+ - **`minimal.html`** — the smallest real integration: `<GcodePreview :source>` plus a fixture picker
134
+ and a layer slider. One short component to copy when getting started.
135
+ - **`showcase.html`** — the full declarative surface: capability-gated color modes (a mode greys out
136
+ with a plain-language reason when the file can't support it), declarative `:hidden-feature-roles`,
137
+ camera, and `getRenderStats()`/`pickSegment()` diagnostics through the component ref's handle
138
+ (`viewer.preview.controls`), whose `state` mirror is directly reactive in Vue.
139
+
140
+ Run it with `npm install --prefix tools/example-vue && npm run dev --prefix tools/example-vue`
141
+ (port 5203).
142
+
92
143
  ## Capability honesty
93
144
 
94
145
  Everything the engine reports as `inferred`/`approximated`/`unavailable` stays that way at this
@@ -12,7 +12,7 @@
12
12
  import { type PropType } from 'vue';
13
13
  import type { BuildVolumeDef, CameraMode, CameraState, CameraView, ColorMode, QualityMode, ProgressivePreview, PreparationStage, QualityPolicy, Theme, TubeOptions } from '@chestnutlabs/gcode-renderer-three';
14
14
  import type { Confidence, DialectMetadata, Warning } from '@chestnutlabs/toolpath-core';
15
- import type { MachineGeometry, ProgressObservation } from '@chestnutlabs/toolpath-core';
15
+ import type { FeatureRoleValue, MachineGeometry, ProgressObservation } from '@chestnutlabs/toolpath-core';
16
16
  import type { WireParseOptions, WorkerLike } from '@chestnutlabs/gcode-parser';
17
17
  import { type RendererMode, type UseGcodePreviewOptions } from './use-gcode-preview.js';
18
18
  export type GcodePreviewSource = Uint8Array | ArrayBuffer | File | null;
@@ -126,6 +126,12 @@ export declare const GcodePreview: import("vue").DefineComponent<import("vue").E
126
126
  type: BooleanConstructor;
127
127
  default: boolean;
128
128
  };
129
+ /** DD-031 G3: feature roles to hide (e.g. `[FeatureRole.Skirt, FeatureRole.Brim]` to declutter a
130
+ * part). Declarative form of `controls.setFeatureRoleVisible`; gate on `capabilities.featureRoles`. */
131
+ hiddenFeatureRoles: {
132
+ type: PropType<FeatureRoleValue[]>;
133
+ default: undefined;
134
+ };
129
135
  /** DD-006 live progress observation; null hides the overlay. */
130
136
  progress: {
131
137
  type: PropType<ProgressObservation | null>;
@@ -301,6 +307,12 @@ export declare const GcodePreview: import("vue").DefineComponent<import("vue").E
301
307
  type: BooleanConstructor;
302
308
  default: boolean;
303
309
  };
310
+ /** DD-031 G3: feature roles to hide (e.g. `[FeatureRole.Skirt, FeatureRole.Brim]` to declutter a
311
+ * part). Declarative form of `controls.setFeatureRoleVisible`; gate on `capabilities.featureRoles`. */
312
+ hiddenFeatureRoles: {
313
+ type: PropType<FeatureRoleValue[]>;
314
+ default: undefined;
315
+ };
304
316
  /** DD-006 live progress observation; null hides the overlay. */
305
317
  progress: {
306
318
  type: PropType<ProgressObservation | null>;
@@ -388,6 +400,7 @@ export declare const GcodePreview: import("vue").DefineComponent<import("vue").E
388
400
  showWipe: boolean;
389
401
  showRetractions: boolean;
390
402
  showVolumeCage: boolean;
403
+ hiddenFeatureRoles: FeatureRoleValue[];
391
404
  progress: ProgressObservation | null;
392
405
  createWorker: () => WorkerLike;
393
406
  rendererOptions: Omit<{
@@ -1 +1 @@
1
- {"version":3,"file":"gcode-preview-component.d.ts","sourceRoot":"","sources":["../src/gcode-preview-component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gcode-preview-component.d.ts","sourceRoot":"","sources":["../src/gcode-preview-component.ts"],"names":[],"mappings":"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"}
@@ -54,6 +54,9 @@ export const GcodePreview = defineComponent({
54
54
  showRetractions: { type: Boolean, default: false },
55
55
  /** #306/#6: show the build-volume wireframe cage (independent of the bed/plate). Default true. */
56
56
  showVolumeCage: { type: Boolean, default: true },
57
+ /** DD-031 G3: feature roles to hide (e.g. `[FeatureRole.Skirt, FeatureRole.Brim]` to declutter a
58
+ * part). Declarative form of `controls.setFeatureRoleVisible`; gate on `capabilities.featureRoles`. */
59
+ hiddenFeatureRoles: { type: Array, default: undefined },
57
60
  /** DD-006 live progress observation; null hides the overlay. */
58
61
  progress: { type: Object, default: null },
59
62
  /** Worker factory escape hatch (DD-005 slim/custom entries; D2). Factory form only —
@@ -221,6 +224,19 @@ export const GcodePreview = defineComponent({
221
224
  if (volume !== undefined)
222
225
  preview.controls.setBuildVolume(volume);
223
226
  });
227
+ // Feature-role visibility (DD-031 G3): diff prev→next so we only toggle roles this prop owns,
228
+ // leaving any role hidden imperatively elsewhere untouched.
229
+ let prevHiddenRoles = [];
230
+ watch(() => props.hiddenFeatureRoles, (roles) => {
231
+ const next = roles ?? [];
232
+ for (const role of prevHiddenRoles)
233
+ if (!next.includes(role))
234
+ preview.controls.setFeatureRoleVisible(role, true);
235
+ for (const role of next)
236
+ if (!prevHiddenRoles.includes(role))
237
+ preview.controls.setFeatureRoleVisible(role, false);
238
+ prevHiddenRoles = [...next];
239
+ }, { immediate: true });
224
240
  watch(() => props.progress, (obs) => {
225
241
  if (obs === null)
226
242
  preview.clearProgress();
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @chestnutlabs/gcode-preview-vue/model — the Vue integration for interactive **source-model** viewing
3
+ * (STL / 3MF), the Prepare-side counterpart to the toolpath `<GcodePreview>` (DD-031). `useModelViewer`
4
+ * composable + `<ModelViewer>` component, both thin reactivity bridges over `createModelPreviewController`.
5
+ */
6
+ export { useModelViewer } from './use-model-viewer.js';
7
+ export type { ModelViewerHandle, UseModelViewerOptions, ModelPreviewControls, ModelPreviewState, ModelViewerEvent, ModelReadyInfo } from './use-model-viewer.js';
8
+ export { ModelViewer } from './model-viewer-component.js';
9
+ export type { ModelViewerSource } from './model-viewer-component.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,YAAY,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @chestnutlabs/gcode-preview-vue/model — the Vue integration for interactive **source-model** viewing
3
+ * (STL / 3MF), the Prepare-side counterpart to the toolpath `<GcodePreview>` (DD-031). `useModelViewer`
4
+ * composable + `<ModelViewer>` component, both thin reactivity bridges over `createModelPreviewController`.
5
+ */
6
+ export { useModelViewer } from './use-model-viewer.js';
7
+ export { ModelViewer } from './model-viewer-component.js';
@@ -0,0 +1,175 @@
1
+ /**
2
+ * <ModelViewer> — the ready-to-use Vue component for interactive source-model viewing (STL / 3MF),
3
+ * the Prepare-side counterpart to <GcodePreview> (DD-031). A SHELL over `useModelViewer`: every prop
4
+ * maps to a composable/controls call, every emit re-fires a controller event, and the handle is
5
+ * exposed via `defineExpose`. Render-function component (no SFC) — the template is a single <canvas>.
6
+ */
7
+ import { type PropType } from 'vue';
8
+ import type { CameraMode, CameraState, CameraView, GLRendererLike, InteractiveStageOptions, LoadProgress, RenderTargetCanvas } from '@chestnutlabs/gcode-renderer-three';
9
+ import type { ModelBackground, ModelLimits, ModelLoader, ModelReadyInfo, ModelSourceInput, PresentationView, RenderScope } from '@chestnutlabs/gcode-model-renderer';
10
+ export type ModelViewerSource = ModelSourceInput | null;
11
+ export declare const ModelViewer: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
12
+ /** The one required-in-practice prop: the source model. Changing it re-parses. */
13
+ source: {
14
+ type: PropType<ModelViewerSource>;
15
+ default: null;
16
+ };
17
+ /** Snap to a preset orientation (shared vocabulary with the toolpath camera). */
18
+ view: {
19
+ type: PropType<PresentationView | CameraView>;
20
+ default: undefined;
21
+ };
22
+ /** Restore a saved camera pose. Pair with `@camera-change` for two-way binding. */
23
+ cameraState: {
24
+ type: PropType<CameraState | null>;
25
+ default: undefined;
26
+ };
27
+ /** `'transparent'` (default) | CSS colour | `0xRRGGBB`. */
28
+ background: {
29
+ type: PropType<ModelBackground>;
30
+ default: undefined;
31
+ };
32
+ /** DD-020 interaction-aware quality; default `'auto'`. */
33
+ interactionQuality: {
34
+ type: PropType<"off" | "auto">;
35
+ default: undefined;
36
+ };
37
+ /** Initial camera projection; default `'perspective'`. */
38
+ cameraMode: {
39
+ type: PropType<CameraMode>;
40
+ default: undefined;
41
+ };
42
+ /** Render only a subset: `{ plateId }` / `{ objectIds }` / `{ instanceFilter }`; null = whole source. */
43
+ renderScope: {
44
+ type: PropType<RenderScope | null>;
45
+ default: undefined;
46
+ };
47
+ /** Source-model triangle / byte caps. */
48
+ limits: {
49
+ type: PropType<ModelLimits>;
50
+ default: undefined;
51
+ };
52
+ /** 3MF `paint_color` palette override (hex per 0-based slot). */
53
+ filamentPalette: {
54
+ type: PropType<readonly (string | undefined)[]>;
55
+ default: undefined;
56
+ };
57
+ /** Loader registry (open `kind`). Default: STL + 3MF. */
58
+ loaders: {
59
+ type: PropType<readonly ModelLoader[]>;
60
+ default: undefined;
61
+ };
62
+ /** Advanced/test: inject GL / orbit controls. */
63
+ createRenderer: {
64
+ type: PropType<(canvas: RenderTargetCanvas) => GLRendererLike>;
65
+ default: undefined;
66
+ };
67
+ createControls: {
68
+ type: PropType<NonNullable<InteractiveStageOptions["createControls"]>>;
69
+ default: undefined;
70
+ };
71
+ }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
72
+ [key: string]: any;
73
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
74
+ ready: (_info: ModelReadyInfo) => true;
75
+ 'camera-change': (_state: CameraState) => true;
76
+ error: (_e: {
77
+ code: string;
78
+ message: string;
79
+ }) => true;
80
+ 'renderer-unsupported': (_e: {
81
+ feature: string;
82
+ message: string;
83
+ }) => true;
84
+ 'context-lost': () => true;
85
+ 'context-restored': () => true;
86
+ progress: (_p: LoadProgress) => true;
87
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
88
+ /** The one required-in-practice prop: the source model. Changing it re-parses. */
89
+ source: {
90
+ type: PropType<ModelViewerSource>;
91
+ default: null;
92
+ };
93
+ /** Snap to a preset orientation (shared vocabulary with the toolpath camera). */
94
+ view: {
95
+ type: PropType<PresentationView | CameraView>;
96
+ default: undefined;
97
+ };
98
+ /** Restore a saved camera pose. Pair with `@camera-change` for two-way binding. */
99
+ cameraState: {
100
+ type: PropType<CameraState | null>;
101
+ default: undefined;
102
+ };
103
+ /** `'transparent'` (default) | CSS colour | `0xRRGGBB`. */
104
+ background: {
105
+ type: PropType<ModelBackground>;
106
+ default: undefined;
107
+ };
108
+ /** DD-020 interaction-aware quality; default `'auto'`. */
109
+ interactionQuality: {
110
+ type: PropType<"off" | "auto">;
111
+ default: undefined;
112
+ };
113
+ /** Initial camera projection; default `'perspective'`. */
114
+ cameraMode: {
115
+ type: PropType<CameraMode>;
116
+ default: undefined;
117
+ };
118
+ /** Render only a subset: `{ plateId }` / `{ objectIds }` / `{ instanceFilter }`; null = whole source. */
119
+ renderScope: {
120
+ type: PropType<RenderScope | null>;
121
+ default: undefined;
122
+ };
123
+ /** Source-model triangle / byte caps. */
124
+ limits: {
125
+ type: PropType<ModelLimits>;
126
+ default: undefined;
127
+ };
128
+ /** 3MF `paint_color` palette override (hex per 0-based slot). */
129
+ filamentPalette: {
130
+ type: PropType<readonly (string | undefined)[]>;
131
+ default: undefined;
132
+ };
133
+ /** Loader registry (open `kind`). Default: STL + 3MF. */
134
+ loaders: {
135
+ type: PropType<readonly ModelLoader[]>;
136
+ default: undefined;
137
+ };
138
+ /** Advanced/test: inject GL / orbit controls. */
139
+ createRenderer: {
140
+ type: PropType<(canvas: RenderTargetCanvas) => GLRendererLike>;
141
+ default: undefined;
142
+ };
143
+ createControls: {
144
+ type: PropType<NonNullable<InteractiveStageOptions["createControls"]>>;
145
+ default: undefined;
146
+ };
147
+ }>> & Readonly<{
148
+ onError?: ((_e: {
149
+ code: string;
150
+ message: string;
151
+ }) => any) | undefined;
152
+ onReady?: ((_info: ModelReadyInfo) => any) | undefined;
153
+ onProgress?: ((_p: LoadProgress) => any) | undefined;
154
+ "onCamera-change"?: ((_state: CameraState) => any) | undefined;
155
+ "onRenderer-unsupported"?: ((_e: {
156
+ feature: string;
157
+ message: string;
158
+ }) => any) | undefined;
159
+ "onContext-lost"?: (() => any) | undefined;
160
+ "onContext-restored"?: (() => any) | undefined;
161
+ }>, {
162
+ source: ModelViewerSource;
163
+ cameraMode: CameraMode;
164
+ interactionQuality: "auto" | "off";
165
+ createRenderer: (canvas: RenderTargetCanvas) => GLRendererLike;
166
+ view: CameraView;
167
+ cameraState: CameraState | null;
168
+ createControls: (camera: import("three").PerspectiveCamera | import("three").OrthographicCamera, domElement: HTMLElement) => import("@chestnutlabs/gcode-renderer-three").ControlsLike;
169
+ background: ModelBackground;
170
+ renderScope: RenderScope | null;
171
+ limits: ModelLimits;
172
+ filamentPalette: readonly (string | undefined)[];
173
+ loaders: readonly ModelLoader[];
174
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
175
+ //# sourceMappingURL=model-viewer-component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-viewer-component.d.ts","sourceRoot":"","sources":["../../src/model/model-viewer-component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAkC,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AACpE,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,UAAU,EACV,cAAc,EACd,uBAAuB,EACvB,YAAY,EACZ,kBAAkB,EACnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,EACZ,MAAM,oCAAoC,CAAC;AAG5C,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,GAAG,IAAI,CAAC;AAExD,eAAO,MAAM,WAAW;IAGpB,kFAAkF;;cAC7B,QAAQ,CAAC,iBAAiB,CAAC;;;IAChF,iFAAiF;;cACzD,QAAQ,CAAC,gBAAgB,GAAG,UAAU,CAAC;;;IAC/D,mFAAmF;;cACpD,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC;;;IAC3D,2DAA2D;;cACnB,QAAQ,CAAC,eAAe,CAAC;;;IACjE,0DAA0D;;cACpB,QAAQ,CAAC,KAAK,GAAG,MAAM,CAAC;;;IAC9D,0DAA0D;;cAC5B,QAAQ,CAAC,UAAU,CAAC;;;IAClD,yGAAyG;;cAC1E,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC;;;IAC3D,yCAAyC;;cACf,QAAQ,CAAC,WAAW,CAAC;;;IAC/C,iEAAiE;;cAC/B,QAAQ,CAAC,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;;;IAC3E,yDAAyD;;cAC/B,QAAQ,CAAC,SAAS,WAAW,EAAE,CAAC;;;IAC1D,iDAAiD;;cAE7B,QAAQ,CAAC,CAAC,MAAM,EAAE,kBAAkB,KAAK,cAAc,CAAC;;;;cAIxD,QAAQ,CAAC,WAAW,CAAC,uBAAuB,CAAC,gBAAgB,CAAC,CAAC,CAAC;;;;;;mBAMrE,cAAc;8BACH,WAAW;gBACzB;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;iCAChB;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;;;mBAGlD,YAAY;;IAtC3B,kFAAkF;;cAC7B,QAAQ,CAAC,iBAAiB,CAAC;;;IAChF,iFAAiF;;cACzD,QAAQ,CAAC,gBAAgB,GAAG,UAAU,CAAC;;;IAC/D,mFAAmF;;cACpD,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC;;;IAC3D,2DAA2D;;cACnB,QAAQ,CAAC,eAAe,CAAC;;;IACjE,0DAA0D;;cACpB,QAAQ,CAAC,KAAK,GAAG,MAAM,CAAC;;;IAC9D,0DAA0D;;cAC5B,QAAQ,CAAC,UAAU,CAAC;;;IAClD,yGAAyG;;cAC1E,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC;;;IAC3D,yCAAyC;;cACf,QAAQ,CAAC,WAAW,CAAC;;;IAC/C,iEAAiE;;cAC/B,QAAQ,CAAC,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;;;IAC3E,yDAAyD;;cAC/B,QAAQ,CAAC,SAAS,WAAW,EAAE,CAAC;;;IAC1D,iDAAiD;;cAE7B,QAAQ,CAAC,CAAC,MAAM,EAAE,kBAAkB,KAAK,cAAc,CAAC;;;;cAIxD,QAAQ,CAAC,WAAW,CAAC,uBAAuB,CAAC,gBAAgB,CAAC,CAAC,CAAC;;;;;cAQhE,MAAM;iBAAW,MAAM;;;;;;iBACH,MAAM;iBAAW,MAAM;;;;;;;;6BAbzB,kBAAkB,KAAK,cAAc;;;;;;;;;4EAiH7E,CAAC"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * <ModelViewer> — the ready-to-use Vue component for interactive source-model viewing (STL / 3MF),
3
+ * the Prepare-side counterpart to <GcodePreview> (DD-031). A SHELL over `useModelViewer`: every prop
4
+ * maps to a composable/controls call, every emit re-fires a controller event, and the handle is
5
+ * exposed via `defineExpose`. Render-function component (no SFC) — the template is a single <canvas>.
6
+ */
7
+ import { defineComponent, h, ref, watch } from 'vue';
8
+ import { useModelViewer } from './use-model-viewer.js';
9
+ export const ModelViewer = defineComponent({
10
+ name: 'ModelViewer',
11
+ props: {
12
+ /** The one required-in-practice prop: the source model. Changing it re-parses. */
13
+ source: { type: [Object, Uint8Array, ArrayBuffer], default: null },
14
+ /** Snap to a preset orientation (shared vocabulary with the toolpath camera). */
15
+ view: { type: String, default: undefined },
16
+ /** Restore a saved camera pose. Pair with `@camera-change` for two-way binding. */
17
+ cameraState: { type: Object, default: undefined },
18
+ /** `'transparent'` (default) | CSS colour | `0xRRGGBB`. */
19
+ background: { type: [String, Number], default: undefined },
20
+ /** DD-020 interaction-aware quality; default `'auto'`. */
21
+ interactionQuality: { type: String, default: undefined },
22
+ /** Initial camera projection; default `'perspective'`. */
23
+ cameraMode: { type: String, default: undefined },
24
+ /** Render only a subset: `{ plateId }` / `{ objectIds }` / `{ instanceFilter }`; null = whole source. */
25
+ renderScope: { type: Object, default: undefined },
26
+ /** Source-model triangle / byte caps. */
27
+ limits: { type: Object, default: undefined },
28
+ /** 3MF `paint_color` palette override (hex per 0-based slot). */
29
+ filamentPalette: { type: Array, default: undefined },
30
+ /** Loader registry (open `kind`). Default: STL + 3MF. */
31
+ loaders: { type: Array, default: undefined },
32
+ /** Advanced/test: inject GL / orbit controls. */
33
+ createRenderer: {
34
+ type: Function,
35
+ default: undefined
36
+ },
37
+ createControls: {
38
+ type: Function,
39
+ default: undefined
40
+ }
41
+ },
42
+ emits: {
43
+ /* eslint-disable @typescript-eslint/no-unused-vars -- emit validators document payloads */
44
+ ready: (_info) => true,
45
+ 'camera-change': (_state) => true,
46
+ error: (_e) => true,
47
+ 'renderer-unsupported': (_e) => true,
48
+ 'context-lost': () => true,
49
+ 'context-restored': () => true,
50
+ progress: (_p) => true
51
+ /* eslint-enable @typescript-eslint/no-unused-vars */
52
+ },
53
+ setup(props, { emit, expose }) {
54
+ const viewer = useModelViewer({
55
+ ...(props.background !== undefined ? { background: props.background } : {}),
56
+ ...(props.interactionQuality !== undefined ? { interactionQuality: props.interactionQuality } : {}),
57
+ ...(props.cameraMode !== undefined ? { cameraMode: props.cameraMode } : {}),
58
+ ...(props.limits !== undefined ? { limits: props.limits } : {}),
59
+ ...(props.filamentPalette !== undefined ? { filamentPalette: props.filamentPalette } : {}),
60
+ ...(props.loaders !== undefined ? { loaders: props.loaders } : {}),
61
+ ...(props.renderScope != null ? { renderScope: props.renderScope } : {}),
62
+ ...(props.createRenderer !== undefined ? { createRenderer: props.createRenderer } : {}),
63
+ ...(props.createControls !== undefined ? { createControls: props.createControls } : {}),
64
+ onProgress: (p) => emit('progress', p)
65
+ });
66
+ viewer.onEvent((e) => {
67
+ switch (e.type) {
68
+ case 'ready':
69
+ emit('ready', e.info);
70
+ break;
71
+ case 'camera-changed':
72
+ emit('camera-change', e.state);
73
+ break;
74
+ case 'error':
75
+ emit('error', { code: e.code, message: e.message });
76
+ break;
77
+ case 'renderer-unsupported':
78
+ emit('renderer-unsupported', { feature: e.feature, message: e.message });
79
+ break;
80
+ case 'context-lost':
81
+ emit('context-lost');
82
+ break;
83
+ case 'context-restored':
84
+ emit('context-restored');
85
+ break;
86
+ default:
87
+ break;
88
+ }
89
+ });
90
+ // Runtime-only props apply immediately on mount (Vue's watch is change-only by default).
91
+ watch(() => props.source, (source) => {
92
+ if (source !== null && source !== undefined)
93
+ void viewer.controls.setSource(source);
94
+ }, { immediate: true });
95
+ watch(() => props.view, (view) => {
96
+ if (view !== undefined)
97
+ viewer.controls.setView(view);
98
+ }, { immediate: true });
99
+ watch(() => props.cameraState, (state) => {
100
+ if (state !== undefined && state !== null)
101
+ viewer.controls.setCameraState(state);
102
+ }, { immediate: true });
103
+ watch(() => props.background, (bg) => {
104
+ if (bg !== undefined)
105
+ viewer.controls.setBackground(bg);
106
+ });
107
+ watch(() => props.interactionQuality, (mode) => {
108
+ if (mode !== undefined)
109
+ viewer.controls.setInteractionQuality(mode);
110
+ });
111
+ watch(() => props.renderScope, (scope) => {
112
+ if (scope !== undefined)
113
+ viewer.controls.setRenderScope(scope);
114
+ });
115
+ expose({ viewer });
116
+ const canvasEl = ref(null);
117
+ watch(canvasEl, (el) => {
118
+ viewer.canvasRef.value = el;
119
+ });
120
+ return () => h('canvas', {
121
+ ref: canvasEl,
122
+ style: { width: '100%', height: '100%', display: 'block', touchAction: 'none' },
123
+ tabindex: '0',
124
+ 'aria-label': '3D source-model preview'
125
+ });
126
+ }
127
+ });
@@ -0,0 +1,28 @@
1
+ /**
2
+ * useModelViewer — the Vue reactivity bridge for interactive **source-model** viewing (the Prepare
3
+ * side), the analogue of `useGcodePreview` for the toolpath/Preview side (DD-031). Owns only the
4
+ * Vue-isms: a canvas template ref, a shallow-reactive state mirror fed by controller snapshots, and
5
+ * scope-tied disposal. The engine/state/contracts live in `@chestnutlabs/gcode-model-renderer` and are
6
+ * re-exported, never redeclared (the D1 drift firewall).
7
+ */
8
+ import { type Ref } from 'vue';
9
+ import { type ModelPreviewControllerOptions, type ModelPreviewControls, type ModelPreviewState, type ModelViewer, type ModelViewerEvent, type ModelReadyInfo } from '@chestnutlabs/gcode-model-renderer';
10
+ import type { CaptureOptions } from '@chestnutlabs/gcode-renderer-three';
11
+ export type { ModelPreviewControls, ModelPreviewState, ModelViewerEvent, ModelReadyInfo };
12
+ /** Vue-facing options — identical to the controller's (the alias is the public name). */
13
+ export type UseModelViewerOptions = ModelPreviewControllerOptions;
14
+ export interface ModelViewerHandle {
15
+ /** Bind to a <canvas> template ref; rebinding disposes and rebuilds safely. */
16
+ canvasRef: Ref<HTMLCanvasElement | null>;
17
+ setSource: ModelPreviewControls['setSource'];
18
+ capture(opts?: CaptureOptions): Promise<Blob>;
19
+ state: Readonly<ModelPreviewState>;
20
+ controls: ModelPreviewControls;
21
+ raw: {
22
+ viewer: () => ModelViewer | null;
23
+ };
24
+ onEvent(cb: (e: ModelViewerEvent) => void): () => void;
25
+ dispose(): void;
26
+ }
27
+ export declare function useModelViewer(options?: UseModelViewerOptions): ModelViewerHandle;
28
+ //# sourceMappingURL=use-model-viewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-model-viewer.d.ts","sourceRoot":"","sources":["../../src/model/use-model-viewer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAA0E,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AACvG,OAAO,EAEL,KAAK,6BAA6B,EAClC,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACpB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,cAAc,EAAE,CAAC;AAC1F,yFAAyF;AACzF,MAAM,MAAM,qBAAqB,GAAG,6BAA6B,CAAC;AAElE,MAAM,WAAW,iBAAiB;IAChC,+EAA+E;IAC/E,SAAS,EAAE,GAAG,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACzC,SAAS,EAAE,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,KAAK,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IACnC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,WAAW,GAAG,IAAI,CAAA;KAAE,CAAC;IAC1C,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACvD,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,iBAAiB,CA2BrF"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * useModelViewer — the Vue reactivity bridge for interactive **source-model** viewing (the Prepare
3
+ * side), the analogue of `useGcodePreview` for the toolpath/Preview side (DD-031). Owns only the
4
+ * Vue-isms: a canvas template ref, a shallow-reactive state mirror fed by controller snapshots, and
5
+ * scope-tied disposal. The engine/state/contracts live in `@chestnutlabs/gcode-model-renderer` and are
6
+ * re-exported, never redeclared (the D1 drift firewall).
7
+ */
8
+ import { getCurrentScope, onScopeDispose, readonly, ref, shallowReactive, watch } from 'vue';
9
+ import { createModelPreviewController } from '@chestnutlabs/gcode-model-renderer';
10
+ export function useModelViewer(options = {}) {
11
+ const controller = createModelPreviewController(options);
12
+ const state = shallowReactive({ ...controller.getState() });
13
+ const offState = controller.onStateChange((snap) => {
14
+ Object.assign(state, snap);
15
+ });
16
+ const canvasRef = ref(null);
17
+ watch(canvasRef, (canvas) => controller.bindCanvas(canvas));
18
+ function dispose() {
19
+ offState();
20
+ controller.dispose();
21
+ }
22
+ if (getCurrentScope() !== undefined)
23
+ onScopeDispose(dispose);
24
+ return {
25
+ canvasRef,
26
+ setSource: controller.controls.setSource,
27
+ capture: controller.controls.capture,
28
+ state: readonly(state),
29
+ controls: controller.controls,
30
+ raw: controller.raw,
31
+ onEvent: controller.onEvent,
32
+ dispose
33
+ };
34
+ }
@@ -10,7 +10,7 @@
10
10
  import { type Ref } from 'vue';
11
11
  import type { GcodeParseSession, WireParseOptions } from '@chestnutlabs/gcode-parser';
12
12
  import type { MappedProgress, ProgressObservation } from '@chestnutlabs/toolpath-core';
13
- import { type GcodePreviewControls, type GcodePreviewState, type ParseOutcome, type PreviewControllerOptions, type PreviewEvent, type PreviewRenderer } from '@chestnutlabs/gcode-preview-core';
13
+ import { type CaptureOptions, type GcodePreviewControls, type GcodePreviewState, type ParseOutcome, type PreviewControllerOptions, type PreviewEvent, type PreviewRenderer } from '@chestnutlabs/gcode-preview-core';
14
14
  export type { GcodePreviewControls, GcodePreviewState, ParseOutcome, PreviewEvent, PreviewRenderer, RendererMode } from '@chestnutlabs/gcode-preview-core';
15
15
  /** Vue-facing options — identical to the controller's (the alias is the public name). */
16
16
  export type UseGcodePreviewOptions = PreviewControllerOptions;
@@ -24,6 +24,9 @@ export interface GcodePreviewHandle {
24
24
  /** Recompute staleness (DD-006 §4.4.3) — call at ~1 Hz while telemetry may go quiet. */
25
25
  tickProgress(nowMs: number): MappedProgress | null;
26
26
  clearProgress(): void;
27
+ /** Capture the current view as an image `Blob` (DD-030 D1, DD-031 G5) — handle-level parity with the
28
+ * Web Component's `capture()`. Also reachable as `controls.capture`. Rejects on the 2D renderer. */
29
+ capture(opts?: CaptureOptions): Promise<Blob>;
27
30
  state: Readonly<GcodePreviewState>;
28
31
  controls: GcodePreviewControls;
29
32
  /** Escape hatches — the neutral objects themselves (advanced use; not reactive). */
@@ -1 +1 @@
1
- {"version":3,"file":"use-gcode-preview.d.ts","sourceRoot":"","sources":["../src/use-gcode-preview.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAA0E,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AACvG,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvF,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EACjB,KAAK,eAAe,EACrB,MAAM,kCAAkC,CAAC;AAG1C,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,YAAY,EACb,MAAM,kCAAkC,CAAC;AAE1C,yFAAyF;AACzF,MAAM,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,SAAS,EAAE,GAAG,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACzC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9F,MAAM,IAAI,IAAI,CAAC;IACf,yFAAyF;IACzF,eAAe,CAAC,GAAG,EAAE,mBAAmB,GAAG,cAAc,GAAG,IAAI,CAAC;IACjE,wFAAwF;IACxF,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAAC;IACnD,aAAa,IAAI,IAAI,CAAC;IACtB,KAAK,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IACnC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,oFAAoF;IACpF,GAAG,EAAE;QAAE,OAAO,EAAE,iBAAiB,CAAC;QAAC,QAAQ,EAAE,MAAM,eAAe,GAAG,IAAI,CAAA;KAAE,CAAC;IAC5E,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACnD,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,kBAAkB,CAiCxF"}
1
+ {"version":3,"file":"use-gcode-preview.d.ts","sourceRoot":"","sources":["../src/use-gcode-preview.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAA0E,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AACvG,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvF,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EACjB,KAAK,eAAe,EACrB,MAAM,kCAAkC,CAAC;AAG1C,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,YAAY,EACb,MAAM,kCAAkC,CAAC;AAE1C,yFAAyF;AACzF,MAAM,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,SAAS,EAAE,GAAG,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACzC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9F,MAAM,IAAI,IAAI,CAAC;IACf,yFAAyF;IACzF,eAAe,CAAC,GAAG,EAAE,mBAAmB,GAAG,cAAc,GAAG,IAAI,CAAC;IACjE,wFAAwF;IACxF,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAAC;IACnD,aAAa,IAAI,IAAI,CAAC;IACtB;yGACqG;IACrG,OAAO,CAAC,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,KAAK,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IACnC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,oFAAoF;IACpF,GAAG,EAAE;QAAE,OAAO,EAAE,iBAAiB,CAAC;QAAC,QAAQ,EAAE,MAAM,eAAe,GAAG,IAAI,CAAA;KAAE,CAAC;IAC5E,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACnD,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,kBAAkB,CAkCxF"}
@@ -33,6 +33,7 @@ export function useGcodePreview(options = {}) {
33
33
  observeProgress: controller.observeProgress,
34
34
  tickProgress: controller.tickProgress,
35
35
  clearProgress: controller.clearProgress,
36
+ capture: controller.controls.capture,
36
37
  state: readonly(state),
37
38
  controls: controller.controls,
38
39
  raw: controller.raw,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chestnutlabs/gcode-preview-vue",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "Thin Vue 3 integration for the Chestnut Labs G-code viewer (DD-007): useGcodePreview composable + GcodePreview component over the framework-neutral parser/renderer/progress packages.",
5
5
  "keywords": [
6
6
  "gcode",
@@ -36,6 +36,10 @@
36
36
  ".": {
37
37
  "types": "./dist/index.d.ts",
38
38
  "import": "./dist/index.js"
39
+ },
40
+ "./model": {
41
+ "types": "./dist/model/index.d.ts",
42
+ "import": "./dist/model/index.js"
39
43
  }
40
44
  },
41
45
  "files": [
@@ -50,10 +54,11 @@
50
54
  "test": "vitest run"
51
55
  },
52
56
  "dependencies": {
53
- "@chestnutlabs/gcode-parser": "0.19.0",
54
- "@chestnutlabs/gcode-renderer-three": "0.19.0",
55
- "@chestnutlabs/toolpath-core": "0.19.0",
56
- "@chestnutlabs/gcode-preview-core": "0.19.0"
57
+ "@chestnutlabs/gcode-model-renderer": "0.20.0",
58
+ "@chestnutlabs/gcode-parser": "0.20.0",
59
+ "@chestnutlabs/gcode-renderer-three": "0.20.0",
60
+ "@chestnutlabs/toolpath-core": "0.20.0",
61
+ "@chestnutlabs/gcode-preview-core": "0.20.0"
57
62
  },
58
63
  "peerDependencies": {
59
64
  "vue": "^3.4.0"