@chestnutlabs/gcode-preview-element 0.19.0 → 0.20.1

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
@@ -43,29 +43,89 @@ Scalar options are **attributes** (also settable as properties); rich options ar
43
43
  | Attribute | Property | Type | Default |
44
44
  |---|---|---|---|
45
45
  | `quality` | `quality` | `'auto' \| 'lines' \| 'tubes'` | `'auto'` |
46
+ | `renderer` | `renderer` | `'3d' \| '2d'` — **construction-time** | `'3d'` |
47
+ | `adjacent-layers` | `adjacentLayers` | integer (2D ghost layers) — **construction-time** | — |
46
48
  | `camera-mode` | `cameraMode` | `'perspective' \| 'orthographic'` | `'perspective'` |
47
49
  | `show-travel` | `showTravel` | `"true" \| "false"` | `true` |
48
50
  | `show-retractions` | `showRetractions` | `"true" \| "false"` | `false` |
49
51
  | `scrub` | `scrub` | integer | — (all) |
50
52
  | `layer-range` | `layerRange` | `"start,end"` / `[number, number]` | — (all) |
53
+ | `hidden-feature-roles` | `hiddenFeatureRoles` | `"6,7"` / `number[]` — hide roles (Skirt, Brim…) | — |
51
54
  | — | `source` | `Uint8Array \| ArrayBuffer \| File` | `null` |
52
55
  | — | `colorMode` | `ColorMode` | — |
53
56
  | — | `theme` | `Theme` | — |
57
+ | — | `tube` | `TubeOptions` — **construction-time** | — |
54
58
  | — | `buildVolume` | `BuildVolumeDef \| MachineGeometry` | — |
55
59
  | — | `progress` | `ProgressObservation \| null` | `null` |
56
60
  | — | `createWorker` | `() => WorkerLike` | batteries default |
57
61
 
58
62
  > `source` is a **property only** (never a URL attribute) — the element does not fetch.
63
+ > `colorMode`, `theme`, `tube`, and `buildVolume` are **property-only** because objects can't be HTML
64
+ > attributes — set them as JS properties. `hidden-feature-roles` gates on `capabilities.featureRoles`
65
+ > (declarative form of `controls.setFeatureRoleVisible`). This is a ~24-option surface; the rest of
66
+ > the declarative props (`qualityMode`, `view`, `cameraState`, `frameContent`, `scrubTime`,
67
+ > `showWipe`, `showVolumeCage`, `interactionQuality`, `parseOptions`, `rendererOptions`, `layerRange`)
68
+ > are set the same way.
59
69
 
60
70
  ### DOM events (`CustomEvent`, kebab-case `detail`)
61
71
 
62
- `ready` · `parse-error` · `parse-cancelled` · `parse-progress` · `build-complete` · `disclosure` ·
63
- `quality-fallback` · `progress-presentation-changed` · `machine-geometry-discovered` ·
64
- `machine-geometry-mismatch` · `error`.
72
+ `ready` · `camerachange` · `parse-error` · `parse-cancelled` · `parse-progress` · `stage` ·
73
+ `build-complete` · `disclosure` · `quality-fallback` · `progress-presentation-changed` ·
74
+ `machine-geometry-discovered` · `machine-geometry-mismatch` · `error`.
75
+
76
+ A few event `detail`s are DOM-wrapped, an accepted custom-element idiom: `disclosure` detail is
77
+ `{ text }`, `machine-geometry-discovered` is `{ machine }`, and `machine-geometry-mismatch` is
78
+ `{ message }`.
65
79
 
