@chestnutlabs/toolpath-core 0.1.0 → 0.3.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
@@ -2,7 +2,7 @@
2
2
 
3
3
  Neutral **`ToolpathIR`** and **capability model** for the Chestnut Labs G-code Preview toolpath stack.
4
4
  This is the replacement seam for the whole stack: the parser **writes** it, renderers and analyzers **read**
5
- it. See [`docs/design/DD-001`](../../docs/design/DD-001-toolpath-ir-and-capability-model.md).
5
+ it. See [`docs/design/DD-001`](https://github.com/ChestnutLabs/gcode-preview/blob/dev/docs/design/DD-001-toolpath-ir-and-capability-model.md).
6
6
 
7
7
  **Design rules**
8
8
 
package/dist/builder.d.ts CHANGED
@@ -59,10 +59,30 @@ export declare class ToolpathIRBuilder {
59
59
  private readonly srcByte;
60
60
  private readonly toolsMap;
61
61
  private readonly objectsList;
62
+ private readonly retractionsList;
63
+ private readonly colorChangesList;
62
64
  private readonly warnings;
63
65
  private readonly capabilities;
64
66
  constructor(opts?: BuilderOptions);
65
67
  addSegment(s: SegmentInput): void;
68
+ /** Record a retraction/unretraction event (DD-009 D1, #148). Position is absolute; stored origin-relative. */
69
+ addRetraction(r: {
70
+ x: number;
71
+ y: number;
72
+ z: number;
73
+ kind: 'retract' | 'unretract';
74
+ srcByte: number;
75
+ segIndex: number;
76
+ }): void;
77
+ /** Record an M600 color-change boundary (DD-009 D2, #147). Position is absolute; stored origin-relative. */
78
+ addColorChange(c: {
79
+ x: number;
80
+ y: number;
81
+ z: number;
82
+ segIndex: number;
83
+ srcByte: number;
84
+ tool: number;
85
+ }): void;
66
86
  addWarning(w: Warning): void;
67
87
  setCapability(name: string, confidence: Confidence): void;
68
88
  setTool(info: ToolInfo): void;
@@ -1 +1 @@
1
- {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,UAAU,EAIf,KAAK,KAAK,EACV,KAAK,IAAI,EACT,KAAK,OAAO,EACb,MAAM,SAAS,CAAC;AAIjB,0GAA0G;AAC1G,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,6CAA6C;IAC7C,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,MAAM,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,oFAAoF;IACpF,YAAY,CAAC,EAAE,IAAI,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiB;IACtC,OAAO,CAAC,YAAY,CAAc;IAElC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAgB;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IAExC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+B;IACxD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;gBAEnD,IAAI,GAAE,cAAmB;IAKrC,UAAU,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI;IAwBjC,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI;IAI5B,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI;IAIzD,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAI7B,sFAAsF;IACtF,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM;IAKnC,QAAQ,IAAI,UAAU;CA4CvB"}
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,UAAU,EAEf,KAAK,QAAQ,EACb,KAAK,UAAU,EAIf,KAAK,KAAK,EACV,KAAK,IAAI,EACT,KAAK,OAAO,EACb,MAAM,SAAS,CAAC;AAIjB,0GAA0G;AAC1G,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,6CAA6C;IAC7C,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,MAAM,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,oFAAoF;IACpF,YAAY,CAAC,EAAE,IAAI,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiB;IACtC,OAAO,CAAC,YAAY,CAAc;IAElC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAgB;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IAExC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+B;IACxD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;IAChD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAyB;IACzD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA0B;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;gBAEnD,IAAI,GAAE,cAAmB;IAKrC,UAAU,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI;IAwBjC,8GAA8G;IAC9G,aAAa,CAAC,CAAC,EAAE;QACf,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,IAAI,EAAE,SAAS,GAAG,WAAW,CAAC;QAC9B,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,IAAI;IAYR,4GAA4G;IAC5G,cAAc,CAAC,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAY7G,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI;IAI5B,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI;IAIzD,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAI7B,sFAAsF;IACtF,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM;IAKnC,QAAQ,IAAI,UAAU;CAuDvB"}
package/dist/builder.js CHANGED
@@ -28,6 +28,8 @@ export class ToolpathIRBuilder {
28
28
  srcByte = [];
29
29
  toolsMap = new Map();
30
30
  objectsList = [];
31
+ retractionsList = [];
32
+ colorChangesList = [];
31
33
  warnings = [];
32
34
  capabilities = {};
33
35
  constructor(opts = {}) {
@@ -57,6 +59,30 @@ export class ToolpathIRBuilder {
57
59
  this.toolsMap.set(s.tool, { id: s.tool });
58
60
  }
59
61
  }
62
+ /** Record a retraction/unretraction event (DD-009 D1, #148). Position is absolute; stored origin-relative. */
63
+ addRetraction(r) {
64
+ const o = this.originOffset ?? { x: 0, y: 0, z: 0 };
65
+ this.retractionsList.push({
66
+ x: r.x - o.x,
67
+ y: r.y - o.y,
68
+ z: r.z - o.z,
69
+ kind: r.kind,
70
+ srcByte: r.srcByte,
71
+ segIndex: r.segIndex
72
+ });
73
+ }
74
+ /** Record an M600 color-change boundary (DD-009 D2, #147). Position is absolute; stored origin-relative. */
75
+ addColorChange(c) {
76
+ const o = this.originOffset ?? { x: 0, y: 0, z: 0 };
77
+ this.colorChangesList.push({
78
+ x: c.x - o.x,
79
+ y: c.y - o.y,
80
+ z: c.z - o.z,
81
+ segIndex: c.segIndex,
82
+ srcByte: c.srcByte,
83
+ tool: c.tool
84
+ });
85
+ }
60
86
  addWarning(w) {
61
87
  this.warnings.push(w);
62
88
  }
@@ -111,7 +137,18 @@ export class ToolpathIRBuilder {
111
137
  capabilities: this.capabilities
112
138
  };
113
139
  const tools = [...this.toolsMap.values()].sort((a, b) => a.id - b.id);
114
- return { header, segments, layers, tools, objects: this.objectsList, bounds, boundsWithTravel, sourceIndex };
140
+ return {
141
+ header,
142
+ segments,
143
+ layers,
144
+ tools,
145
+ objects: this.objectsList,
146
+ retractions: this.retractionsList,
147
+ colorChanges: this.colorChangesList,
148
+ bounds,
149
+ boundsWithTravel,
150
+ sourceIndex
151
+ };
115
152
  }
116
153
  }
117
154
  /** Group segments into layers by their `layer` index; layer Z is absolute. Assumes dense layer indices. */
package/dist/index.d.ts CHANGED
@@ -11,4 +11,6 @@ export * from './bounds.js';
11
11
  export * from './source-index.js';
12
12
  export * from './metadata.js';
13
13
  export * from './progress.js';
14
+ export * from './time.js';
15
+ export * from './source-map.js';
14
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -11,3 +11,5 @@ export * from './bounds.js';
11
11
  export * from './source-index.js';
12
12
  export * from './metadata.js';
13
13
  export * from './progress.js';
14
+ export * from './time.js';
15
+ export * from './source-map.js';
package/dist/ir.d.ts CHANGED
@@ -126,6 +126,43 @@ export interface ObjectInfo {
126
126
  id: string;
127
127
  name?: string;
128
128
  }
129
+ /**
130
+ * A filament retraction (`retract`) or its reversal (`unretract`) — an E-only move
131
+ * with no XYZ travel, so it has a *position* but no segment in the main stream
132
+ * (DD-009 D1 amendment, #148). Kept in a sparse side channel so segment indices,
133
+ * scrub, and layer ranges are untouched. `segIndex` is the index of the next
134
+ * segment emitted after the event, for layer/scrub-aligned marker clipping.
135
+ */
136
+ export interface RetractionEvent {
137
+ /** Position (same frame as segments: origin-relative). */
138
+ x: number;
139
+ y: number;
140
+ z: number;
141
+ kind: 'retract' | 'unretract';
142
+ /** Byte offset in the source for scrub/telemetry alignment. */
143
+ srcByte: number;
144
+ /** Segment index at the moment of the event (draw-range clip alignment). */
145
+ segIndex: number;
146
+ }
147
+ /**
148
+ * A manual filament-swap color boundary (`M600`) — a marker with a *position* but
149
+ * no motion segment (DD-009 D2 amendment, #147). Like {@link RetractionEvent} it is
150
+ * kept in a sparse side channel so segment indices, scrub, and layer ranges are
151
+ * untouched. The renderer's `colorChange` color mode shades segments by *swap slot*
152
+ * (the count of color changes at or before a segment), NOT by the `tool` channel.
153
+ */
154
+ export interface ColorChangeEvent {
155
+ /** Position (same frame as segments: origin-relative). */
156
+ x: number;
157
+ y: number;
158
+ z: number;
159
+ /** Index of the first segment emitted after the swap (slot boundary + marker clip). */
160
+ segIndex: number;
161
+ /** Byte offset in the source for scrub/telemetry alignment. */
162
+ srcByte: number;
163
+ /** Tool active at the swap — provenance only; not used to pick the swap color. */
164
+ tool: number;
165
+ }
129
166
  export interface ToolpathBounds {
130
167
  min: Vec3;
131
168
  max: Vec3;
@@ -141,6 +178,10 @@ export interface ToolpathIR {
141
178
  layers: ToolpathLayer[];
142
179
  tools: ToolInfo[];
143
180
  objects: ObjectInfo[];
181
+ /** Sparse retraction/unretraction events (DD-009 D1, #148); empty when none seen. */
182
+ retractions: RetractionEvent[];
183
+ /** Sparse M600 filament-swap color-change boundaries (DD-009 D2, #147); empty when none seen. */
184
+ colorChanges: ColorChangeEvent[];
144
185
  /** Bounds over extruding moves only. */
145
186
  bounds: ToolpathBounds;
146
187
  /** Bounds including travel moves. */
package/dist/ir.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ir.d.ts","sourceRoot":"","sources":["../src/ir.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ir.d.ts","sourceRoot":"","sources":["../src/ir.ts"],"names":[],"mappings":"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"}
@@ -64,6 +64,39 @@ export interface FilamentInfo {
64
64
  color?: string;
65
65
  name?: string;
66
66
  }
67
+ /**
68
+ * Slicer-reported filament consumption (#183) — the "info panel" totals a slicer emits as G-code
69
+ * comments. Absent when the slicer doesn't report it (capability-honest). Aggregate across extruders;
70
+ * fields are independently optional (a slicer may report length but not weight).
71
+ */
72
+ export interface FilamentUsage {
73
+ /** Total filament length in millimetres. */
74
+ lengthMm?: number;
75
+ /** Total extruded volume in cm³. */
76
+ volumeCm3?: number;
77
+ /** Total filament weight in grams. */
78
+ weightG?: number;
79
+ source: {
80
+ adapterId: string;
81
+ evidence: string;
82
+ srcByte?: number;
83
+ };
84
+ }
85
+ /**
86
+ * The slicer's own print-time estimate (#183) — the trustworthy figure for a time readout / time
87
+ * scrub, versus a kinematic estimate. Absent when the slicer doesn't emit it.
88
+ */
89
+ export interface PrintEstimate {
90
+ /** Estimated print duration in seconds. */
91
+ seconds: number;
92
+ /** Slicer mode label when given (e.g. PrusaSlicer 'normal' / 'silent'). */
93
+ mode?: string;
94
+ source: {
95
+ adapterId: string;
96
+ evidence: string;
97
+ srcByte?: number;
98
+ };
99
+ }
67
100
  export interface ThumbnailData {
68
101
  width: number;
69
102
  height: number;
@@ -80,6 +113,10 @@ export interface DialectMetadata {
80
113
  dialects?: DialectDetection[];
81
114
  machine?: MachineGeometry;
82
115
  filaments?: FilamentInfo[];
116
+ /** Slicer-reported total filament consumption (#183); absent when not emitted. */
117
+ filamentUsage?: FilamentUsage;
118
+ /** The slicer's own print-time estimate (#183); absent when not emitted. */
119
+ printEstimate?: PrintEstimate;
83
120
  thumbnails?: ThumbnailData[];
84
121
  /** Whitelisted key/value settings only — bounded, never local paths. */
85
122
  raw?: Record<string, string>;
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,MAAM,WAAW,MAAM;IACrB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,gEAAgE;AAChE,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,EACC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAC1C;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GACtD;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC1C,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,UAAU,EAAE,UAAU,CAAC;IACvB,oEAAoE;IACpE,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACnE;AAED,oEAAoE;AACpE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IACxC,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B"}
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Source-line ↔ segment mapping (#184) — the "G-code debugger" surface: resolve a rendered segment
3
+ * to the G-code line that produced it, and a source line back to its segment. Framework-free and
4
+ * built on data the IR already carries (`segments.srcByte`, the byte→segment `sourceIndex`); the only
5
+ * missing piece is byte↔line, which needs the source text (the IR stores byte offsets, not lines).
6
+ *
7
+ * Build a {@link SourceLineIndex} once from the source, then all four lookups are O(log n).
8
+ */
9
+ import { type SourceIndex } from './ir.js';
10
+ /** Byte offsets of each line start (index 0 = line 1 at byte 0), plus the total length. */
11
+ export interface SourceLineIndex {
12
+ /** `lineStarts[k]` is the byte offset where line `k + 1` begins. */
13
+ lineStarts: Uint32Array;
14
+ /** Total source length in bytes. */
15
+ byteLength: number;
16
+ }
17
+ /** Build the line index from the raw source (string or the parsed bytes). O(bytes), one pass. */
18
+ export declare function buildSourceLineIndex(source: string | Uint8Array): SourceLineIndex;
19
+ /** 1-based line number containing `byteOffset` (binary search). Clamped to [1, lineCount]. */
20
+ export declare function lineAtByte(index: SourceLineIndex, byteOffset: number): number;
21
+ /** Byte range `[start, end)` of a 1-based `line`; null when out of range. `end` excludes the newline-led next line. */
22
+ export declare function byteRangeOfLine(index: SourceLineIndex, line: number): [number, number] | null;
23
+ /** 1-based source line that produced segment `segIndex`; null when the index is out of range. */
24
+ export declare function sourceLineOfSegment(srcByte: Uint32Array, lineIndex: SourceLineIndex, segIndex: number): number | null;
25
+ /**
26
+ * The segment produced by a 1-based source `line`, or -1 when the line produced no segment (a comment,
27
+ * a blank line, or a non-motion command). Resolves to the first segment whose source byte falls within
28
+ * the line's byte range.
29
+ */
30
+ export declare function segmentAtSourceLine(sourceIndex: SourceIndex, lineIndex: SourceLineIndex, line: number): number;
31
+ //# sourceMappingURL=source-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-map.d.ts","sourceRoot":"","sources":["../src/source-map.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,2FAA2F;AAC3F,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,UAAU,EAAE,WAAW,CAAC;IACxB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,iGAAiG;AACjG,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,eAAe,CAYjF;AAED,8FAA8F;AAC9F,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAe7E;AAED,uHAAuH;AACvH,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAM7F;AAED,iGAAiG;AACjG,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGrH;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAiB9G"}
@@ -0,0 +1,74 @@
1
+ /** Build the line index from the raw source (string or the parsed bytes). O(bytes), one pass. */
2
+ export function buildSourceLineIndex(source) {
3
+ // TextEncoder is a runtime global (browser + Node); reach it via globalThis so this DOM-free
4
+ // package (lib: ES2022, types: []) typechecks without pulling the DOM lib.
5
+ const Enc = globalThis.TextEncoder;
6
+ const bytes = typeof source === 'string' ? new Enc().encode(source) : source;
7
+ const starts = [0];
8
+ // A trailing '\n' ends the last line rather than starting an empty new one (editor convention),
9
+ // so only record a start when bytes follow the newline.
10
+ for (let i = 0; i < bytes.length; i++) {
11
+ if (bytes[i] === 0x0a /* \n */ && i + 1 < bytes.length)
12
+ starts.push(i + 1);
13
+ }
14
+ return { lineStarts: Uint32Array.from(starts), byteLength: bytes.length };
15
+ }
16
+ /** 1-based line number containing `byteOffset` (binary search). Clamped to [1, lineCount]. */
17
+ export function lineAtByte(index, byteOffset) {
18
+ const starts = index.lineStarts;
19
+ let lo = 0;
20
+ let hi = starts.length - 1;
21
+ let ans = 0;
22
+ while (lo <= hi) {
23
+ const mid = (lo + hi) >> 1;
24
+ if (starts[mid] <= byteOffset) {
25
+ ans = mid;
26
+ lo = mid + 1;
27
+ }
28
+ else {
29
+ hi = mid - 1;
30
+ }
31
+ }
32
+ return ans + 1; // 1-based
33
+ }
34
+ /** Byte range `[start, end)` of a 1-based `line`; null when out of range. `end` excludes the newline-led next line. */
35
+ export function byteRangeOfLine(index, line) {
36
+ const starts = index.lineStarts;
37
+ if (line < 1 || line > starts.length)
38
+ return null;
39
+ const start = starts[line - 1];
40
+ const end = line < starts.length ? starts[line] : index.byteLength;
41
+ return [start, end];
42
+ }
43
+ /** 1-based source line that produced segment `segIndex`; null when the index is out of range. */
44
+ export function sourceLineOfSegment(srcByte, lineIndex, segIndex) {
45
+ if (segIndex < 0 || segIndex >= srcByte.length)
46
+ return null;
47
+ return lineAtByte(lineIndex, srcByte[segIndex]);
48
+ }
49
+ /**
50
+ * The segment produced by a 1-based source `line`, or -1 when the line produced no segment (a comment,
51
+ * a blank line, or a non-motion command). Resolves to the first segment whose source byte falls within
52
+ * the line's byte range.
53
+ */
54
+ export function segmentAtSourceLine(sourceIndex, lineIndex, line) {
55
+ const range = byteRangeOfLine(lineIndex, line);
56
+ if (range === null)
57
+ return -1;
58
+ // Smallest indexed byte >= range start whose byte is < range end.
59
+ const offsets = sourceIndex.byteOffsets;
60
+ let lo = 0;
61
+ let hi = offsets.length;
62
+ while (lo < hi) {
63
+ const mid = (lo + hi) >>> 1;
64
+ if (offsets[mid] < range[0])
65
+ lo = mid + 1;
66
+ else
67
+ hi = mid;
68
+ }
69
+ if (lo < offsets.length && offsets[lo] >= range[0] && offsets[lo] < range[1]) {
70
+ return sourceIndex.segmentIndices[lo];
71
+ }
72
+ // The line produced no segment (comment, blank, or a non-motion command) — honestly -1.
73
+ return -1;
74
+ }
package/dist/time.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Kinematic time axis over the IR (#181) — a per-segment duration model for a time readout and
3
+ * time-based scrubbing, derived from geometry the IR already carries.
4
+ *
5
+ * Each segment's duration is its 3D length divided by its feedrate (`feedrate` is mm/min). This is a
6
+ * **kinematic estimate**: constant-velocity per segment, NOT acceleration/jerk-aware, so it slightly
7
+ * *under*estimates real print time. A segment with an unknown feedrate (NaN, before the first `F`)
8
+ * contributes zero and flags the estimate as approximate — never a fabricated duration. When the
9
+ * slicer's own estimate is available (`DialectMetadata.printEstimate`, #183), prefer it; this is the
10
+ * honest fallback and the axis time-scrub always needs.
11
+ */
12
+ import type { ToolpathIR } from './ir.js';
13
+ export interface ToolpathTime {
14
+ /** Cumulative END time (ms) of each segment; length = `segments.count`, monotonic non-decreasing. */
15
+ cumulativeMs: Float64Array;
16
+ /** Total kinematic duration (ms). */
17
+ totalMs: number;
18
+ /**
19
+ * True if any moving segment had an unknown feedrate (contributed 0). The estimate is then a lower
20
+ * bound / approximate — a consumer should disclose it (and prefer the slicer estimate when present).
21
+ */
22
+ hasUnknownFeedrate: boolean;
23
+ }
24
+ /** Build the cumulative kinematic time axis for `ir`. O(segments), no allocation beyond the axis. */
25
+ export declare function computeToolpathTime(ir: ToolpathIR): ToolpathTime;
26
+ /**
27
+ * The number of segments completed at time `ms` — i.e. the count of segments whose cumulative END
28
+ * time is ≤ `ms` (binary search). 0 before the first segment finishes; `count` at/after the end. This
29
+ * is exactly a scrub cut position (segments `[0, result)` are done), so it maps straight to a
30
+ * segment-index scrub.
31
+ */
32
+ export declare function segmentsCompletedAtTime(cumulativeMs: Float64Array, ms: number): number;
33
+ //# sourceMappingURL=time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../src/time.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,MAAM,WAAW,YAAY;IAC3B,qGAAqG;IACrG,YAAY,EAAE,YAAY,CAAC;IAC3B,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AAED,qGAAqG;AACrG,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,UAAU,GAAG,YAAY,CAoBhE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAStF"}
package/dist/time.js ADDED
@@ -0,0 +1,41 @@
1
+ /** Build the cumulative kinematic time axis for `ir`. O(segments), no allocation beyond the axis. */
2
+ export function computeToolpathTime(ir) {
3
+ const seg = ir.segments;
4
+ const n = seg.count;
5
+ const cumulativeMs = new Float64Array(n);
6
+ let t = 0;
7
+ let hasUnknownFeedrate = false;
8
+ for (let i = 0; i < n; i++) {
9
+ const dx = seg.x1[i] - seg.x0[i];
10
+ const dy = seg.y1[i] - seg.y0[i];
11
+ const dz = seg.z1[i] - seg.z0[i];
12
+ const dist = Math.hypot(dx, dy, dz);
13
+ const f = seg.feedrate[i]; // mm/min
14
+ if (Number.isFinite(f) && f > 0) {
15
+ t += dist / (f / 60000); // mm ÷ (mm/ms) = ms
16
+ }
17
+ else if (dist > 0) {
18
+ hasUnknownFeedrate = true;
19
+ }
20
+ cumulativeMs[i] = t;
21
+ }
22
+ return { cumulativeMs, totalMs: t, hasUnknownFeedrate };
23
+ }
24
+ /**
25
+ * The number of segments completed at time `ms` — i.e. the count of segments whose cumulative END
26
+ * time is ≤ `ms` (binary search). 0 before the first segment finishes; `count` at/after the end. This
27
+ * is exactly a scrub cut position (segments `[0, result)` are done), so it maps straight to a
28
+ * segment-index scrub.
29
+ */
30
+ export function segmentsCompletedAtTime(cumulativeMs, ms) {
31
+ let lo = 0;
32
+ let hi = cumulativeMs.length;
33
+ while (lo < hi) {
34
+ const mid = (lo + hi) >>> 1;
35
+ if (cumulativeMs[mid] <= ms)
36
+ lo = mid + 1;
37
+ else
38
+ hi = mid;
39
+ }
40
+ return lo;
41
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chestnutlabs/toolpath-core",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Neutral ToolpathIR and capability model for the Chestnut Labs G-code Preview toolpath stack.",
5
5
  "keywords": [
6
6
  "gcode",