diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ed232d0b..3127b494 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -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: diff --git a/.github/workflows/docs-pages.yml b/.github/workflows/docs-pages.yml index c866ccc4..f9ba207d 100644 --- a/.github/workflows/docs-pages.yml +++ b/.github/workflows/docs-pages.yml @@ -13,6 +13,8 @@ on: - 'packages/**' - 'typedoc.json' - 'tools/docs/**' + - 'docs/manual/**' + - 'docs/media/**' - '.github/workflows/docs-pages.yml' workflow_dispatch: diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml index 82c3af2c..a35432fa 100644 --- a/.github/workflows/release-publish.yml +++ b/.github/workflows/release-publish.yml @@ -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. diff --git a/.prettierignore b/.prettierignore index 3092074f..80dfe5f5 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,3 +5,4 @@ dist *.min.css *.svelte +docs-site diff --git a/CLAUDE.md b/CLAUDE.md index 230d5b93..28e2e7eb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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`). @@ -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/`). - `docs/` — user manual (`manual/`), consumer references (`reference/`, `compatibility/`), and the maintainer planning/design/research set. diff --git a/README.md b/README.md index 09965583..189ddf27 100644 --- a/README.md +++ b/README.md @@ -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) --- @@ -100,6 +100,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". + + + + + + +
A print rendered on a round, delta-style build plate — the bed outline and grid are circular, with the model centered on itNon-rectangular beds. 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 shape on the build volume; rectangular stays the default.
@@ -132,6 +144,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 [# LT #] + # = [# * 360 / #] + G0 X[# + # * COS[#]] Y[# + # * SIN[#]] ; computed hole position + o100 call ; drill (subroutine) + # = [# + 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 @@ -148,6 +185,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. @@ -201,6 +249,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 @@ -319,7 +373,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) · diff --git a/RELEASE_REVIEW.md b/RELEASE_REVIEW.md new file mode 100644 index 00000000..28afb607 --- /dev/null +++ b/RELEASE_REVIEW.md @@ -0,0 +1,53 @@ + + +# Release review — v0.18.0 + +**Review version:** v0.18.0 +**Changed-capability inventory diffed against:** `v0.17.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). + +> **This review (documentation-systematization pass).** v0.18.0 was already published to npm; this +> pass reconciled its public surface retroactively and stood up the enforcement machinery. The two +> shipped feature arcs — DD-017 RS274NGC parametric programs (parser) and DD-030 renderer/viewer +> interop (non-rectangular bed, per-plate render scope, `capture() → Blob`) — are covered by the +> manual (`concept-parametric-programs.md`, `concept-ir-capabilities.md`, `adapters.md`) and the +> package CHANGELOGs. No user-facing surface misrepresents the shipped build. + +## Changed packages (`src/` since the previous release) + +| Package | Changed src files | Changelog summary | Disposition | +|---|--:|---|---| +| `@chestnutlabs/gcode-model-renderer` | 5 | feat(renderer): interactive view capture() → Blob + per-plate render scope + non-rect bed (DD-030) | Status: reviewed | +| `@chestnutlabs/gcode-parser` | 6 | feat(parser): RS274NGC parameters + expressions + O-word flow + subroutines (DD-017 P1–3) | Status: reviewed | +| `@chestnutlabs/gcode-preview-core` | 3 | feat: capture()/render-scope plumbed through GcodePreviewControls + staged progress (DD-030) | Status: reviewed | +| `@chestnutlabs/gcode-preview-element` | 1 | feat: Web Component inherits imperative capture() (DD-030 D1) | Status: reviewed | +| `@chestnutlabs/gcode-renderer-three` | 8 | feat(renderer): non-rectangular build-bed geometry + frameBounds precedence (DD-030 D3) | 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, and the DD-017/DD-030 capability descriptions accurately describe the v0.18.0 product; no fabricated capability or validation claim. +- **Docs review:** resolved — the manual (parametric-programs + IR-capabilities + adapters), package READMEs, and quick-start match the shipped API; the parametric-programs concept page is now registered in Pages nav and link-checked. +- **Visual review:** resolved — DD-017 is a parser/semantic capability (no new on-screen surface beyond parsed geometry, disclosed via capabilities); DD-030's non-rect bed / per-plate scope / capture map to existing renderer imagery, tracked in `docs/VISUAL_FEATURE_COVERAGE.md`. No changed capability is left visually undocumented without a matrix entry. + +_Resolve each marker above by replacing `pending` with `resolved` once reconciled._ diff --git a/docs/USER_FACING_DOCS_STYLE.md b/docs/USER_FACING_DOCS_STYLE.md index 7ff99648..726ad33e 100644 --- a/docs/USER_FACING_DOCS_STYLE.md +++ b/docs/USER_FACING_DOCS_STYLE.md @@ -86,11 +86,35 @@ confident, visual, technically credible, and human**. ## 6. Visuals -Screenshots carry the product. Rules: +Screenshots carry the product. + +**Default rule:** every user-facing feature is **visually documented somewhere** — unless the +coverage matrix ([`docs/VISUAL_FEATURE_COVERAGE.md`](VISUAL_FEATURE_COVERAGE.md)) records *why not* +(the feature is non-visual, is redundant with an existing shot, or is inherently temporal and +covered by a clip). "We didn't get to it" is not a recorded reason; an explicit matrix entry is. +The per-release Public Product + Docs + **Visual** review (`RELEASE_REVIEW.md`, enforced by +`npm run docs:release-check`) is where this is reconciled before promotion. + +**Two visual classes** — know which one you are producing: + +- **Showcase** — the hero images that sell the product (README top, Pages homepage). They pick the + most compelling model + framing and demonstrate the product as a whole. +- **Feature-proof** — the minimum image that *proves a specific capability exists and works* + (a color mode, a non-rectangular bed, a clip plane, a capability disclosure). It is judged by the + §8 recognition test, not by how pretty it is. Every feature the matrix tracks needs one, even when + it will never be a hero shot. + +Rules: - **Real software only.** Every image is a render from the current build (see [`tools/screenshots/`](../tools/screenshots/README.md)). Never mock, composite, or hand-paint a screenshot, and never show UI the software doesn't have. +- **Documentation capture background.** Feature-proof and grid captures use the canonical + **mid-grey, slicer/CAD-style documentation background** — a named shared capture setting in + [`tools/screenshots/`](../tools/screenshots/README.md), *not* a library default. The neutral grey + keeps toolpath colors, feature coloring, and geometry legible and consistent across a set. It is a + documentation convention only: consumers keep full control of the rendered background, and nothing + here changes the library's own defaults. - **Put a strong visual near the top** of the root README, above the fold. It should demonstrate the product, not decorate the page. - **Consistency:** hold viewport size, framing, crop, sample models, filenames, and UI state steady @@ -133,6 +157,16 @@ consideration is): If a visible behavior changed, regenerate the affected media with the capture harness rather than leaving a stale image in place. +**The recognition test (for feature-proof visuals).** A feature-proof image passes only if: + +> Would a developer who knows the product recognize *this specific feature* from the image alone, +> with the caption removed? + +If the capability is not legible without the words underneath it, the shot is not proving anything — +reframe it, pick a model that exercises the feature, or add the on-screen state that makes it +visible. Track the outcome in the coverage matrix ([`docs/VISUAL_FEATURE_COVERAGE.md`](VISUAL_FEATURE_COVERAGE.md)); +a feature with no passing image needs either a new capture or a recorded reason it has none. + ## 9. Links and legal - Link to deeper docs instead of inlining every detail: compatibility matrix, progress contract, diff --git a/docs/VISUAL_FEATURE_COVERAGE.md b/docs/VISUAL_FEATURE_COVERAGE.md new file mode 100644 index 00000000..ef597411 --- /dev/null +++ b/docs/VISUAL_FEATURE_COVERAGE.md @@ -0,0 +1,228 @@ +# Visual Feature Coverage Matrix + +**Purpose.** A persistent, maintained inventory of every user-facing capability G-code Preview +ships, and how well each is *communicated* — demonstrated in the demo, shown in media, and +documented across the README, the GitHub Pages feature gallery, and the manual/package docs. + +This file is a **release artifact**, not a one-time audit. The release process +([`docs/reference/release-process.md`](reference/release-process.md)) requires the Public Product + +Documentation + Visual Review to reconcile this matrix against what actually shipped, so no +capability silently loses coverage. See +[Maintaining this matrix](#maintaining-this-matrix-release-integration) at the bottom. + +> **Scope.** "User-facing" = something a consumer of the packages can see, control, inspect, +> configure, or must understand to use the library. Internal architecture, build tooling, and test +> harnesses are out of scope except where they surface a consumer-visible behavior. + +## Status vocabulary + +| Status | Meaning | +|---|---| +| `covered` | Demonstrated and documented adequately; a current visual explains it where visual. | +| `needs screenshot` | Real capability, no image yet — a static shot would materially help. | +| `needs better coverage` | Has an image, but it under-explains the feature (see the §8 test below). | +| `needs comparison` | Best shown as before/after or A-vs-B, not a single frame. | +| `needs animation` | The interaction *is* the feature; a static frame can't carry it. | +| `needs demo exposure` | Not reachable/observable in the shipped showcase demo. | +| `not visually meaningful` | Genuinely non-visual; documented by code/table/prose instead. | +| `internal-only` | Not consumer-facing; here only to record the decision to exclude it. | + +The **§8 test** (from [`USER_FACING_DOCS_STYLE.md`](USER_FACING_DOCS_STYLE.md)): *if a developer saw +this image with no caption, would they have a reasonable chance of noticing which feature it +demonstrates?* If not, the visual is `needs better coverage` no matter how pretty it is. + +## Two visual classes + +- **Showcase** — clean, immediately legible, carefully framed. Used in the README, the Pages + homepage, and major landing sections. +- **Feature-proof** — intentionally shows controls, toggles, legends, values, selected states, + diagnostics, warnings, confidence tiers, and before/after comparisons. Used in the Pages feature + gallery, manual concept pages, and recipes. Completeness over beauty. + +Both are captured on the shared **mid-grey documentation presentation** +(`tools/screenshots/`) — a neutral slicer/CAD-style viewport, not the demo's incidental dark UI. +Intentional exceptions (transparency, dark/light themes, custom backgrounds) are noted per-row. + +--- + +## This pass (2026-08-27) — coverage delta + +What moved to **covered** in the second public-product pass: + +- All 14 existing images **regenerated on the mid-grey documentation presentation**; the harness is + now manifest-driven (`shots.manifest.json`) with a shared `lib/presentation.mjs` look. +- **New media**: `parametric-bolt-circle`, `bed-circular`, `bed-polygon`, `render-tubes`, + `render-lines` — each on the mid-grey look. +- **Parametric RS274NGC**, **non-rectangular beds**, **capture/export**, **render diagnostics**, + **progressive/held reveal**, **parallel geometry pool**, **render scope / per-plate**: now in the + **README**, the **feature gallery**, and (where visual) concept pages with real screenshots. +- **Demo now exposes**: `capture()` (Capture PNG), `getRenderStats()` (diagnostics panel), + `progressivePreview` selector, **By speed** + **By object** color modes, the parametric fixture, + and nav links to the model / model-viewer / 2D / CNC-validation / headless-still pages. + +Still on the **to-capture** list (honest remainder — recorded, not forgotten): + +- `needs animation`: segment/time **scrub**, **progressive / held reveal**, interaction-aware + quality, user-scrub-wins — temporal, so a GIF/short clip beats a still (harness has the ffmpeg + path via `lib/browser.mjs`; not yet wired into shots). +- `needs comparison`: **object-aware framing** (whole-job vs model-aware), **fresh vs stale** + progress, **render scope** (plate/object subset before/after). +- `needs screenshot`: **diagnostics panel** in-context, **transparent-background capture** over a + checkerboard, per-mode **color legends** (feature/object/power), circular/polygon **bed** shots + with a flatter model for a cleaner outline. + +These are tracked here so the next release's Public Product + Documentation + Visual Review picks +them up rather than rediscovering them. + +## 1. Toolpath inspection + +| Capability | User-facing | Demo | Media | README | Pages gallery | Manual/pkg | Status | +|---|:---:|:---:|:---:|:---:|:---:|:---:|---| +| Layer-range clipping | ✅ | ✅ | `layer-clip-benchy` | ✅ | gallery | recipes | needs better coverage — show the range control + resulting cut | +| Segment scrub | ✅ | ✅ | — | — | gallery | recipes | needs animation — scrub is temporal | +| Time scrub + print-time estimate (slicer vs kinematic provenance) | ✅ | ✅ | — | mention | gallery | concept-progress-motion | needs animation + needs better coverage (provenance label) | +| Travel-move toggle | ✅ | ✅ | (in others) | ✅ | gallery | recipes | covered | +| Wipe-move toggle | ✅ | ✅ | — | mention | gallery | — | needs screenshot | +| Retraction / de-retraction markers | ✅ | ✅ | `retraction-markers` | ✅ | gallery | — | covered | +| Seam moves | ✅ | partial | — | mention | gallery | — | needs screenshot | +| Source-line ↔ segment mapping ("debugger": `pickSegment` + `segmentAtSourceLine`) | ✅ | ❌ | — | ❌ | gallery | recipes | needs demo exposure + needs screenshot | + +## 2. Coloring & analysis modes + +| Capability | User-facing | Demo | Media | README | Pages gallery | Manual/pkg | Status | +|---|:---:|:---:|:---:|:---:|:---:|:---:|---| +| Color by feature role | ✅ | ✅ | `viewer-benchy-tubes` (hero) | ✅ | gallery | concept-ir-capabilities | needs better coverage — add a legend | +| Color by speed / feedrate | ✅ | driven | `color-speed-calicat` | ✅ | gallery | — | needs better coverage — add ramp legend | +| Color by layer height | ✅ | ✅ | `color-layerheight` | ✅ | gallery | — | covered | +| Color by object | ✅ | driven | — | ❌ | gallery | — | needs screenshot | +| Color by tool | ✅ | ✅ | — | mention | gallery | — | needs screenshot | +| Color by M600 color change | ✅ | ✅ | — | mention | gallery | — | needs screenshot | +| Color by filament (file's own colours) | ✅ | driven | — | ❌ | gallery | concept-dialects-containers | needs screenshot | +| Color by tool power (laser/spindle) | ✅ | validate page | — | mention | gallery (CNC) | — | needs demo exposure + needs screenshot | +| Color by cut-vs-rapid (move kind) | ✅ | validate page | `cnc-cut-vs-rapid` | ✅ | gallery (CNC) | — | needs better coverage — legend + context | + +## 3. Live job progress + +| Capability | User-facing | Demo | Media | README | Pages gallery | Manual/pkg | Status | +|---|:---:|:---:|:---:|:---:|:---:|:---:|---| +| Known (byte-exact) position | ✅ | ✅ | `progress-known` | ✅ | gallery | concept-progress-motion | covered | +| Approximated position (uncertainty band) | ✅ | ✅ | `progress-approximated` | ✅ | gallery | concept-progress-motion | covered (pair reads as comparison) | +| Stale-signal greying | ✅ | ✅ | — | mention | gallery | concept-progress-motion | needs comparison (fresh vs stale) | +| File-identity mismatch detection | ✅ | ✅ | — | ❌ | — | reference/progress-* | not visually meaningful (prose + code) | +| User-scrub-wins over telemetry | ✅ | ✅ | — | mention | gallery | reference/progress-consumer-notes | needs animation | + +## 4. Rendering & quality + +| Capability | User-facing | Demo | Media | README | Pages gallery | Manual/pkg | Status | +|---|:---:|:---:|:---:|:---:|:---:|:---:|---| +| Tube geometry | ✅ | ✅ | hero | ✅ | gallery | concept-workers | covered | +| Line geometry | ✅ | ✅ | `render-lines` | mention | gallery | concept-workers | covered (tubes-vs-lines pair in gallery + concept) | +| Canvas 2D fallback (no WebGL/Three) | ✅ | 2d page | `canvas-2d-fallback` | ✅ | gallery | concept-workers | covered | +| Quality modes (full/adaptive/fast) | ✅ | partial | — | mention | gallery | concept-workers | needs demo exposure | +| Progressive preview (`auto`/`lines`) | ✅ | ✅ (selector) | — | ✅ | gallery | concept-workers | demo + docs covered; animation pending | +| Held / single clean reveal (`hold`) | ✅ | ✅ (selector) | — | ✅ | gallery | concept-workers | demo + docs covered; animation pending | +| Renderer build stages (`stage` event) | ✅ | ❌ | — | ✅ (prose) | gallery | concept-workers | needs animation | +| Interaction-aware quality | ✅ | ❌ | — | ✅ (prose) | gallery | concept-workers | needs animation | +| Disclosed decimation / degradation | ✅ | ✅ (disclosure) | — | ✅ (prose) | gallery | concept-workers | needs screenshot (disclosure text) | +| Render diagnostics (`getRenderStats`) | ✅ | ✅ (panel) | — | ✅ | gallery | concept-workers | demo + README + gallery covered; in-context panel screenshot pending | +| Geometry worker pool (parallel tubes) | ✅ | ❌ | — | mention | gallery | concept-workers | not visually meaningful (diagnostics panel proxies it) | +| WebGL context-loss recovery | ✅ | ❌ | — | mention | — | — | not visually meaningful | + +## 5. Cameras & presentation + +| Capability | User-facing | Demo | Media | README | Pages gallery | Manual/pkg | Status | +|---|:---:|:---:|:---:|:---:|:---:|:---:|---| +| Camera presets (7 views) | ✅ | ✅ | `camera-top/front/iso` | ✅ | gallery | — | covered (labeled sequence) | +| Perspective vs orthographic | ✅ | ✅ | (in camera trio) | ✅ | gallery | — | covered | +| Saved/restored camera state | ✅ | ✅ | — | mention | — | recipes | not visually meaningful | +| Object-aware framing (`frameContent`) | ✅ | ✅ | — | ✅ (prose) | gallery | concept-ir-capabilities | needs comparison — whole-job vs model-aware | +| Build-volume cage toggle | ✅ | ✅ | — | mention | gallery | — | needs screenshot | +| Capture / export → Blob | ✅ | ✅ | — | ✅ | gallery | recipes | covered (demo Capture PNG + README + gallery); in-context screenshot pending | +| Transparent / independent-background capture | ✅ | ✅ (via capture) | — | ✅ | gallery | recipes | demo + README covered; checkerboard screenshot pending | + +## 6. Source-model rendering (STL / 3MF) + +| Capability | User-facing | Demo | Media | README | Pages gallery | Manual/pkg | Status | +|---|:---:|:---:|:---:|:---:|:---:|:---:|---| +| Toolpath vs source-model (two renderers) | ✅ | model page | `model-render-stl-3mf` | ✅ | gallery | — | covered | +| STL presentation still | ✅ | model page | (in pair) | ✅ | gallery | model-renderer README | covered | +| 3MF material/color presentation | ✅ | model page | (in pair) | ✅ | gallery | model-renderer README | covered | +| Interactive model viewer (`createModelViewer`) | ✅ | model-viewer page | — | ✅ (prose) | gallery | model-renderer README | needs demo exposure (link) + needs animation | +| Multi-object files | ✅ | model page | — | mention | gallery | — | needs screenshot | +| Multi-plate files + per-plate render | ✅ | ❌ | — | ❌ | gallery | — | needs demo exposure + needs comparison | +| Render scope / object subsets (`RenderScope`) | ✅ | ❌ | — | ❌ | gallery | recipes | needs demo exposure + needs comparison | +| Instance-aware rendering ("N copies") | ✅ | ❌ | — | ❌ | — | — | needs screenshot (badge) | + +## 7. Machine / build geometry + +| Capability | User-facing | Demo | Media | README | Pages gallery | Manual/pkg | Status | +|---|:---:|:---:|:---:|:---:|:---:|:---:|---| +| Rectangular bed | ✅ | ✅ | (in many) | mention | gallery | — | covered | +| Circular / delta bed | ✅ | harness | `bed-circular` | ✅ | gallery | concept-dialects-containers | covered (media + README + gallery); interactive bed selector still pending | +| Polygonal bed | ✅ | harness | `bed-polygon` | ✅ | gallery | concept-dialects-containers | covered (media + README + gallery); interactive bed selector still pending | +| Excluded-region outlines | ✅ | ✅ | — | ❌ | — | — | needs screenshot | +| Bed surface / texture themes | ✅ | ✅ | — | mention | gallery | — | needs screenshot | + +## 8. CNC / laser / plotter + +| Capability | User-facing | Demo | Media | README | Pages gallery | Manual/pkg | Status | +|---|:---:|:---:|:---:|:---:|:---:|:---:|---| +| Cut vs rapid classification | ✅ | validate page | `cnc-cut-vs-rapid` | ✅ | gallery (CNC) | motion-coverage | needs better coverage (legend/context) | +| Tool power channel (laser/RPM) | ✅ | validate page | — | mention | gallery (CNC) | — | needs demo exposure + needs screenshot | +| Canned drilling cycles (G81/82/83) | ✅ | ❌ | — | mention | gallery (CNC) | motion-coverage | needs screenshot | +| Validation tiers (validated vs experimental) | ✅ | validate page | — | ✅ (prose) | gallery (CNC) | compatibility | not visually meaningful (prose/table) | +| Parametric RS274NGC programs (params/expr/O-word/subs) | ✅ | ✅ (fixture) | `parametric-bolt-circle` | ✅ | gallery (CNC) | concept-parametric-programs | covered — demo fixture + media + README + gallery (program paired with geometry) | + +## 9. Formats, dialects & classification + +| Capability | User-facing | Demo | Media | README | Pages gallery | Manual/pkg | Status | +|---|:---:|:---:|:---:|:---:|:---:|:---:|---| +| `.gcode` plain | ✅ | ✅ | (all) | ✅ | — | concept-dialects-containers | covered (table) | +| `.gcode.3mf` container + multi-plate | ✅ | ✅ | — | ✅ | gallery | concept-dialects-containers | needs screenshot | +| `.bgcode` (Prusa binary) | ✅ | ❌ | — | ✅ | — | concept-dialects-containers | not visually meaningful (table) | +| Slicer/controller recognition | ✅ | ✅ | — | ✅ | — | compatibility | not visually meaningful (table) | +| Object / feature classification (model vs housekeeping) | ✅ | ❌ | — | mention | gallery | concept-ir-capabilities | needs demo exposure + needs comparison | +| Slice metadata panel (filament, usage, estimate, thumbnails) | ✅ | ✅ | — | mention | gallery | concept-dialects-containers | needs screenshot | +| Capability / confidence model | ✅ | ✅ | — | ✅ (table) | gallery | concept-ir-capabilities | needs screenshot (honest-fallback UI) | + +## 10. Framework integration & headless + +| Capability | User-facing | Demo | Media | README | Pages gallery | Manual/pkg | Status | +|---|:---:|:---:|:---:|:---:|:---:|:---:|---| +| Vue / React / Svelte / Web Component adapters | ✅ | examples | — | ✅ (table) | — | adapters | not visually meaningful (code) | +| Headless toolpath still (`renderStill`) | ✅ | still page | — | ✅ | gallery | reference/still-render | needs screenshot (server-thumbnail context) | +| Headless model still (`renderModelStill`) | ✅ | model page | `model-render-stl-3mf` | ✅ | gallery | model-renderer README | covered | +| Off-thread parsing / cancellation / limits | ✅ | ✅ | — | ✅ (prose) | — | concept-workers | not visually meaningful | + +--- + +## Media asset inventory + +Canonical assets live in [`docs/media/`](media/) and are produced by +[`tools/screenshots/`](../tools/screenshots/README.md) from real renders of the tracked MIT corpus — +nothing mocked or hand-edited. Every asset is enumerated in the shot manifest +(`tools/screenshots/shots.manifest.json`) with its source file, parameters, output class, caption, +and alt text. Regenerate with `node tools/screenshots/capture.mjs` (all) or by shot name (subset). + +Assets are consumed by **both** the README and the Pages build (copied to `docs-site/media/` at build +time), so there is one canonical source per image — no duplicate files. + +--- + +## Maintaining this matrix (release integration) + +This matrix is kept honest by the release contract, not by memory: + +1. **Every release** runs the Public Product + Documentation + Visual Review + ([release process](reference/release-process.md)). It compares the release candidate against the + previous published tag, generates the changed-capability inventory, and for each new or + materially changed user-facing capability decides a disposition here. +2. The generated `RELEASE_REVIEW.md` (seeded by `npm run version`) lists the changed packages and + requires each to be reconciled — Product / Docs / Visual — before promotion. + `npm run docs:release-check` **blocks the `dev` → `main` promotion** until the review is resolved + for the exact version being cut. +3. A row may legitimately settle on `not visually meaningful` or "no new image necessary" — but that + is a **recorded decision**, never a silent omission. "We didn't check" is not an acceptable state. + +The default rule is stronger than "keep docs current": **every user-facing feature is visually +documented somewhere** unless this matrix explicitly records why it isn't. diff --git a/docs/manual/concept-parametric-programs.md b/docs/manual/concept-parametric-programs.md index 2b4dd7ba..f767d558 100644 --- a/docs/manual/concept-parametric-programs.md +++ b/docs/manual/concept-parametric-programs.md @@ -43,9 +43,15 @@ o100 while [# LT #] o100 endwhile ``` -The six rapids land on the circle: the loop runs and the degree-trig expressions evaluate, so the +The rapids land on the circle: the loop runs and the degree-trig expressions evaluate, so the preview shows the pattern the machine would follow — not an empty plate. +![A CNC toolpath of 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](../media/parametric-bolt-circle.png) + +*A slightly larger version of the same idea — eight holes, a centre hole, and a computed frame — +rendered from [`test-data/fixtures/parametric/bolt-circle.ngc`](https://github.com/ChestnutLabs/gcode-preview/blob/dev/test-data/fixtures/parametric/bolt-circle.ngc). +Nothing in that file lists a hole position; every one is computed.* + ## It costs nothing on ordinary files The interpreter engages **only** when a program actually uses `#`, `[`, or an O-word. Every FDM and diff --git a/docs/manual/concept-progress-motion.md b/docs/manual/concept-progress-motion.md index 4aab4817..e8bc5748 100644 --- a/docs/manual/concept-progress-motion.md +++ b/docs/manual/concept-progress-motion.md @@ -20,6 +20,11 @@ and the stack maps it onto the toolpath with **tiered confidence**: - **stale** signal → handled explicitly, not silently frozen; - **user scrub always wins** over incoming telemetry. +| Known position | Approximated position | +|---|---| +| ![Live progress with a byte-exact position marker and a ghosted remaining path](../media/progress-known.png) | ![Live progress from a coarse signal shown as an emphasis band over the current layer](../media/progress-approximated.png) | +| Byte-exact telemetry → a precise cut and an exact marker. | A layer index or bare percentage → an uncertainty band, not a fake dot. | + The normalized contract and consumer guidance are in the [progress signal contract](https://github.com/ChestnutLabs/gcode-preview/blob/dev/docs/reference/progress-signal-contract.md) and [consumer notes](https://github.com/ChestnutLabs/gcode-preview/blob/dev/docs/reference/progress-consumer-notes.md). diff --git a/docs/manual/concept-workers.md b/docs/manual/concept-workers.md index 331b21d0..c8e578c8 100644 --- a/docs/manual/concept-workers.md +++ b/docs/manual/concept-workers.md @@ -54,3 +54,13 @@ The Three.js renderer keeps interactions cheap: **layer chunks** with decimation clip and segment scrub as **draw-range** updates (no geometry rebuilds), tube-or-line geometry with automatic quality fallback, per-file build plates, and WebGL context-loss recovery. Pair a bounded parse with draw-range navigation and even very large toolpaths stay responsive. + +| Tubes | Lines | +|---|---| +| ![The calicat as lit 3D extrusion tubes](../media/render-tubes.png) | ![The calicat as flat single-pixel toolpath lines](../media/render-lines.png) | +| Lit 3D cross-sections — the default for models that fit the geometry budget. | Flat one-pixel paths — lighter, for very large files or low-GPU devices. | + +A **parallel geometry worker pool** builds the tubes off the main thread (byte-identical to serial, +degrading pool → serial → lines under a memory budget, all disclosed), and **`getRenderStats()`** +reports exactly what happened — backend, hardware-vs-software GPU, draw calls, and timings — so "why +is this slow / what am I running on" is answerable, never guessed. diff --git a/docs/manual/feature-gallery.md b/docs/manual/feature-gallery.md new file mode 100644 index 00000000..e7554aa0 --- /dev/null +++ b/docs/manual/feature-gallery.md @@ -0,0 +1,135 @@ +--- +title: Feature gallery +group: Guide +category: Guide +--- + +# Feature gallery + +What G-code Preview can actually do, shown rather than described. Every image is a **real render of a +real file** from the tracked demo corpus, captured by [`tools/screenshots/`](https://github.com/ChestnutLabs/gcode-preview/tree/dev/tools/screenshots) +on a neutral slicer/CAD viewport — nothing mocked. This page is the visual companion to the +[capability model](concept-ir-capabilities.md) and the per-feature +[coverage matrix](https://github.com/ChestnutLabs/gcode-preview/blob/dev/docs/VISUAL_FEATURE_COVERAGE.md). + +> New here? Start with the [getting-started guide](index.md), then come back to browse the breadth. + +## Toolpath inspection + +The core job: turn a sliced file into an interactive picture of the actual moves the machine makes. + +| | | +|---|---| +| ![3DBenchy as extrusion tubes, colored by feature role](../media/viewer-benchy-tubes.png) | ![3DBenchy clipped to a mid-height layer band, exposing perimeters and infill](../media/layer-clip-benchy.png) | +| **Tube geometry, feature coloring.** Lit 3D extrusion cross-sections, colored by what each move *is*. | **Layer-range clipping.** Isolate any band of layers by index — a draw-range trim, no geometry rebuild. | +| ![Calicat lower layers with retraction and de-retraction markers pinned on the path](../media/retraction-markers.png) | ![The calicat as flat single-pixel toolpath lines](../media/render-lines.png) | +| **Retraction & de-retraction markers.** Toggle markers for retractions, wipes, travel, and seams. | **Line geometry.** Flat one-pixel paths — lighter for very large files or low-GPU devices. | + +Also here: **segment scrub** (step move-by-move), **time scrub** with an honest print-time estimate +(labeled *slicer estimate* vs *kinematic approximation*), and **source-line ↔ segment mapping** — click +a move to find its byte in the file, and back. See [recipes](recipes.md). + +## Coloring & analysis + +Color is analysis. Every mode is capability-gated — it colors from real data or explains why it can't. + +| | | +|---|---| +| ![The calicat colored by feedrate, blue slow to red fast](../media/color-speed-calicat.png) | ![A variable-layer-height print colored blue for thin layers to red for thick](../media/color-layerheight.png) | +| **By speed / feedrate.** An auto-ranged ramp reveals slow corners and fast infill. | **By layer height.** Spot variable-layer-height regions at a glance. | + +Also: **feature role**, **object**, **tool**, **M600 color change**, the file's **own filament +colours**, **tool power** (laser/spindle), and **cut-vs-rapid** for CNC. All share one +renderer-agnostic [`ColorMode`](concept-ir-capabilities.md) model across the 3D and 2D renderers. + +## Live job progress + +Feed the viewer your printer's telemetry and it maps the signal onto the toolpath **at the confidence +the signal deserves** — the library's honesty rule made visible. + +| Known position | Approximated position | +|---|---| +| ![Live progress with a byte-exact position marker and a ghosted remaining path](../media/progress-known.png) | ![Live progress from a coarse signal shown as an emphasis band over the current layer](../media/progress-approximated.png) | +| Byte-exact telemetry → a precise cut and an exact marker. | A layer index or bare percentage → an uncertainty **band**, not a fake dot. | + +A **stale** signal greys the overlay instead of freezing a lie; **user scrub always wins** over +incoming telemetry; file-identity mismatches are detected and disclosed. See +[live progress & motion model](concept-progress-motion.md). + +## Rendering & quality + +| | | +|---|---| +| ![The calicat as lit 3D tubes](../media/render-tubes.png) | ![A single layer drawn by the Canvas 2D renderer, no WebGL](../media/canvas-2d-fallback.png) | +| **Tubes vs lines.** Automatic quality selection, or force either. | **Canvas 2D fallback.** A flat layer view with **no WebGL and no Three.js** — the 2D bundle never ships Three. | + +Underneath: **quality modes** (full / adaptive / fast), **interaction-aware quality** (drop detail +while orbiting, restore on settle), a **parallel geometry worker pool** (byte-identical tubes off the +main thread, degrading pool → serial → lines, all disclosed), **progressive preview** with a **single +clean `hold` reveal**, staged preparation progress, and **`getRenderStats()`** diagnostics (backend, +hardware-vs-software GPU, draw calls, timings — never fabricated). See +[workers, streaming & performance](concept-workers.md). + +## Cameras, framing & capture + +| | | | +|---|---|---| +| ![3DBenchy from the front, orthographic](../media/camera-front.png) | ![3DBenchy from the top, orthographic](../media/camera-top.png) | ![3DBenchy isometric, perspective](../media/camera-iso.png) | +| **Front** (ortho) | **Top** (ortho) | **Iso** (perspective) | + +Seven **camera presets**, orthographic/perspective, and a serializable **camera state** you can +persist and restore. **Object-aware framing** fits the printed object — excluding skirt, prime line, +and purge — instead of the whole machine volume. **`capture()`** returns the current view as a `Blob` +(PNG/JPEG/WebP), including a **transparent background** for compositing onto cards, from the +interactive viewer *or* the headless still. + +## Models & plates — the other renderer + +Sometimes you don't want the toolpath at all — you want a clean picture of *what the object is*. +That's a separate presentation renderer over the **source model** (STL / 3MF). + +![Two presentation stills: a neutral STL labeled materials unavailable beside a colored 3MF labeled materials known](../media/model-render-stl-3mf.png) + +STL is a single neutral object; **3MF** brings multi-object structure and per-object / per-triangle +**material colors** — and when the source *doesn't* declare colors, the render says +`materials: 'unavailable'` rather than inventing one. A 3MF project can hold several **plates** and +many **objects**: render **one plate at a time** and narrow to a **render scope** (a plate, or a +subset of objects) for a single thumbnail. Headless `renderModelStill` and interactive +`createModelViewer` share the look. See the +[model-renderer README](https://github.com/ChestnutLabs/gcode-preview/blob/dev/packages/gcode-model-renderer/README.md). + +## Machine geometry + +| | | +|---|---| +| ![A print on a round, delta-style build plate with a circular grid](../media/bed-circular.png) | ![A print on a hexagonal build plate with the grid clipped to the polygon](../media/bed-polygon.png) | +| **Circular / delta beds.** The outline and grid follow the round shape. | **Polygonal beds.** An arbitrary polygon outline, grid clipped to the shape. | + +Rectangular stays the default and byte-identical; a `shape` on the build volume opts into round or +polygonal. Bed geometry discovered from the file (its printer profile) is offered to the consumer, +never force-applied over a bed you set. + +## CNC, laser & parametric + +| | | +|---|---| +| ![An Easel CNC carve colored by move kind, cut moves pink and rapid moves blue](../media/cnc-cut-vs-rapid.png) | ![A CNC bolt circle plus frame computed by a parametric program](../media/parametric-bolt-circle.png) | +| **Cut vs rapid.** Non-extrusion toolpaths classify tool-engaged moves as `Cut`; color by cut-vs-rapid or tool power. | **Parametric programs (RS274NGC).** Geometry the machine *computes* — a `while`-loop bolt circle + subroutine — resolved to the real toolpath. | + +Canned drilling cycles (`G81`/`G82`/`G83`) expand; controller support is **honesty-tiered** +(experimental until hardware-validated) but geometry always parses. Parametric execution is +**bounded** and reports `parametricProgram: 'known'` only on a clean run. See +[parametric programs](concept-parametric-programs.md) and the +[motion & position coverage](../compatibility/gcode-motion-coverage.md). + +## Framework integration + +The whole viewer ships as drop-in **Vue, React, Svelte, and Web Component** components over one shared +engine, plus a lower-level API (composable / hook / store / action) for building your own controls, +and a headless `renderStill` for server thumbnails. See [framework adapters](adapters.md). + +--- + +*Missing a capability here? The [coverage matrix](https://github.com/ChestnutLabs/gcode-preview/blob/dev/docs/VISUAL_FEATURE_COVERAGE.md) +tracks every user-facing feature and its documentation state — including the shots still on the +to-capture list.* diff --git a/docs/manual/index.md b/docs/manual/index.md index 890a6b50..563a2147 100644 --- a/docs/manual/index.md +++ b/docs/manual/index.md @@ -1,11 +1,50 @@ -A worker-based, cross-vendor **G-code toolpath stack** for the browser: parse `.gcode` and -`.gcode.3mf` off the main thread, normalize them into a versioned intermediate representation -(**ToolpathIR**), and render an interactive Three.js preview — with first-class **Vue, React, -Svelte**, and **Web Component** adapters over one shared, framework-neutral engine. - -This is the **SDK manual** (these Guide and Concept pages). The **generated -API reference** — every public export of all fourteen `@chestnutlabs/*` packages — is a companion site -linked from the **API reference** item in the top nav. + + +
    +
  • + +

    Toolpath inspection

    Layer clip, segment & time scrub, travel / retraction / seam markers, source-line mapping.

    +
  • +
  • + +

    Coloring & analysis

    Color by speed, feature, object, tool, layer height, color change, or tool power.

    +
  • +
  • + +

    Live job progress

    Map printer telemetry onto the path at the confidence it deserves — exact, band, or stale.

    +
  • +
  • + +

    Models & plates

    Present the source STL / 3MF — multi-object, per-plate, colored materials — a second renderer.

    +
  • +
  • + +

    CNC, laser & parametric

    Cut vs rapid, tool power, canned cycles, and RS274NGC programs the machine computes.

    +
  • +
  • + +

    Any build surface

    Rectangular, circular / delta, and polygonal beds — outline and grid follow the real shape.

    +
  • +
+ +These Guide and Concept pages are the **SDK manual**. The generated +**[API reference](https://chestnutlabs.github.io/gcode-preview/api/)** — every public export of all +fourteen `@chestnutlabs/*` packages — is a companion site linked from the top nav. New here? Jump to +the **[feature gallery](feature-gallery.md)** to browse the breadth, or start below. ## Install diff --git a/docs/media/app-control-panel.png b/docs/media/app-control-panel.png index d1d01306..e466eb72 100644 Binary files a/docs/media/app-control-panel.png and b/docs/media/app-control-panel.png differ diff --git a/docs/media/bed-circular.png b/docs/media/bed-circular.png new file mode 100644 index 00000000..6acf4ebd Binary files /dev/null and b/docs/media/bed-circular.png differ diff --git a/docs/media/bed-polygon.png b/docs/media/bed-polygon.png new file mode 100644 index 00000000..44cd0767 Binary files /dev/null and b/docs/media/bed-polygon.png differ diff --git a/docs/media/camera-front.png b/docs/media/camera-front.png index 8acccbed..2d88ba56 100644 Binary files a/docs/media/camera-front.png and b/docs/media/camera-front.png differ diff --git a/docs/media/camera-iso.png b/docs/media/camera-iso.png index f7060951..061a9274 100644 Binary files a/docs/media/camera-iso.png and b/docs/media/camera-iso.png differ diff --git a/docs/media/camera-top.png b/docs/media/camera-top.png index 6ece7f6a..4122b430 100644 Binary files a/docs/media/camera-top.png and b/docs/media/camera-top.png differ diff --git a/docs/media/canvas-2d-fallback.png b/docs/media/canvas-2d-fallback.png index 1c6ca251..478d9660 100644 Binary files a/docs/media/canvas-2d-fallback.png and b/docs/media/canvas-2d-fallback.png differ diff --git a/docs/media/cnc-cut-vs-rapid.png b/docs/media/cnc-cut-vs-rapid.png index 05f4efa0..bb0d2883 100644 Binary files a/docs/media/cnc-cut-vs-rapid.png and b/docs/media/cnc-cut-vs-rapid.png differ diff --git a/docs/media/color-layerheight.png b/docs/media/color-layerheight.png index 5a407775..5b2eb53f 100644 Binary files a/docs/media/color-layerheight.png and b/docs/media/color-layerheight.png differ diff --git a/docs/media/color-speed-calicat.png b/docs/media/color-speed-calicat.png index c3a210f8..63b10bab 100644 Binary files a/docs/media/color-speed-calicat.png and b/docs/media/color-speed-calicat.png differ diff --git a/docs/media/layer-clip-benchy.png b/docs/media/layer-clip-benchy.png index 503d8de8..f3ff6570 100644 Binary files a/docs/media/layer-clip-benchy.png and b/docs/media/layer-clip-benchy.png differ diff --git a/docs/media/model-render-stl-3mf.png b/docs/media/model-render-stl-3mf.png index 6eba0963..e6d9f731 100644 Binary files a/docs/media/model-render-stl-3mf.png and b/docs/media/model-render-stl-3mf.png differ diff --git a/docs/media/parametric-bolt-circle.png b/docs/media/parametric-bolt-circle.png new file mode 100644 index 00000000..5ea787e7 Binary files /dev/null and b/docs/media/parametric-bolt-circle.png differ diff --git a/docs/media/progress-approximated.png b/docs/media/progress-approximated.png index 606cb5aa..3fc9261b 100644 Binary files a/docs/media/progress-approximated.png and b/docs/media/progress-approximated.png differ diff --git a/docs/media/progress-known.png b/docs/media/progress-known.png index 4f253903..f296dcf1 100644 Binary files a/docs/media/progress-known.png and b/docs/media/progress-known.png differ diff --git a/docs/media/render-lines.png b/docs/media/render-lines.png new file mode 100644 index 00000000..244ba63a Binary files /dev/null and b/docs/media/render-lines.png differ diff --git a/docs/media/render-tubes.png b/docs/media/render-tubes.png new file mode 100644 index 00000000..b945b982 Binary files /dev/null and b/docs/media/render-tubes.png differ diff --git a/docs/media/retraction-markers.png b/docs/media/retraction-markers.png index 3781e5af..4c4dc6ec 100644 Binary files a/docs/media/retraction-markers.png and b/docs/media/retraction-markers.png differ diff --git a/docs/media/viewer-benchy-tubes.png b/docs/media/viewer-benchy-tubes.png index 75638a53..a8abef74 100644 Binary files a/docs/media/viewer-benchy-tubes.png and b/docs/media/viewer-benchy-tubes.png differ diff --git a/docs/reference/release-process.md b/docs/reference/release-process.md index 86823721..f2ddd7d6 100644 --- a/docs/reference/release-process.md +++ b/docs/reference/release-process.md @@ -26,13 +26,31 @@ from the protected `Release / publish` workflow on a tag from `main` — never f stamper drops a `RELEASE_NOTES_DRAFT.md` (proposed lead + history line + deduped changelog points) into the PR for the author to fold in, then delete. The single source of truth for these surfaces is `tools/release/doc-surfaces.mjs`. + - **The Public Product + Docs + Visual review is seeded here too.** The same stamper generates + `RELEASE_REVIEW.md` from a **changed-capability inventory** — every package whose `src/` changed + since the previous `vX.Y.Z` tag (`changedCapabilityInventory()`), with its changed files and + changelog summary — each disposition pre-filled `Status: pending`, plus three global markers + (Product / Docs / Visual) pre-filled `pending`. It is the *inverse* of the notes draft: the + draft must be **absent** to promote, this review must be **present and fully resolved**. See the + dedicated review step below. +2a. **Public Product + Documentation + Visual review (required, before promotion):** open + `RELEASE_REVIEW.md` and reconcile the changed-capability inventory against the whole public + surface — the root `README`, the Pages homepage, the feature gallery, the manual (`docs/manual/`), + the demo and `tools/example-*` apps, the screenshots, and the visual coverage matrix + (`docs/VISUAL_FEATURE_COVERAGE.md`). For each changed package set its disposition to + `Status: reviewed` / `no-change-needed` / `not-applicable` (never `pending`), regenerating any + media the change invalidated (`tools/screenshots/`). Then resolve the three global markers by + replacing `pending` with `resolved`. `npm run docs:release-check` (the `Docs release gate`) reads + this file and **blocks the promotion PR** until the version matches and every disposition is + resolved — so the review is enforced, not a reminder. 3. **Promotion PR (`dev` → `main`):** a deliberate PR carrying the versioned state to `main`, merged only with the required checks green — including the **`Docs release gate`** (`npm run docs:release-check`), which fails the promotion if any version surface, the `docs/README` current-state lead, or the release-history list disagrees with the version being - cut, or if `RELEASE_NOTES_DRAFT.md` is still present. It also prints a screenshots/guides review - reminder (the judgment call from CLAUDE.md's *Public-docs completion check*; confirmed via the - promotion PR-template checkbox, not hard-failed). The first promotion (`v0.1.0`) ended the + cut, if `RELEASE_NOTES_DRAFT.md` is still present, or if `RELEASE_REVIEW.md` is missing, names a + different version, or still carries an unresolved disposition (a `Status: pending` row or a + Product/Docs/Visual marker not `resolved`). The Public Product + Docs + Visual review (step 2a) is + thus **enforced by the gate**, not left to a checkbox. The first promotion (`v0.1.0`) ended the founding-baseline freeze on `main`. 4. **Tag + GitHub Release:** tag `vX.Y.Z` on `main` and publish a GitHub Release for it. This — and nothing else — triggers publication. @@ -70,7 +88,7 @@ from the protected `Release / publish` workflow on a tag from `main` — never f | Branch | Protection | |---|---| | `dev` | required check `build` (existing); the *Changeset presence* check runs on every PR | -| `main` | required check `build` (existing, kept name-stable); **add `node-24` as required** at the rehearsal; no direct pushes; release PRs (promotion) only | +| `main` | required check `build` (existing, kept name-stable); **add `node-24` as required** at the rehearsal; the **`Docs release gate`** (`docs-release-gate.yml` → `npm run docs:release-check`) runs on every PR to `main` and — since promotion PRs are the only PRs targeting `main` — is the mechanism that enforces both the version surfaces and the resolved `RELEASE_REVIEW.md`; no direct pushes; release PRs (promotion) only | | tags `v*` | created only on `main` (the publish workflow independently verifies tag ∈ `main` and refuses otherwise) | ## Failure behavior (DD-008 §6) diff --git a/test-data/fixtures/parametric/bolt-circle.ngc b/test-data/fixtures/parametric/bolt-circle.ngc new file mode 100644 index 00000000..fa423763 --- /dev/null +++ b/test-data/fixtures/parametric/bolt-circle.ngc @@ -0,0 +1,51 @@ +; RS274NGC parametric program (LinuxCNC dialect) — computed geometry demo. +; +; Nothing here spells out a hole position move-by-move: a bolt circle of holes and +; a surrounding frame are COMPUTED from a handful of parameters using expressions, +; a while-loop, and a subroutine. The parser runs this programming layer, so the +; preview shows the real toolpath the machine would follow — not an empty plate. +; +; MIT-clean, hand-authored for documentation (Chestnut Labs). + +G21 G17 G90 ; mm, XY plane, absolute +S12000 M3 ; spindle on -> productive G1 moves classify as Cut + +; --- parameters ----------------------------------------------------------- +# = 60 ; bolt-circle centre X +# = 60 ; bolt-circle centre Y +# = 34 ; bolt-circle radius +# = 8 ; number of holes +# = 46 ; frame half-width +#<_zsafe> = 3 ; retract height (global: readable inside the subroutine) +#<_zcut> = -4 ; hole depth (global: named locals are per-call-frame) + +; --- subroutine: peck-drill a hole at the current X/Y ---------------------- +o100 sub + G1 Z#<_zcut> F120 ; plunge (cut) + G0 Z#<_zsafe> ; retract (rapid) +o100 endsub + +; --- bolt circle: one hole per step, position computed with degree trig ----- +# = 0 +o200 while [# LT #] + # = [# * 360 / #] + G0 X[# + # * COS[#]] Y[# + # * SIN[#]] + o100 call + # = [# + 1] +o200 endwhile + +; --- a centre hole --------------------------------------------------------- +G0 X# Y# +o100 call + +; --- computed square frame around the pattern ------------------------------ +G0 X[# - #] Y[# - #] +G1 Z#<_zcut> F160 +G1 X[# + #] Y[# - #] +G1 X[# + #] Y[# + #] +G1 X[# - #] Y[# + #] +G1 X[# - #] Y[# - #] +G0 Z#<_zsafe> + +M5 ; spindle off +M2 ; end diff --git a/tools/demo/index.html b/tools/demo/index.html index 7e2ffd8f..fd3939b2 100644 --- a/tools/demo/index.html +++ b/tools/demo/index.html @@ -223,6 +223,8 @@

+ + @@ -235,6 +237,15 @@

+