Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
39d7cd1
docs: DD-017 Phase 4 — parametric-programs capability/disclosure surf…
sobechestnut-dev Aug 28, 2026
32cb0ea
tools(screenshots): manifest-driven harness + mid-grey documentation …
sobechestnut-dev Aug 28, 2026
f6f1fcd
docs(media): add parametric, non-rect bed, and tubes/lines shots + de…
sobechestnut-dev Aug 28, 2026
755c0ac
release: enforce Public-Product/Docs/Visual review + fix Pages media/…
sobechestnut-dev Aug 28, 2026
95d8f95
merge: release Public-Product/Docs/Visual review gate + Pages media/t…
sobechestnut-dev Aug 28, 2026
3e1a476
docs: visual Pages homepage + feature gallery; README brought current
sobechestnut-dev Aug 28, 2026
06ec4ee
demo: expose capture(), render diagnostics, progressive, speed/object…
sobechestnut-dev Aug 28, 2026
c4b3815
docs(coverage): record this pass's coverage delta + honest remainder
sobechestnut-dev Aug 28, 2026
0605ca2
chore: prettier-format harness; ignore generated docs-site in prettier
sobechestnut-dev Aug 28, 2026
c61ba31
Merge pull request #421 from ChestnutLabs/docs/public-product-pass-v2
sobechestnut-dev Aug 28, 2026
4f6b3a3
docs(media): wire up scrub + progressive (layer-buildup) animations
sobechestnut-dev Aug 28, 2026
3d257d5
Merge pull request #422 from ChestnutLabs/docs/scrub-progressive-anim…
sobechestnut-dev Aug 28, 2026
81690dc
feat(renderer): setFeatureRoleVisible — show/hide a single feature role
sobechestnut-dev Aug 28, 2026
1fcceb9
docs(renderer): drop broken {@link FeatureRole} in setFeatureRoleVisi…
sobechestnut-dev Aug 28, 2026
da2f4a0
Merge pull request #423 from ChestnutLabs/feat/set-feature-role-visible
sobechestnut-dev Aug 28, 2026
89cab13
docs(media): knock out the visual-coverage remainder
sobechestnut-dev Aug 28, 2026
fff155d
Merge pull request #425 from ChestnutLabs/docs/visual-remainder
sobechestnut-dev Aug 28, 2026
5e786fd
release: version packages (lockstep) (#424)
github-actions[bot] Aug 28, 2026
f0ceb0b
docs: fold v0.19.0 release notes + resolve the release review
sobechestnut-dev Aug 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
## Documentation
- [ ] User- and maintainer-facing docs updated in this PR (docs are part of the feature)
- [ ] Support matrix / migration notes updated, or N/A
- [ ] **Release promotion (`dev` → `main`) only:** `npm run docs:release-check` is green, the
`docs/README` current-state narrative + history name this version, `RELEASE_NOTES_DRAFT.md`
is folded in and deleted, and screenshots/guides were reviewed (CLAUDE.md public-docs
completion check) — or N/A for a normal `dev` PR.
- [ ] **Release promotion (`dev` → `main`) only:** `npm run docs:release-check` is green — the
`docs/README` current-state narrative + history name this version, `RELEASE_NOTES_DRAFT.md` is
folded in and deleted, and the enforced **`RELEASE_REVIEW.md`** (Public Product + Docs + Visual
review) is present for this version with every disposition resolved (each changed package
`reviewed` / `no-change-needed` / `not-applicable`; Product / Docs / Visual markers `resolved`).
The gate blocks promotion until it is — or N/A for a normal `dev` PR.

## Impact
- Security: <untrusted-input / limits impact, or none>
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/docs-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ on:
- 'packages/**'
- 'typedoc.json'
- 'tools/docs/**'
- 'docs/manual/**'
- 'docs/media/**'
- '.github/workflows/docs-pages.yml'
workflow_dispatch:

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# DD-008 D3 (#130): the ONLY path that publishes @chestnutlabs/* — a GitHub Release
# (tag vX.Y.Z) cut from `main`. Fresh install, every repository gate, then a
# dependency-ordered `npm publish` ×9 with npm provenance. Trusted publishing (OIDC)
# dependency-ordered `npm publish` ×14 with npm provenance. Trusted publishing (OIDC)
# is the intended auth; a granular NPM_TOKEN secret is the recorded fallback
# (DD-008 §4.3 — the @chestnutlabs scope is user-owned; org conversion deferred).
# No workstation publishing, ever.
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
dist
*.min.css
*.svelte
docs-site
23 changes: 16 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Project instructions for Claude Code and other agents working in this repository

A browser G-code / toolpath toolkit: parse `.gcode`, `.gcode.3mf`, and Prusa `.bgcode` off the main
thread into a neutral intermediate representation (`ToolpathIR`) and render it with Three.js or a
Canvas 2D fallback. It ships as 13 lockstep-versioned `@chestnutlabs/*` packages plus Vue, React,
Canvas 2D fallback. It ships as 14 lockstep-versioned `@chestnutlabs/*` packages plus Vue, React,
Svelte, and Web Component adapters over one shared engine. It began as a fork of
`xyz-tools/gcode-preview` — attribution and provenance are load-bearing (see `NOTICE.md`).

Expand Down Expand Up @@ -48,18 +48,27 @@ deliberate consideration is):

If visible behavior changed, regenerate the affected media with
[`tools/screenshots/`](tools/screenshots/README.md) rather than leaving a stale image in place.
Every user-facing feature is **visually documented somewhere** unless the visual coverage matrix
([`docs/VISUAL_FEATURE_COVERAGE.md`](docs/VISUAL_FEATURE_COVERAGE.md)) records why not — see the
visual standard in [`docs/USER_FACING_DOCS_STYLE.md`](docs/USER_FACING_DOCS_STYLE.md) §6/§8.

**Docs freshness is enforced at release time, not left as post-release cleanup.** The `version`
script auto-stamps the deterministic "vX.Y.Z is on npm" strings into the generated Version PR and
script auto-stamps the deterministic "vX.Y.Z is on npm" strings into the generated Version PR,
drops a `RELEASE_NOTES_DRAFT.md` to seed the `docs/README` "Current state" narrative + history
(fold it in, then delete it). The `Docs release gate` (`npm run docs:release-check`) then **blocks
the `dev` → `main` promotion** until every version surface, the current-state lead, and the
history list name the version being cut. Surfaces live in `tools/release/doc-surfaces.mjs`; the
flow is documented in [`docs/reference/release-process.md`](docs/reference/release-process.md).
(fold it in, then delete it), and generates `RELEASE_REVIEW.md` — a **per-release Public Product +
Documentation + Visual review** seeded from the changed-capability inventory (every package whose
`src/` changed since the previous tag). The `Docs release gate` (`npm run docs:release-check`) then
**blocks the `dev` → `main` promotion** until every version surface names the version being cut,
`RELEASE_NOTES_DRAFT.md` is gone, **and** `RELEASE_REVIEW.md` is present with every disposition
resolved (each changed package `reviewed` / `no-change-needed` / `not-applicable`, and the Product /
Docs / Visual markers `resolved`). This is enforcement, not a checkbox: reconcile the README, Pages
homepage, feature gallery, manual, demo/examples, screenshots, and the coverage matrix against the
inventory, then resolve the review. Surfaces live in `tools/release/doc-surfaces.mjs`; the flow is
documented in [`docs/reference/release-process.md`](docs/reference/release-process.md).

## Repo orientation