66
80
  The underlying handle is also exposed as instance members (`state`, `controls`, `raw`, `onEvent`,
67
- `parse`, `observeProgress`, `tickProgress`, `clearProgress`) for advanced use — the same neutral
68
- controller surface the other adapters expose.
81
+ `parse`, `observeProgress`, `tickProgress`, `clearProgress`, `capture`) for advanced use — the same
82
+ neutral controller surface the other adapters expose. `controls` reaches the imperative extras —
83
+ `getRenderStats()` (render diagnostics), `pickSegment(ndcX, ndcY, threshold?)` (source-mapping /
84
+ picking), and `isColorModeAvailable(mode)`; `capture(opts?)` (image `Blob`) is both a top-level
85
+ method and `controls.capture`. The handle `state` carries capability-aware UI data
86
+ (`availableColorModes`, `hasRetractions`, `hasColorChanges`).
87
+
88
+ ## Model viewing (Prepare side)
89
+
90
+ The `/model/define` entry registers `<gcode-model-viewer>` — the **Prepare**-side counterpart to
91
+ `<gcode-preview>` (the tag deliberately avoids the reserved `<model-viewer>`). Where `<gcode-preview>`
92
+ draws the toolpath (how a print runs), `<gcode-model-viewer>` draws the **source model** (an `.stl` /
93
+ `.3mf` mesh) — the object before slicing.
94
+
95
+ ```html
96
+ <script type="module">
97
+ import '@chestnutlabs/gcode-preview-element/model/define'; // registers <gcode-model-viewer>
98
+
99
+ const el = document.querySelector('gcode-model-viewer');
100
+ el.addEventListener('ready', (e) => console.log(e.detail.objectCount, e.detail.materials));
101
+ el.source = { kind: '3mf', bytes }; // rich options are properties; primitives are attributes
102
+ </script>
103
+
104
+ <gcode-model-viewer background="transparent" style="width: 100%; height: 70vh"></gcode-model-viewer>
105
+ ```
106
+
107
+ The `ready` event carries the honest material-colour tier: `e.detail.materials` is `'known'` /
108
+ `'approximated'` when the file declared colours the render used, and `'unavailable'` when it declared
109
+ none (a neutral default, never faked). The same attribute/property split as `<gcode-preview>` applies —
110
+ rich options (`.source`, `.cameraState`, `.renderScope`, …) are properties; primitives (`view`,
111
+ `background`, `camera-mode`) are attributes. See
112
+ [`docs/manual/adapters.md`](../../docs/manual/adapters.md) "Two viewers: Preview and Prepare" for the
113
+ cross-adapter tour, and `tools/example-webcomponent/model.html` for a runnable minimal page.
114
+
115
+ ## Examples
116
+
117
+ `tools/example-webcomponent` in the repository is a framework-free Vite app with two tiers, both
118
+ driving this published element (no raw renderer or parser imports):
119
+
120
+ - **`minimal.html`** — the smallest real integration: import `/define` to register `<gcode-preview>`,
121
+ set the `source` property, listen for `ready`; the layer slider drives the `layer-range` attribute.
122
+ Shows the attribute/property split in ~40 lines.
123
+ - **`showcase.html`** — the full surface in vanilla JS: objects (`source`, `colorMode`,
124
+ `hiddenFeatureRoles`) set as properties, primitives (`layer-range`, `view`) as attributes;
125
+ capability-gated color modes; `getRenderStats()`/`pickSegment()` diagnostics via `element.controls`.
126
+
127
+ Run it with `npm install --prefix tools/example-webcomponent && npm run dev --prefix
128
+ tools/example-webcomponent` (port 5204).
69
129
 
70
130
  ## Workers
71
131
 
@@ -34,6 +34,8 @@ export declare class GcodePreviewElement extends HTMLElement {
34
34
  private _createWorker;
35
35
  private _rendererOptions;
36
36
  private _cameraState;
37
+ /** Which roles the `hidden-feature-roles` attribute last hid, for prev→next diffing (DD-031 G3). */
38
+ private prevHiddenRoles;
37
39
  get source(): GcodePreviewSource;
38
40
  set source(v: GcodePreviewSource);
39
41
  get parseOptions(): WireParseOptions | undefined;
@@ -52,6 +54,17 @@ export declare class GcodePreviewElement extends HTMLElement {
52
54
  set createWorker(v: (() => WorkerLike) | undefined);
53
55
  get rendererOptions(): ElementRendererOptions | undefined;
54
56
  set rendererOptions(v: ElementRendererOptions | undefined);
57
+ /**
58
+ * DD-014 D5 renderer selection (DD-031 E1): reflected property accessor over the `renderer`
59
+ * attribute. Construction-time like every adapter — read once at connect; changing it after the
60
+ * element is connected has no effect (mode switching post-mount is out of scope), it just keeps the
61
+ * attribute and property in sync so the value is readable/consistent.
62
+ */
63
+ get renderer(): string | null;
64
+ set renderer(v: string | null);
65
+ /** 2D only: preceding "ghost" layers (DD-031 E1). Construction-time; reflected accessor over the attribute. */
66
+ get adjacentLayers(): number | null;
67
+ set adjacentLayers(v: number | null);
55
68
  get quality(): string | null;
56
69
  set quality(v: string | null);
57
70
  get qualityMode(): string | null;
@@ -92,6 +105,13 @@ export declare class GcodePreviewElement extends HTMLElement {
92
105
  set scrubTime(v: number | null);
93
106
  get layerRange(): [number, number] | null;
94
107
  set layerRange(v: [number, number] | null);
108
+ /**
109
+ * DD-031 G3: feature roles to hide, as a comma-separated numeric list (`hidden-feature-roles="6,7"`
110
+ * for Skirt+Brim). Declarative form of `controls.setFeatureRoleVisible`; gate on
111
+ * `capabilities.featureRoles`. Import `FeatureRole` from `@chestnutlabs/toolpath-core` for the values.
112
+ */
113
+ get hiddenFeatureRoles(): number[];
114
+ set hiddenFeatureRoles(v: number[] | null);
95
115
  get state(): GcodePreviewState;
96
116
  get controls(): GcodePreviewControls;
97
117
  get raw(): PreviewController['raw'];
@@ -107,6 +127,8 @@ export declare class GcodePreviewElement extends HTMLElement {
107
127
  attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
108
128
  /** Apply the runtime-only controls (the construction options were set at controller creation). */
109
129
  private applyRuntimeState;
130
+ /** Feature-role visibility (DD-031 G3): diff prev→next so we only toggle roles this attribute owns. */
131
+ private applyHiddenRoles;
110
132
  private applyProgress;
111
133
  private reflect;
112
134
  private requireController;
@@ -1 +1 @@
1
- {"version":3,"file":"gcode-preview-element.d.ts","sourceRoot":"","sources":["../src/gcode-preview-element.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gcode-preview-element.d.ts","sourceRoot":"","sources":["../src/gcode-preview-element.ts"],"names":[],"mappings":"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"}
@@ -26,7 +26,8 @@ const OBSERVED = [
26
26
  'show-volume-cage',
27
27
  'scrub',
28
28
  'scrub-time',
29
- 'layer-range'
29
+ 'layer-range',
30
+ 'hidden-feature-roles'
30
31
  ];
31
32
  /** The default tag name (DD-009 §4.5). */
32
33
  export const DEFAULT_TAG = 'gcode-preview';
@@ -47,6 +48,8 @@ export class GcodePreviewElement extends HTMLElement {
47
48
  _createWorker;
48
49
  _rendererOptions;
49
50
  _cameraState = null;
51
+ /** Which roles the `hidden-feature-roles` attribute last hid, for prev→next diffing (DD-031 G3). */
52
+ prevHiddenRoles = [];
50
53
  // ---- rich-option property accessors ----
51
54
  get source() {
52
55
  return this._source;
@@ -111,6 +114,26 @@ export class GcodePreviewElement extends HTMLElement {
111
114
  set rendererOptions(v) {
112
115
  this._rendererOptions = v; // construction-only injectables
113
116
  }
117
+ /**
118
+ * DD-014 D5 renderer selection (DD-031 E1): reflected property accessor over the `renderer`
119
+ * attribute. Construction-time like every adapter — read once at connect; changing it after the
120
+ * element is connected has no effect (mode switching post-mount is out of scope), it just keeps the
121
+ * attribute and property in sync so the value is readable/consistent.
122
+ */
123
+ get renderer() {
124
+ return this.getAttribute('renderer');
125
+ }
126
+ set renderer(v) {
127
+ this.reflect('renderer', v);
128
+ }
129
+ /** 2D only: preceding "ghost" layers (DD-031 E1). Construction-time; reflected accessor over the attribute. */
130
+ get adjacentLayers() {
131
+ const a = this.getAttribute('adjacent-layers');
132
+ return a === null ? null : Number(a);
133
+ }
134
+ set adjacentLayers(v) {
135
+ this.reflect('adjacent-layers', v);
136
+ }
114
137
  // ---- scalar-option accessors (reflect to attributes: one source of truth) ----
115
138
  get quality() {
116
139
  return this.getAttribute('quality');
@@ -216,6 +239,17 @@ export class GcodePreviewElement extends HTMLElement {
216
239
  set layerRange(v) {
217
240
  this.reflect('layer-range', v === null ? null : `${v[0]},${v[1]}`);
218
241
  }
242
+ /**
243
+ * DD-031 G3: feature roles to hide, as a comma-separated numeric list (`hidden-feature-roles="6,7"`
244
+ * for Skirt+Brim). Declarative form of `controls.setFeatureRoleVisible`; gate on
245
+ * `capabilities.featureRoles`. Import `FeatureRole` from `@chestnutlabs/toolpath-core` for the values.
246
+ */
247
+ get hiddenFeatureRoles() {
248
+ return parseRoleList(this.getAttribute('hidden-feature-roles'));
249
+ }
250
+ set hiddenFeatureRoles(v) {
251
+ this.reflect('hidden-feature-roles', v === null || v.length === 0 ? null : v.join(','));
252
+ }
219
253
  // ---- handle-parity passthrough (advanced/parity surface; DOM events are the ergonomic one) ----
220
254
  get state() {
221
255
  return this.requireController().getState();
@@ -292,6 +326,10 @@ export class GcodePreviewElement extends HTMLElement {
292
326
  this.controller = null;
293
327
  this.canvasEl = null;
294
328
  this.shadowRoot?.replaceChildren();
329
+ // A reconnect builds a FRESH controller with all roles visible. prevHiddenRoles tracks what the
330
+ // previous controller had hidden; if we don't reset it, the prev→next diff on re-apply sees no
331
+ // change and re-hides nothing, so hidden skirt/brim reappear permanently after a DOM move.
332
+ this.prevHiddenRoles = [];
295
333
  }
296
334
  attributeChangedCallback(name, _old, value) {
297
335
  if (this.controller === null)
@@ -351,6 +389,9 @@ export class GcodePreviewElement extends HTMLElement {
351
389
  c.setLayerRange(r[0], r[1]);
352
390
  break;
353
391
  }
392
+ case 'hidden-feature-roles':
393
+ this.applyHiddenRoles(parseRoleList(value));
394
+ break;
354
395
  default:
355
396
  break;
356
397
  }
@@ -370,7 +411,32 @@ export class GcodePreviewElement extends HTMLElement {
370
411
  c.setLayerRange(r[0], r[1]);
371
412
  c.setScrubPosition(this.scrub);
372
413
  c.setScrubTime(this.scrubTime);
414
+ this.applyHiddenRoles(this.hiddenFeatureRoles);
373
415
  this.applyProgress();
416
+ // Camera framing set BEFORE connect: attributeChangedCallback/the cameraState setter both no-op
417
+ // while controller === null, so the initial `view` attribute and any pre-connect cameraState must
418
+ // be applied here or they're silently dropped (the <gcode-model-viewer> element already does this).
419
+ // Apply the preset view first, then let an explicit cameraState override it.
420
+ const view = this.getAttribute('view');
421
+ if (view !== null)
422
+ c.setView(view);
423
+ if (this._cameraState !== null)
424
+ c.setCameraState(this._cameraState);
425
+ }
426
+ /** Feature-role visibility (DD-031 G3): diff prev→next so we only toggle roles this attribute owns. */
427
+ applyHiddenRoles(next) {
428
+ if (this.controller === null)
429
+ return;
430
+ const c = this.controller.controls;
431
+ for (const role of this.prevHiddenRoles) {
432
+ if (!next.includes(role))
433
+ c.setFeatureRoleVisible(role, true);
434
+ }
435
+ for (const role of next) {
436
+ if (!this.prevHiddenRoles.includes(role))
437
+ c.setFeatureRoleVisible(role, false);
438
+ }
439
+ this.prevHiddenRoles = [...next];
374
440
  }
375
441
  applyProgress() {
376
442
  if (this.controller === null)
@@ -455,6 +521,15 @@ function parseLayerRange(value) {
455
521
  return null;
456
522
  return [parts[0], parts[1]];
457
523
  }
524
+ /** Parse `hidden-feature-roles="6,7"` into a numeric role list; ignores blanks/NaN (DD-031 G3). */
525
+ function parseRoleList(value) {
526
+ if (value === null || value.trim() === '')
527
+ return [];
528
+ return value
529
+ .split(',')
530
+ .map((s) => Number(s.trim()))
531
+ .filter((n) => Number.isFinite(n));
532
+ }
458
533
  /**
459
534
  * Register `<gcode-preview>` (idempotent — safe to call repeatedly and from multiple
460
535
  * bundles). Kept as a function (not a module side effect) so the package stays
package/dist/index.d.ts CHANGED
@@ -5,5 +5,5 @@
5
5
  * `@chestnutlabs/gcode-preview-element/define` to auto-register.
6
6
  */
7
7
  export { GcodePreviewElement, defineGcodePreview, DEFAULT_TAG, type GcodePreviewSource, type ElementRendererOptions } from './gcode-preview-element.js';
8
- export type { GcodePreviewControls, GcodePreviewState, ParseOutcome, PreviewEvent } from '@chestnutlabs/gcode-preview-core';
8
+ export type { GcodePreviewControls, GcodePreviewState, ParseOutcome, PreviewEvent, PreviewRenderer, RendererMode } from '@chestnutlabs/gcode-preview-core';
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC5B,MAAM,4BAA4B,CAAC;AAGpC,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACb,MAAM,kCAAkC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC5B,MAAM,4BAA4B,CAAC;AAIpC,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,YAAY,EACb,MAAM,kCAAkC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=define.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/model/define.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Side-effectful registration entry: `import '@chestnutlabs/gcode-preview-element/model/define'`
3
+ * auto-registers `<gcode-model-viewer>`. Kept as a separate subpath so `.../model` stays
4
+ * side-effect-free.
5
+ */
6
+ import { defineGcodeModelViewer } from './index.js';
7
+ defineGcodeModelViewer();
@@ -0,0 +1,68 @@
1
+ /**
2
+ * <gcode-model-viewer> — the framework-free Web Component for interactive source-model viewing
3
+ * (STL / 3MF), the Prepare-side counterpart to <gcode-preview> (DD-031). A SHELL over
4
+ * `createModelPreviewController`, exactly like the Vue/React/Svelte model adapters: attributes and
5
+ * properties map to controller options / `controls.*` calls, and controller events are re-emitted as
6
+ * DOM `CustomEvent`s. The handle is also exposed as instance members (`state`/`controls`/`raw`/`onEvent`/
7
+ * `setSource`/`capture`) so the shared model behavioral suite runs against it identically.
8
+ *
9
+ * The tag is `gcode-model-viewer` (not the reserved `model-viewer`). No framework peer dependency.
10
+ */
11
+ import { type ModelBackground, type ModelLimits, type ModelLoader, type ModelPreviewControls, type ModelPreviewState, type ModelSourceInput, type ModelViewer, type ModelViewerEvent, type RenderScope } from '@chestnutlabs/gcode-model-renderer';
12
+ import type { CameraState, CaptureOptions, GLRendererLike, InteractiveStageOptions, RenderTargetCanvas } from '@chestnutlabs/gcode-renderer-three';
13
+ /** The default tag name for the model viewer. */
14
+ export declare const DEFAULT_MODEL_TAG = "gcode-model-viewer";
15
+ export declare class GcodeModelViewerElement extends HTMLElement {
16
+ static get observedAttributes(): string[];
17
+ private controller;
18
+ private canvasEl;
19
+ private _source;
20
+ private _cameraState;
21
+ private _background;
22
+ private _renderScope;
23
+ private _limits;
24
+ private _filamentPalette;
25
+ private _loaders;
26
+ private _createRenderer;
27
+ private _createControls;
28
+ get source(): ModelSourceInput | null;
29
+ set source(v: ModelSourceInput | null);
30
+ get cameraState(): CameraState | null;
31
+ set cameraState(v: CameraState | null);
32
+ get background(): ModelBackground | undefined;
33
+ set background(v: ModelBackground | undefined);
34
+ get renderScope(): RenderScope | null;
35
+ set renderScope(v: RenderScope | null);
36
+ get limits(): ModelLimits | undefined;
37
+ set limits(v: ModelLimits | undefined);
38
+ get filamentPalette(): readonly (string | undefined)[] | undefined;
39
+ set filamentPalette(v: readonly (string | undefined)[] | undefined);
40
+ get loaders(): readonly ModelLoader[] | undefined;
41
+ set loaders(v: readonly ModelLoader[] | undefined);
42
+ get createRenderer(): ((canvas: RenderTargetCanvas) => GLRendererLike) | undefined;
43
+ set createRenderer(v: ((canvas: RenderTargetCanvas) => GLRendererLike) | undefined);
44
+ get createControls(): NonNullable<InteractiveStageOptions['createControls']> | undefined;
45
+ set createControls(v: NonNullable<InteractiveStageOptions['createControls']> | undefined);
46
+ get view(): string | null;
47
+ set view(v: string | null);
48
+ get interactionQuality(): string | null;
49
+ set interactionQuality(v: string | null);
50
+ get cameraMode(): string | null;
51
+ set cameraMode(v: string | null);
52
+ get state(): ModelPreviewState;
53
+ get controls(): ModelPreviewControls;
54
+ get raw(): {
55
+ viewer: () => ModelViewer | null;
56
+ };
57
+ setSource(input: ModelSourceInput): Promise<import('@chestnutlabs/gcode-model-renderer').ModelReadyInfo>;
58
+ capture(opts?: CaptureOptions): Promise<Blob>;
59
+ onEvent(cb: (e: ModelViewerEvent) => void): () => void;
60
+ connectedCallback(): void;
61
+ disconnectedCallback(): void;
62
+ attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
63
+ private reemit;
64
+ private requireController;
65
+ }
66
+ /** Register the element (idempotent). Import `.../model/define` for auto-registration. */
67
+ export declare function defineGcodeModelViewer(tag?: string): void;
68
+ //# sourceMappingURL=gcode-model-viewer-element.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gcode-model-viewer-element.d.ts","sourceRoot":"","sources":["../../src/model/gcode-model-viewer-element.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,249 @@
1
+ /**
2
+ * <gcode-model-viewer> — the framework-free Web Component for interactive source-model viewing
3
+ * (STL / 3MF), the Prepare-side counterpart to <gcode-preview> (DD-031). A SHELL over
4
+ * `createModelPreviewController`, exactly like the Vue/React/Svelte model adapters: attributes and
5
+ * properties map to controller options / `controls.*` calls, and controller events are re-emitted as
6
+ * DOM `CustomEvent`s. The handle is also exposed as instance members (`state`/`controls`/`raw`/`onEvent`/
7
+ * `setSource`/`capture`) so the shared model behavioral suite runs against it identically.
8
+ *
9
+ * The tag is `gcode-model-viewer` (not the reserved `model-viewer`). No framework peer dependency.
10
+ */
11
+ import { createModelPreviewController } from '@chestnutlabs/gcode-model-renderer';
12
+ /** Observed scalar attributes; rich options (source, cameraState, palettes, loaders, injectables) are property-only. */
13
+ const OBSERVED = ['view', 'background', 'interaction-quality', 'camera-mode'];
14
+ /** The default tag name for the model viewer. */
15
+ export const DEFAULT_MODEL_TAG = 'gcode-model-viewer';
16
+ export class GcodeModelViewerElement extends HTMLElement {
17
+ static get observedAttributes() {
18
+ return [...OBSERVED];
19
+ }
20
+ controller = null;
21
+ canvasEl = null;
22
+ // Rich options — objects/functions can't be attributes, so they are property-only.
23
+ _source = null;
24
+ _cameraState = null;
25
+ _background;
26
+ _renderScope = null;
27
+ _limits;
28
+ _filamentPalette;
29
+ _loaders;
30
+ _createRenderer;
31
+ _createControls;
32
+ // ---- rich-option property accessors ----
33
+ get source() {
34
+ return this._source;
35
+ }
36
+ set source(v) {
37
+ this._source = v;
38
+ if (v !== null && this.controller !== null)
39
+ void this.controller.controls.setSource(v);
40
+ }
41
+ get cameraState() {
42
+ return this._cameraState;
43
+ }
44
+ set cameraState(v) {
45
+ this._cameraState = v;
46
+ if (v !== null)
47
+ this.controller?.controls.setCameraState(v);
48
+ }
49
+ get background() {
50
+ return this._background;
51
+ }
52
+ set background(v) {
53
+ this._background = v;
54
+ if (v !== undefined)
55
+ this.controller?.controls.setBackground(v);
56
+ }
57
+ get renderScope() {
58
+ return this._renderScope;
59
+ }
60
+ set renderScope(v) {
61
+ this._renderScope = v;
62
+ this.controller?.controls.setRenderScope(v);
63
+ }
64
+ get limits() {
65
+ return this._limits;
66
+ }
67
+ set limits(v) {
68
+ this._limits = v; // construction-time only
69
+ }
70
+ get filamentPalette() {
71
+ return this._filamentPalette;
72
+ }
73
+ set filamentPalette(v) {
74
+ this._filamentPalette = v; // construction-time only
75
+ }
76
+ get loaders() {
77
+ return this._loaders;
78
+ }
79
+ set loaders(v) {
80
+ this._loaders = v; // construction-time only
81
+ }
82
+ get createRenderer() {
83
+ return this._createRenderer;
84
+ }
85
+ set createRenderer(v) {
86
+ this._createRenderer = v; // construction-time only
87
+ }
88
+ get createControls() {
89
+ return this._createControls;
90
+ }
91
+ set createControls(v) {
92
+ this._createControls = v; // construction-time only
93
+ }
94
+ // ---- scalar attribute accessors ----
95
+ get view() {
96
+ return this.getAttribute('view');
97
+ }
98
+ set view(v) {
99
+ if (v === null)
100
+ this.removeAttribute('view');
101
+ else
102
+ this.setAttribute('view', v);
103
+ }
104
+ get interactionQuality() {
105
+ return this.getAttribute('interaction-quality');
106
+ }
107
+ set interactionQuality(v) {
108
+ if (v === null)
109
+ this.removeAttribute('interaction-quality');
110
+ else
111
+ this.setAttribute('interaction-quality', v);
112
+ }
113
+ get cameraMode() {
114
+ return this.getAttribute('camera-mode');
115
+ }
116
+ set cameraMode(v) {
117
+ if (v === null)
118
+ this.removeAttribute('camera-mode');
119
+ else
120
+ this.setAttribute('camera-mode', v);
121
+ }
122
+ // ---- handle passthrough (parity with the other adapters) ----
123
+ get state() {
124
+ return this.requireController().getState();
125
+ }
126
+ get controls() {
127
+ return this.requireController().controls;
128
+ }
129
+ get raw() {
130
+ return this.requireController().raw;
131
+ }
132
+ setSource(input) {
133
+ return this.requireController().controls.setSource(input);
134
+ }
135
+ capture(opts) {
136
+ return this.requireController().controls.capture(opts);
137
+ }
138
+ onEvent(cb) {
139
+ return this.requireController().onEvent(cb);
140
+ }
141
+ // ---- lifecycle ----
142
+ connectedCallback() {
143
+ if (this.controller !== null)
144
+ return;
145
+ const root = this.shadowRoot ?? this.attachShadow({ mode: 'open' });
146
+ root.replaceChildren();
147
+ const style = document.createElement('style');
148
+ style.textContent = ':host{display:block;width:100%;height:100%}canvas{display:block;width:100%;height:100%}';
149
+ const canvas = document.createElement('canvas');
150
+ canvas.setAttribute('aria-label', '3D source-model preview');
151
+ canvas.setAttribute('tabindex', '0');
152
+ root.append(style, canvas);
153
+ this.canvasEl = canvas;
154
+ const bg = this._background ?? this.getAttribute('background') ?? undefined;
155
+ this.controller = createModelPreviewController({
156
+ ...(this._loaders ? { loaders: this._loaders } : {}),
157
+ ...(bg !== undefined ? { background: bg } : {}),
158
+ ...(this.getAttribute('interaction-quality')
159
+ ? { interactionQuality: this.getAttribute('interaction-quality') }
160
+ : {}),
161
+ ...(this.getAttribute('camera-mode') ? { cameraMode: this.getAttribute('camera-mode') } : {}),
162
+ ...(this._limits ? { limits: this._limits } : {}),
163
+ ...(this._filamentPalette ? { filamentPalette: this._filamentPalette } : {}),
164
+ ...(this._renderScope ? { renderScope: this._renderScope } : {}),
165
+ ...(this._createRenderer ? { createRenderer: this._createRenderer } : {}),
166
+ ...(this._createControls ? { createControls: this._createControls } : {}),
167
+ onProgress: (p) => this.dispatchEvent(new CustomEvent('progress', { detail: p }))
168
+ });
169
+ this.controller.onEvent((e) => this.reemit(e));
170
+ this.controller.bindCanvas(canvas);
171
+ // Apply runtime-only state that isn't a construction option.
172
+ const view = this.getAttribute('view');
173
+ if (view !== null)
174
+ this.controller.controls.setView(view);
175
+ if (this._cameraState !== null)
176
+ this.controller.controls.setCameraState(this._cameraState);
177
+ if (this._source !== null)
178
+ void this.controller.controls.setSource(this._source);
179
+ }
180
+ disconnectedCallback() {
181
+ this.controller?.dispose();
182
+ this.controller = null;
183
+ this.canvasEl = null;
184
+ this.shadowRoot?.replaceChildren();
185
+ }
186
+ attributeChangedCallback(name, _old, value) {
187
+ if (this.controller === null)
188
+ return;
189
+ const c = this.controller.controls;
190
+ switch (name) {
191
+ case 'view':
192
+ if (value !== null)
193
+ c.setView(value);
194
+ break;
195
+ case 'background':
196
+ if (value !== null)
197
+ c.setBackground(value);
198
+ break;
199
+ case 'interaction-quality':
200
+ if (value !== null)
201
+ c.setInteractionQuality(value);
202
+ break;
203
+ case 'camera-mode':
204
+ // Construction-time only (projection switching post-mount is out of scope); no-op at runtime.
205
+ break;
206
+ default:
207
+ break;
208
+ }
209
+ }
210
+ reemit(e) {
211
+ const emit = (type, detail) => {
212
+ this.dispatchEvent(new CustomEvent(type, { detail }));
213
+ };
214
+ switch (e.type) {
215
+ case 'ready':
216
+ emit('ready', e.info);
217
+ break;
218
+ case 'camera-changed':
219
+ emit('camerachange', e.state);
220
+ break;
221
+ case 'error':
222
+ emit('error', { code: e.code, message: e.message });
223
+ break;
224
+ case 'renderer-unsupported':
225
+ emit('renderer-unsupported', { feature: e.feature, message: e.message });
226
+ break;
227
+ case 'context-lost':
228
+ emit('context-lost');
229
+ break;
230
+ case 'context-restored':
231
+ emit('context-restored');
232
+ break;
233
+ default:
234
+ break;
235
+ }
236
+ }
237
+ requireController() {
238
+ if (this.controller === null) {
239
+ throw new Error('gcode-model-viewer: not connected to the DOM yet (no controller)');
240
+ }
241
+ return this.controller;
242
+ }
243
+ }
244
+ /** Register the element (idempotent). Import `.../model/define` for auto-registration. */
245
+ export function defineGcodeModelViewer(tag = DEFAULT_MODEL_TAG) {
246
+ if (customElements.get(tag) === undefined) {
247
+ customElements.define(tag, GcodeModelViewerElement);
248
+ }
249
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @chestnutlabs/gcode-preview-element/model — the framework-free `<gcode-model-viewer>` Web Component
3
+ * for interactive source-model viewing (STL / 3MF), the Prepare-side counterpart to `<gcode-preview>`
4
+ * (DD-031). Registration is a function (`defineGcodeModelViewer`) so this entry stays side-effect-free;
5
+ * import `.../model/define` to auto-register. A thin shell over `createModelPreviewController`.
6
+ */
7
+ export { GcodeModelViewerElement, defineGcodeModelViewer, DEFAULT_MODEL_TAG } from './gcode-model-viewer-element.js';
8
+ export type { ModelPreviewControls, ModelPreviewState, ModelViewer, ModelViewerEvent, ModelReadyInfo, ModelSourceInput } from '@chestnutlabs/gcode-model-renderer';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAGrH,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EACjB,MAAM,oCAAoC,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @chestnutlabs/gcode-preview-element/model — the framework-free `<gcode-model-viewer>` Web Component
3
+ * for interactive source-model viewing (STL / 3MF), the Prepare-side counterpart to `<gcode-preview>`
4
+ * (DD-031). Registration is a function (`defineGcodeModelViewer`) so this entry stays side-effect-free;
5
+ * import `.../model/define` to auto-register. A thin shell over `createModelPreviewController`.
6
+ */
7
+ export { GcodeModelViewerElement, defineGcodeModelViewer, DEFAULT_MODEL_TAG } from './gcode-model-viewer-element.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chestnutlabs/gcode-preview-element",
3
- "version": "0.19.0",
3
+ "version": "0.20.1",
4
4
  "description": "Framework-free <gcode-preview> Web Component for the Chestnut Labs G-code viewer (DD-007 D1 / DD-009 D5): a custom element bridging @chestnutlabs/gcode-preview-core, no framework peer dependency.",
5
5
  "keywords": [
6
6
  "gcode",
@@ -38,6 +38,14 @@
38
38
  "./define": {
39
39
  "types": "./dist/define.d.ts",
40
40
  "import": "./dist/define.js"
41
+ },
42
+ "./model": {
43
+ "types": "./dist/model/index.d.ts",
44
+ "import": "./dist/model/index.js"
45
+ },
46
+ "./model/define": {
47
+ "types": "./dist/model/define.d.ts",
48
+ "import": "./dist/model/define.js"
41
49
  }
42
50
  },
43
51
  "files": [
@@ -52,9 +60,10 @@
52
60
  "test": "vitest run"
53
61
  },
54
62
  "dependencies": {
55
- "@chestnutlabs/gcode-parser": "0.19.0",
56
- "@chestnutlabs/gcode-preview-core": "0.19.0",
57
- "@chestnutlabs/gcode-renderer-three": "0.19.0",
58
- "@chestnutlabs/toolpath-core": "0.19.0"
63
+ "@chestnutlabs/gcode-model-renderer": "0.20.1",
64
+ "@chestnutlabs/gcode-parser": "0.20.1",
65
+ "@chestnutlabs/gcode-preview-core": "0.20.1",
66
+ "@chestnutlabs/gcode-renderer-three": "0.20.1",
67
+ "@chestnutlabs/toolpath-core": "0.20.1"
59
68
  }
60
69
  }