Skip to content

Read per-path extrusion width and line height from slicer comments - #458

Merged
sophiedeziel merged 6 commits into
developfrom
interpreter-line-width-height
Sep 7, 2026
Merged

sophiedeziel merged 6 commits into
developfrom
interpreter-line-width-height

Conversation

@sophiedeziel

@sophiedeziel sophiedeziel commented Sep 7, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Prints sliced with adaptive layer height render as uniform 0.2 mm slabs, because every path is built with the same hardcoded dimensions. PrusaSlicer-family slicers (PrusaSlicer, SuperSlicer, OrcaSlicer, Bambu Studio) already announce the truth in ;WIDTH: / ;HEIGHT: comments, so this reads them through the slicer metadata pipeline rather than teaching the interpreter about comments.

The comments are line-indexed rather than folded into the per-layer metadata: width changes many times within a layer (33,168 times in the bundled 3DBenchy), so per-layer granularity would not fit. A dimension change breaks the current path lazily, at the next move rather than at the comment, because the interpreter resumes the last path at every streaming chunk boundary — an eager break would be undone and streamed output would diverge from one-shot.

Ref #96. #461 and #462 are stacked on this.

Behavior changes

  • Global lineHeight / extrusionWidth are now a fallback, not an override. Precedence per path: slicer value → global setting → built-in 0.6 / 0.2. A file that carries dimension comments ignores the global settings, so the demo's extrusion-width slider no longer affects it (relabelled accordingly). Files without the comments render byte-identically to before.
  • Dimension comments no longer identify a slicer. Slic3r emits the same dialect, and since the Prusa-family parser is tried first it was claiming those files and losing Slic3r's own layer markers.

Public API changes

  • SceneManager.lineHeight getter is now number | undefined — breaking for TypeScript consumers who annotate it as number. It has to be able to report "unset", which is what lets a path's own height win.
  • Path.extrusionWidth / Path.lineHeight are now optional (undefined = the slicer announced none); new Path.DEFAULT_EXTRUSION_WIDTH / DEFAULT_LINE_HEIGHT constants expose the built-in values.
  • Path.geometry options renamed extrusionWidthOverride → extrusionWidthFallback (same for height), with inverted semantics. No @deprecated alias: an alias would have to keep the old precedence to be meaningful, which is the behavior being replaced.
  • New ExtrusionDimensionMetadata type, Metadata.extrusionDimensions, and an overridable SlicerMetadataParser.parseExtrusionDimensions that defaults to reporting none.

Screenshots

Calibration cube sliced with adaptive layer heights (0.07–0.33 mm), same camera:

Before After
develop: uniform 0.2 mm layers with air gaps where the real layers are thicker this PR: per-path heights and widths, solid surface

close-up: ~0.3 mm beads at the rim, ~0.07 mm bands through the numerals

Checks

  • npm run check passes (test + typeCheck + lint)
  • npm run test:coverage — src/ still at 100%
  • Labelled appropriately (enhancement)

Assisted by Claude Code - Fable 5

@sophiedeziel sophiedeziel added the enhancement Improvement to an existing feature label Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

Visit the preview URL for this PR (updated for commit 39961eb):

https://gcode-preview--pr458-interpreter-line-wid-kx9lalpy.web.app

(expires Wed, 07 Oct 2026 18:01:52 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 59bd114ae4847b32c2bba0b68620b9069a3e3531

Comment thread src/parser/prusa-family-parser.ts Fixed
@sophiedeziel sophiedeziel added parser Related to G-code parsing renderer Related to rendering and the three.js scene labels Sep 7, 2026
- Parse standalone ;WIDTH:/;HEIGHT: comments (PrusaSlicer, SuperSlicer,
  OrcaSlicer, Bambu Studio) in a new interpreter comment handler and track
  the values on the job state, so adaptive-layer-height prints render each
  path with its true dimensions instead of the hardcoded 0.6/0.2
- Break the in-progress path lazily at the next move when the state
  dimensions changed (Job.continuePath), which keeps streamed parses
  identical to one-shot parses across chunk boundaries
- Make ObjectsManager.lineHeight optional, mirroring extrusionWidth:
  unset means each path renders with its own height (tubes and the line
  midplane offset); an explicitly set global value overrides as before
- Files without dimension comments are unaffected: paths keep defaulting
  to 0.6/0.2
- Security-review hardening: the value capture is now a strict decimal
  pattern, so ;WIDTH:0.45mm is ignored instead of parseFloat silently
  truncating it to 0.45
Reworks the ;WIDTH:/;HEIGHT: support after review feedback: no comment
command in the interpreter — the dimensions ride the same metadata
pipeline the layer comments already use, and become per-path values
that take precedence over the global settings.

- Delete the interpreter comment handler; PrusaFamilyMetadataParser
  gains parseExtrusionDimensions (with a base-class default reporting
  none), reported as line-indexed events with sub-layer granularity,
  accumulated across streaming chunks with whole-file line indices like
  the layer metadata
- ;WIDTH:/;HEIGHT: now also identify the Prusa family dialect
- Job.beginCommand, called by the interpreter once per command, maps
  the line-indexed events onto the command stream and folds them into
  the state; path breaking stays lazy at the next move (continuePath),
  keeping streamed parses identical to one-shot parses
- Precedence flip: a path's own dimensions (from metadata) win, the
  global lineHeight/extrusionWidth settings fill in for paths without
  them, and the built-in 0.6/0.2 defaults apply last — paths and state
  now leave dimensions undefined until metadata announces them
- CodeQL flagged js/polynomial-redos on the strict numeric capture:
  the ambiguous adjacent digit runs in \d*\.?\d+ backtrack
  quadratically on long digit strings with a non-matching tail
- \d+(?:\.\d+)? fails in linear time; exponent notation is dropped
  too, since the dialect never emits it — overflow-to-Infinity is
  still rejected by the finiteness check
@sophiedeziel
sophiedeziel force-pushed the interpreter-line-width-height branch from bc5b773 to e64eced Compare September 7, 2026 16:24
;WIDTH:/;HEIGHT: were added to the PrusaSlicer family's identification
patterns, but Slic3r -- which PrusaSlicer was forked from -- emits the
same comments in its verbose gcode. The family parser is tried first, so
a file whose header says "generated by Slic3r" was claimed by it anyway,
and Slic3r's own layer markers (;move to next layer) then went unparsed.

The generator comments already identify the family; the dimension
comments identify no single slicer. Test fixtures that leaned on them to
be detected now carry a generator comment, like real files do.

Also labels the demo's extrusion width control as a fallback: paths that
carry a ;WIDTH: of their own ignore it, which is every bundled demo file
except the two CNC ones (3DBenchy alone has 33,168 of them).
A slicer emits one dimension comment per extrusion -- 33,168 of them in
the bundled 3DBenchy -- and every comment in the file is offered to this
pattern. The capture arrays were a fifth of the scan's cost, and both
captured values are recoverable for less: the leading letter says which
dimension it is, and the pattern has already vouched for everything past
the colon being the number.

A first-character check now rejects the other comments before the
pattern runs. Measured on the bundled files, the scan is 14-23% faster
and its output byte-identical; against the whole parse the gain is
0.4 ms of ~55 ms, below the noise floor.
@sophiedeziel
sophiedeziel merged commit ed42e9e into develop Sep 7, 2026
7 checks passed
@sophiedeziel
sophiedeziel deleted the interpreter-line-width-height branch September 7, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Improvement to an existing feature parser Related to G-code parsing renderer Related to rendering and the three.js scene

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants