@chestnutlabs/gcode-preview-vue 0.18.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 +58 -7
- package/dist/gcode-preview-component.d.ts +14 -1
- package/dist/gcode-preview-component.d.ts.map +1 -1
- package/dist/gcode-preview-component.js +16 -0
- package/dist/model/index.d.ts +10 -0
- package/dist/model/index.d.ts.map +1 -0
- package/dist/model/index.js +7 -0
- package/dist/model/model-viewer-component.d.ts +175 -0
- package/dist/model/model-viewer-component.d.ts.map +1 -0
- package/dist/model/model-viewer-component.js +127 -0
- package/dist/model/use-model-viewer.d.ts +28 -0
- package/dist/model/use-model-viewer.d.ts.map +1 -0
- package/dist/model/use-model-viewer.js +34 -0
- package/dist/use-gcode-preview.d.ts +4 -1
- package/dist/use-gcode-preview.d.ts.map +1 -1
- package/dist/use-gcode-preview.js +1 -0
- package/package.json +10 -5
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
|
-
| `
|
|
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`, `
|
|
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":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAA6C,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC/E,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EACV,WAAW,EACX,UAAU,EACV,SAAS,EACT,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,KAAK,EACL,WAAW,EACZ,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACxF,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;
|
|
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,
|
|
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.
|
|
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-
|
|
54
|
-
"@chestnutlabs/gcode-
|
|
55
|
-
"@chestnutlabs/
|
|
56
|
-
"@chestnutlabs/
|
|
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"
|