- `packages/*` — the 13 published packages (foundation → parse → color → render → adapters). Build
- `packages/*` — the 14 published packages (foundation → parse → color → render → adapters). Build
in dependency order; each package builds itself (`npm run build -w @chestnutlabs/<pkg>`).
- `docs/` — user manual (`manual/`), consumer references (`reference/`, `compatibility/`), and the
maintainer planning/design/research set.
Expand Down
65 changes: 61 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ live printer progress. Parsing runs in a Web Worker, so a 250 MB file never free
[![docs](https://img.shields.io/badge/docs-manual%20%2B%20API-2ea44f)](https://chestnutlabs.github.io/gcode-preview/)
![node](https://img.shields.io/badge/node-%E2%89%A522-339933)

![3DBenchy rendered as extrusion tubes with per-feature coloring — perimeters, infill, and skirt in distinct colors — on a dark build plate](docs/media/viewer-benchy-tubes.png)
![3DBenchy rendered as extrusion tubes with per-feature coloring — perimeters, infill, and skirt in distinct colors — on a neutral grey build plate](docs/media/viewer-benchy-tubes.png)

---

Expand Down Expand Up @@ -66,7 +66,8 @@ Every one of those maps to something the library actually does, below.
move, with a keyboard-operable slider.
- **Time scrub & print-time estimate** — scrub along the *time* axis and read an estimated print
time, labeled by provenance (the slicer's own estimate, or a kinematic approximation).
- **Feature inspection** — toggle travel, wipe, seam, and retraction/de-retraction markers.
- **Feature inspection** — toggle travel, wipe, seam, and retraction/de-retraction markers, or
**hide a whole feature role** (`setFeatureRoleVisible` — e.g. hide brim/skirt to declutter a part).
- **Source-line ↔ segment mapping** — go from a byte in the file to the segment it drew, and back.

### Live job progress
Expand Down Expand Up @@ -100,6 +101,18 @@ signal deserves**:
giving up final-frame fidelity. The hard GPU/vertex-budget fallback still applies underneath.
- **Degradation is disclosed** — over a large-file threshold the renderer decimates and *tells you*
the exact reduction factor rather than dropping detail silently.
- **Any build surface, not just a rectangle** — rectangular, **circular / delta**, and **polygonal**
beds render with the outline and grid following the real shape (`buildVolume.shape`).
- **Capture / export** — `capture()` returns the current view as a `Blob` (PNG/JPEG/WebP) from the
interactive viewer *or* the headless still, including a **transparent background** for compositing
onto cards — the same primitive behind server thumbnails and "save image".

<table>
<tr>
<td width="50%"><img src="docs/media/bed-circular.png" alt="A print rendered on a round, delta-style build plate — the bed outline and grid are circular, with the model centered on it"></td>
<td><b>Non-rectangular beds.</b> A circular (delta) or polygonal build surface draws its true outline and clips the grid to the shape, instead of forcing a rectangle. Pass a <code>shape</code> on the build volume; rectangular stays the default.</td>
</tr>
</table>

<table>
<tr>
Expand Down Expand Up @@ -132,6 +145,31 @@ a controller's semantic claims are reported `inferred` until confirmed on real h
— today **GRBL/LightBurn laser is hardware-validated**; GRBL-mill and LinuxCNC are experimental.
Geometry always parses regardless of tier.

#### Parametric programs (RS274NGC)

Some G-code doesn't spell out its geometry move by move — it **computes** it. A LinuxCNC / CAM
program can set variables, evaluate expressions as coordinates, loop, branch, and call subroutines,
so a bolt circle is a `while` loop over an angle instead of twelve explicit moves. The parser runs
that programming layer, so these files resolve to the **real toolpath** instead of rendering empty.

![A CNC toolpath of eight drilled holes on a circle plus a centre hole and a square frame, all computed by a parametric program, cut moves in pink and rapid moves in blue](docs/media/parametric-bolt-circle.png)

```gcode
o200 while [#<i> LT #<holes>]
#<a> = [#<i> * 360 / #<holes>]
G0 X[#<cx> + #<r> * COS[#<a>]] Y[#<cy> + #<r> * SIN[#<a>]] ; computed hole position
o100 call ; drill (subroutine)
#<i> = [#<i> + 1]
o200 endwhile
```

Parameters, expressions, `if` / `while` / `do` / `repeat` control flow, and in-file subroutines all
run — **bounded** (a hostile file can't hang the parser: `maxProgramIterations` / `maxCallDepth`) and
**honest** (a clean run reports `parametricProgram: 'known'`; a limit or unsupported construct drops
to `approximated` with a specific warning). It engages only on files that use `#` / `[` / O-words;
every FDM file is byte-for-byte unchanged. See
[Parametric programs](docs/manual/concept-parametric-programs.md).

### Framework integration

Four adapters over one engine, with matching options, events, and TypeScript types — enforced by a
Expand All @@ -148,6 +186,17 @@ shared behavioral test suite that runs against all four in CI:

- **Off-thread parsing** — a `GcodeParseSession` runs the parser in a Web Worker with streaming
input, progressive previews for large files, resource limits, and cancellation.
- **Parallel geometry build** — a geometry worker pool builds extrusion tubes off the main thread
(byte-identical to serial), bounded by a memory budget and degrading gracefully (pool → serial →
lines) with every step disclosed. Big plates stay responsive.
- **Preparation is staged, the reveal is clean** — a `stage` event walks
`parsing → classifying → building-geometry → preparing-gpu → ready` with a real build percentage,
and `progressivePreview: 'hold'` suppresses the half-built scene so the model appears in one clean
reveal instead of visibly growing.
- **Render diagnostics** — `getRenderStats()` reports what actually happened: backend and WebGL
version, hardware-vs-software GPU (unmasked renderer/vendor), geometry mode, rendered segment and
draw-call counts, whether decimation applied, worker count, and a timing breakdown — a ready-made
"what am I running on / why is this slow" panel, never fabricated.
- **Batteries-included worker** — the adapters wire up a worker with every dialect and `.gcode.3mf`
support via the bundler-native `new Worker(new URL(...))` pattern (Vite works out of the box); a
`createWorker` hook is the escape hatch for slim builds, custom dialects, or strict-CSP hosts.
Expand Down Expand Up @@ -201,6 +250,12 @@ multicolor) with camera presets and the same serializable camera state, over the
orbit controls. See the
[model-renderer README](packages/gcode-model-renderer/README.md#interactive-viewer).

**Multi-plate, multi-object, or just a subset.** A 3MF project can hold several plates and many
objects. Parse or render **one plate at a time** (`parseOptions.plate`), and a **render scope**
(`{ plateId }`, `{ objectIds }`, or an instance filter) narrows a still or the viewer to exactly the
plate or objects you want — a single plate's thumbnail, or one part isolated from the rest — with a
stable cache key per scope.

## Quick start

Install an adapter **plus `three`** (the renderer declares `three` as a peer dependency, range
Expand Down Expand Up @@ -319,7 +374,9 @@ contain. Details: [ToolpathIR & the capability model](docs/manual/concept-ir-cap

## Documentation

- **[Manual & getting started](https://chestnutlabs.github.io/gcode-preview/)** and the
- **[Manual & getting started](https://chestnutlabs.github.io/gcode-preview/)**, the
**[visual feature gallery](https://chestnutlabs.github.io/gcode-preview/documents/Feature_gallery.html)**
(what it does, shown rather than described), and the
**[API reference](https://chestnutlabs.github.io/gcode-preview/api/)** (generated from source).
- Concepts: [workers & performance](docs/manual/concept-workers.md) ·
[IR & capabilities](docs/manual/concept-ir-capabilities.md) ·
Expand Down Expand Up @@ -395,7 +452,7 @@ row inspects the *toolpath*, the bottom row presents the *source model* (see

Design rationale, boundaries, and the accepted architecture live in
[`docs/design/`](docs/design); the [docs index](docs/README.md) maps the whole set. Fourteen
packages publish to npm in lockstep (currently **v0.18.0**) with npm provenance.
packages publish to npm in lockstep (currently **v0.19.0**) with npm provenance.

## Development

Expand Down
44 changes: 44 additions & 0 deletions RELEASE_REVIEW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!--
RELEASE_REVIEW.md — Public Product + Docs + Visual review for the version being cut.
Auto-seeded by tools/release/stamp-release-docs.mjs (inside `npm run version`), then
RESOLVED by hand before promotion. The release gate (`npm run docs:release-check`) blocks
the dev -> main promotion until this file:
* declares the version being cut on the "Review version:" line;
* carries NO `Status: pending` row — every changed package must be one of
reviewed / no-change-needed / not-applicable;
* marks all three global dispositions "resolved":
"Product review: resolved", "Docs review: resolved", "Visual review: resolved".
Keep the greppable tokens ("Review version:", "Status:", "<X> review:") intact — the gate
parses them literally. Delete rows only for packages that did not change.
-->

# Release review — v0.19.0

**Review version:** v0.19.0
**Changed-capability inventory diffed against:** `v0.18.0`

This artifact records the per-release **Public Product + Documentation + Visual** reconciliation:
before the `dev` -> `main` promotion, compare the changed capabilities below against the README,
the Pages homepage, the feature gallery, the manual, the demo and examples, the screenshots, and
the coverage matrix ([`docs/VISUAL_FEATURE_COVERAGE.md`](docs/VISUAL_FEATURE_COVERAGE.md)); then set
each disposition. Guidance: CLAUDE.md "Public-docs completion check" and
[`docs/reference/release-process.md`](docs/reference/release-process.md).

## Changed packages (`src/` since the previous release)

| Package | Changed src files | Changelog summary | Disposition |
|---|--:|---|---|
| `@chestnutlabs/gcode-preview-core` | 2 | feat(renderer): `setFeatureRoleVisible(role, visible)` — show/hide a single feature role | Status: reviewed |
| `@chestnutlabs/gcode-renderer-three` | 2 | feat(renderer): `setFeatureRoleVisible(role, visible)` — show/hide a single feature role | Status: reviewed |
| `@chestnutlabs/toolpath-core` | 1 | feat(renderer): `setFeatureRoleVisible(role, visible)` — show/hide a single feature role | Status: reviewed |

Set each **Disposition** to one of `Status: reviewed` / `Status: no-change-needed` /
`Status: not-applicable` (never `Status: pending`).

## Global dispositions

- **Product review:** resolved — README / Pages homepage / feature gallery still describe the product accurately for this release.
- **Docs review:** resolved — manual, package READMEs, examples, and quick-start match the shipped API.
- **Visual review:** resolved — every changed user-facing capability is visually documented, or the coverage matrix records why not.

_Resolve each marker above by replacing `pending` with `resolved` once reconciled._
Loading
Loading