@chestnutlabs/gcode-preview-core 0.11.0 → 0.13.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.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Resolve a `{ mode: 'filament' }` colour request into a concrete colorer mode using the file's OWN filament
3
+ * colours (DD-024 flash fix). These colours live in parse metadata (`metadata.filaments[].color`), which the
4
+ * IR-only colorer cannot see — so the metadata-aware controller resolves them here before the colorer runs,
5
+ * and the first visible pass is already coloured (no neutral-then-recolor). Honesty preserved: no usable
6
+ * filament colours ⇒ neutral, never a fabricated palette.
7
+ */
8
+ import type { ColorMode, RGB } from '@chestnutlabs/gcode-renderer-three';
9
+ import type { DialectMetadata, ToolpathIR } from '@chestnutlabs/toolpath-core';
10
+ /** Neutral fallback for a resolved `filament` colour mode (matches the colorer default). */
11
+ export declare const FILAMENT_FALLBACK: RGB;
12
+ /** Parse a `#RRGGBB` (or `#RGB`) hex string to 0..1 RGB, or `null` when not a usable colour. */
13
+ export declare function hexToRgb(hex: string | undefined): RGB | null;
14
+ /**
15
+ * Build a tool/slot palette from the parse metadata's own filament colours (`metadata.filaments[].color`),
16
+ * indexed by 0-based `slot`. Filaments without a usable colour leave a gap filled with the fallback so the
17
+ * array stays dense up to the highest declared slot. Empty when the source declared no filament colours.
18
+ */
19
+ export declare function filamentPalette(metadata: DialectMetadata | undefined): RGB[];
20
+ /**
21
+ * Resolve a `{ mode: 'filament' }` request into a concrete colorer mode: colour-change files (M600 swaps)
22
+ * shade by swap slot, multi-extruder files by tool — both from the source's `metadata.filaments` palette. No
23
+ * usable filament colours ⇒ honest neutral (`single` fallback). Any other mode passes through unchanged.
24
+ */
25
+ export declare function resolveColorMode(mode: ColorMode | undefined, metadata: DialectMetadata | undefined, ir: ToolpathIR | null): ColorMode | undefined;
26
+ //# sourceMappingURL=color-resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-resolve.d.ts","sourceRoot":"","sources":["../src/color-resolve.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE/E,4FAA4F;AAC5F,eAAO,MAAM,iBAAiB,EAAE,GAAqB,CAAC;AAEtD,gGAAgG;AAChG,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,GAAG,IAAI,CAM5D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,GAAG,SAAS,GAAG,GAAG,EAAE,CAgB5E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,SAAS,GAAG,SAAS,EAC3B,QAAQ,EAAE,eAAe,GAAG,SAAS,EACrC,EAAE,EAAE,UAAU,GAAG,IAAI,GACpB,SAAS,GAAG,SAAS,CAQvB"}
@@ -0,0 +1,55 @@
1
+ /** Neutral fallback for a resolved `filament` colour mode (matches the colorer default). */
2
+ export const FILAMENT_FALLBACK = [0.7, 0.7, 0.7];
3
+ /** Parse a `#RRGGBB` (or `#RGB`) hex string to 0..1 RGB, or `null` when not a usable colour. */
4
+ export function hexToRgb(hex) {
5
+ if (hex === undefined)
6
+ return null;
7
+ let h = hex.trim().replace(/^#/, '');
8
+ if (h.length === 3)
9
+ h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
10
+ if (!/^[0-9a-fA-F]{6}$/.test(h))
11
+ return null;
12
+ return [parseInt(h.slice(0, 2), 16) / 255, parseInt(h.slice(2, 4), 16) / 255, parseInt(h.slice(4, 6), 16) / 255];
13
+ }
14
+ /**
15
+ * Build a tool/slot palette from the parse metadata's own filament colours (`metadata.filaments[].color`),
16
+ * indexed by 0-based `slot`. Filaments without a usable colour leave a gap filled with the fallback so the
17
+ * array stays dense up to the highest declared slot. Empty when the source declared no filament colours.
18
+ */
19
+ export function filamentPalette(metadata) {
20
+ const filaments = metadata?.filaments;
21
+ if (filaments === undefined || filaments.length === 0)
22
+ return [];
23
+ let maxSlot = -1;
24
+ for (const f of filaments)
25
+ if (f.slot > maxSlot)
26
+ maxSlot = f.slot;
27
+ if (maxSlot < 0)
28
+ return [];
29
+ const palette = Array.from({ length: maxSlot + 1 }, () => FILAMENT_FALLBACK);
30
+ let any = false;
31
+ for (const f of filaments) {
32
+ const rgb = hexToRgb(f.color);
33
+ if (rgb !== null && f.slot >= 0) {
34
+ palette[f.slot] = rgb;
35
+ any = true;
36
+ }
37
+ }
38
+ return any ? palette : [];
39
+ }
40
+ /**
41
+ * Resolve a `{ mode: 'filament' }` request into a concrete colorer mode: colour-change files (M600 swaps)
42
+ * shade by swap slot, multi-extruder files by tool — both from the source's `metadata.filaments` palette. No
43
+ * usable filament colours ⇒ honest neutral (`single` fallback). Any other mode passes through unchanged.
44
+ */
45
+ export function resolveColorMode(mode, metadata, ir) {
46
+ if (mode === undefined || mode.mode !== 'filament')
47
+ return mode;
48
+ const fallback = mode.fallback ?? FILAMENT_FALLBACK;
49
+ const palette = filamentPalette(metadata);
50
+ if (palette.length === 0)
51
+ return { mode: 'single', color: fallback };
52
+ return ir !== null && ir.colorChanges.length > 0
53
+ ? { mode: 'colorChange', palette, fallback }
54
+ : { mode: 'tool', palette, fallback };
55
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,7 @@
12
12
  import { GcodeParseSession, CancelledError, ParseSessionError } from '@chestnutlabs/gcode-parser';
13
13
  import { LayerView2DRenderer } from './renderer-2d-adapter.js';
14
14
  import { createProgressMapper, computeToolpathTime, segmentsCompletedAtTime } from '@chestnutlabs/toolpath-core';
15
+ import { resolveColorMode } from './color-resolve.js';
15
16
  const INITIAL_STATE = {
16
17
  parsing: false,
17
18
  parseProgress: null,
@@ -29,6 +30,13 @@ const INITIAL_STATE = {
29
30
  function toBytes(input) {
30
31
  return input instanceof Uint8Array ? input : new Uint8Array(input);
31
32
  }
33
+ /** English ordinal for the decimation disclosure ("every 3rd", not "every 3th"). */
34
+ function ordinal(n) {
35
+ const rem100 = n % 100;
36
+ const rem10 = n % 10;
37
+ const suffix = rem100 >= 11 && rem100 <= 13 ? 'th' : rem10 === 1 ? 'st' : rem10 === 2 ? 'nd' : rem10 === 3 ? 'rd' : 'th';
38
+ return `${n}${suffix}`;
39
+ }
32
40
  export function createPreviewController(options = {}) {
33
41
  let snapshot = { ...INITIAL_STATE };
34
42
  const stateListeners = new Set();
@@ -45,6 +53,10 @@ export function createPreviewController(options = {}) {
45
53
  let timeAxis = null;
46
54
  let lastMachine;
47
55
  let mapper = null;
56
+ // The consumer's requested colour mode, kept so a `filament` request (colour by the file's own filament
57
+ // colours) can be resolved against the parse metadata as each file loads (DD-024 flash fix).
58
+ let requestedColorMode = options.renderer?.colorMode;
59
+ let lastMetadata;
48
60
  let consumerVolumeSet = options.renderer?.buildVolume !== undefined;
49
61
  let activeParse = null;
50
62
  let resizeObserver = null;
@@ -71,7 +83,7 @@ export function createPreviewController(options = {}) {
71
83
  mutate({
72
84
  activeQuality: e.quality,
73
85
  disclosure: e.decimationApplied > 1
74
- ? `Showing every ${e.decimationApplied}th extrusion segment (layer boundaries kept); ` +
86
+ ? `Showing every ${ordinal(e.decimationApplied)} extrusion segment (layer boundaries kept); ` +
75
87
  `travel hidden. ${e.segments.toLocaleString()} segments drawn.`
76
88
  : ''
77
89
  });
@@ -144,7 +156,7 @@ export function createPreviewController(options = {}) {
144
156
  if ((r.mode ?? '3d') === '2d') {
145
157
  // The 2D renderer is a static (three-free) import — construct synchronously.
146
158
  applyRendererReady(canvas, new LayerView2DRenderer(canvas, {
147
- colorMode: r.colorMode,
159
+ colorMode: resolveColorMode(requestedColorMode, lastMetadata, lastIR),
148
160
  adjacentLayers: r.adjacentLayers,
149
161
  ghostOpacity: r.ghostOpacity
150
162
  }));
@@ -162,7 +174,7 @@ export function createPreviewController(options = {}) {
162
174
  cameraMode: r.cameraMode,
163
175
  frameContent: r.frameContent,
164
176
  interactionQuality: r.interactionQuality,
165
- colorMode: r.colorMode,
177
+ colorMode: resolveColorMode(requestedColorMode, lastMetadata, lastIR),
166
178
  tube: r.tube,
167
179
  theme: r.theme,
168
180
  createRenderer: r.createRenderer,
@@ -205,6 +217,7 @@ export function createPreviewController(options = {}) {
205
217
  try {
206
218
  const result = await run;
207
219
  lastIR = result.ir;
220
+ lastMetadata = result.metadata;
208
221
  lastMachine = result.metadata?.machine;
209
222
  mapper = createProgressMapper(result.ir, { fileSizeBytes: bytes });
210
223
  // Time axis (#181): prefer the slicer's own estimate (#183) for the total; the kinematic axis
@@ -216,8 +229,15 @@ export function createPreviewController(options = {}) {
216
229
  const counts = renderer !== null
217
230
  ? { layerCount: renderer.layerCount, segmentCount: renderer.segmentCount }
218
231
  : { layerCount: result.ir.layers.length, segmentCount: result.ir.segments.count };
219
- if (renderer !== null)
232
+ if (renderer !== null) {
233
+ // Resolve a `filament` colour request against THIS file's metadata BEFORE the build, so the first
234
+ // visible pass is already coloured from the source's own filament colours — no neutral-then-recolor
235
+ // flash (DD-024). A pass-through mode is unchanged.
236
+ if (requestedColorMode?.mode === 'filament') {
237
+ renderer.setColorMode(resolveColorMode(requestedColorMode, result.metadata, result.ir));
238
+ }
220
239
  renderer.setIR(result.ir);
240
+ }
221
241
  mutate({
222
242
  summary: {
223
243
  segments: result.ir.segments.count,
@@ -282,9 +302,13 @@ export function createPreviewController(options = {}) {
282
302
  // Availability is IR/renderer-dependent; before the renderer is ready we optimistically queue
283
303
  // and report true (the mode applies once bound). Callers can re-check after `parse-complete`.
284
304
  setColorMode: (m) => {
305
+ // Remember the request so a `filament` mode re-resolves per file; resolve it against the current
306
+ // metadata before handing the concrete mode to the renderer (DD-024).
307
+ requestedColorMode = m;
308
+ const resolved = (resolveColorMode(m, lastMetadata, lastIR) ?? m);
285
309
  if (renderer !== null)
286
- return renderer.setColorMode(m);
287
- pendingOps.push((r) => r.setColorMode(m));
310
+ return renderer.setColorMode(resolved);
311
+ pendingOps.push((r) => r.setColorMode(resolved));
288
312
  return true;
289
313
  },
290
314
  setQuality: (q) => withRenderer((r) => r.setQuality(q)),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chestnutlabs/gcode-preview-core",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Framework-neutral preview controller for the Chestnut Labs G-code viewer (DD-007 §4.6): the shared engine glue, state model, and TypeScript contracts beneath the Vue/React/Svelte adapters.",
5
5
  "keywords": [
6
6
  "gcode",
@@ -52,9 +52,9 @@
52
52
  "test": "vitest run"
53
53
  },
54
54
  "dependencies": {
55
- "@chestnutlabs/gcode-parser": "0.11.0",
56
- "@chestnutlabs/gcode-renderer-2d": "0.11.0",
57
- "@chestnutlabs/gcode-renderer-three": "0.11.0",
58
- "@chestnutlabs/toolpath-core": "0.11.0"
55
+ "@chestnutlabs/gcode-parser": "0.13.0",
56
+ "@chestnutlabs/gcode-renderer-2d": "0.13.0",
57
+ "@chestnutlabs/gcode-renderer-three": "0.13.0",
58
+ "@chestnutlabs/toolpath-core": "0.13.0"
59
59
  }
60
60
  }