Skip to content

release: promote v0.20.0 to main - #429

Merged
sobechestnut-dev merged 23 commits into
mainfrom
dev
Aug 30, 2026
Merged

sobechestnut-dev merged 23 commits into
mainfrom
dev

Conversation

@sobechestnut-dev

Copy link
Copy Markdown
Contributor

Promotion of the versioned v0.20.0 state (dev → main) for the lockstep release.

Headline (DD-031): interactive source-model viewing (STL/3MF) becomes a first-class, declarative half of the SDK — createModelPreviewController + a <ModelViewer> adapter on each framework's /model subpath (<gcode-model-viewer> for the Web Component), with a portable model behavioral suite + parity guards. Plus the toolpath dark-capability closure (getRenderStats/pickSegment/isColorModeAvailable/declarative hiddenFeatureRoles/handle capture), capture({ includeBuildVolume }), the Feature Lab demo, and two-tier framework examples.

All 14 packages bump to v0.20.0 (lockstep). Changesets consumed, per-package CHANGELOGs generated, internal ranges pinned, docs folded (docs/README current-state + release history), and RELEASE_REVIEW.md resolved. docs:release-check passes.

Tagging v0.20.0 on main after merge triggers the publish workflow.

🤖 Generated with Claude Code

sobechestnut-dev and others added 23 commits August 28, 2026 11:36
…ity (DD-031 G1-G6, E1/E4)

Phase 2 of the consumer-UX pass: no shipped capability stays reachable only via
raw.renderer(), and every new public controls method is exposed + parity-tested
across Vue/React/Svelte/Web Component.

Core (gcode-preview-core):
- GcodePreviewControls gains getRenderStats() (G1), pickSegment() (G2), and
  isColorModeAvailable() — the render-diagnostics and source-mapping surfaces
  were previously ToolpathRenderer-only.
- GcodePreviewState gains availableColorModes/hasRetractions/hasColorChanges (G6),
  refreshed post-parse from the renderer's honest capability gates, so a UI can
  offer+explain controls without the raw handle.
- PreviewRenderer widened accordingly; the 2D adapter implements the new members
  honestly (getRenderStats null; no fabricated stats).

Adapters:
- Declarative hiddenFeatureRoles (G3) on all four (prop / prop / prop /
  hidden-feature-roles attribute), diffing prev->next so it only toggles roles it
  owns. Backs the AnyBridge hide-adhesion feature declaratively.
- capture() promoted to the Vue/React/Svelte handles (G5), matching the WC method.
- Web Component: renderer/adjacentLayers property accessors (E1); index re-exports
  RendererMode/PreviewRenderer (E4).

Tests: portable behavioral suite extended (layer-range clip, color-mode gating,
diagnostics+picking reachability) plus a controls-completeness parity guard so a
capability can't ship in core and vanish from an adapter. The guard caught React's
hand-listed harness controls; fixed to delegate the whole controls object.

Docs: DD-031 (accepted) records the audit, parity matrix, gaps, and Feature-Lab
architecture.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…bility gaps (DD-031)

- adapters.md: replace the overstated "12-prop identical surface" with the real ~24-prop
  shared surface grouped by intent; correct the WC attribute-vs-property split; add the
  imperative surface (getRenderStats/pickSegment/isColorModeAvailable/capture) and
  capability-aware state; note the deliberate per-framework differences.
- Four adapter READMEs aligned to the verified surface: React README no longer omits
  onParseCancelled/onParseProgress; showRetractions/cameraMode/theme documented across all
  (not WC-only); core README names all four adapters incl. the Web Component; new
  hiddenFeatureRoles + reachable diagnostics/picking/capture added; WC property-only options,
  DOM event-detail wrapping, and Svelte's .svelte subpath documented as intentional.
- CLAUDE.md: add the mandatory framework-parity completion check (mission process rule).
- Changeset: additive minor across core + four adapters (lockstep).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-free toolpath cutouts

AnyBridge thumbnail parity: capture({ background:'transparent' }) on the toolpath
renderer baked in the build-plate grid, because the grid/bed/origin/cage are scene
geometry the transparent backdrop swap doesn't touch — so a consumer couldn't produce
a clean toolpath-only cutout the way ModelRenderer does.

Adds CaptureOptions.includeBuildVolume (default true = current behavior). When false,
ToolpathRenderer.capture hides its build-volume group for the off-screen render only and
restores it synchronously in a finally (no intermediate frame painted → live view
untouched). Flows through GcodePreviewControls.capture to all four adapters; a no-op
where there is no build volume (ModelViewer) or no capture (2D renderer).

Test: a capture-capable stub GL records the group's visibility at render-to-target time —
false with includeBuildVolume:false, true by default, restored to visible afterward.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… controller (DD-031 P3/P4)

Replaces the inherited sidebar-of-fieldsets engineering harness with a viewport-dominant
"Feature Lab" built on @chestnutlabs/gcode-preview-core (the published controller) — it now
dogfoods the real adapter surface instead of importing the raw ToolpathRenderer.

- New workspace-internal (unpublished) tools/demo-kit: a design-token CSS system, capability-
  aware control metadata + default color-mode palettes, an organized fixture catalog (by
  purpose, not filename), and formatting helpers — shared substrate for the demo and the
  framework showcase examples.
- Layout: compact header (brand + file/job + capture + chrome light/dark), viewport as the
  hero with floating legend + quick camera controls + count pill + stage banner, an intent-
  grouped inspector rail (Inspect / Appearance / View / Render / Machine / Progress / CNC /
  Diagnostics), a bottom Layers/Segments/Time scrub strip, and an honesty status bar.
- Contextual + capability-aware: color modes gray out with a plain-language reason when the
  file lacks the channel; the Hide brim/skirt toggle appears only when feature roles are
  known; the CNC tab appears only for tool-power files; capability badges are tiered
  known/inferred/unavailable. Diagnostics reads getRenderStats() through the public controls,
  and clicking the model reads pickSegment() — the previously-dark surfaces, now first-class.
- Preserves keyboard camera/scrub shortcuts and focus styles.

Verified in a headless Chromium: skirt-brim parses (454 seg / 14 layers / 3m04s), feature
coloring + legend, hide-adhesion removes skirt/brim live, getRenderStats returns the SwiftShader
diagnostics, contextual gating correct.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…1 P4)

Restructure the React example into the DD-031 §4.7 two tiers, both driving the
real @chestnutlabs/gcode-preview-react (no raw renderer/session):

- minimal.html / minimal.jsx — smallest real integration: <GcodePreview source>
  plus a fixture picker and a layer slider. One short file to copy.
- showcase.html / showcase.jsx — full declarative surface mirroring the Feature
  Lab's capability-aware UX in React idiom: color modes gate on the file's
  capabilities with a plain-language reason, feature-role hiding is a declarative
  prop, diagnostics + picking come through the ref handle's controls. Styled with
  the shared workspace-internal demo-kit (tokens + capability metadata + fixtures).
- index.html — landing linking the two tiers.
- vite.config: multi-page input, publicDir=test-data (demo-kit fixture paths),
  server.fs.allow for the ../demo-kit relative import.

Verified headless: minimal loads 3DBenchy (240 layers); showcase parses
skirt-brim (454 seg / 14 layers), badges tier known/unavailable correctly, color
modes gate with reasons, getRenderStats reports 3d-webgl/tubes/GPU, hide-adhesion
applies — zero console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…(DD-031 P4)

Greenfield Vue example (there was none), mirroring the React reference and driving
the real @chestnutlabs/gcode-preview-vue:

- Minimal.vue — smallest real integration: <GcodePreview :source> + fixture picker
  + layer slider, ordinary reactive state driving declarative bindings.
- Showcase.vue — full declarative surface in Vue idiom: capability-gated color
  modes with reasons, declarative :hidden-feature-roles, diagnostics/picking via the
  component ref's handle (viewer.preview.controls). Shared demo-kit styling.
- index landing, multi-page vite (plugin-vue), publicDir=test-data, fs.allow demo-kit.
- launch.json: example-vue (5203) + example-webcomponent (5204) placeholders.

Verified headless: minimal loads calicat (174 layers); showcase parses skirt-brim
(454 seg / 14 layers / 3m 04s), badges tier correctly, 3 modes gate with reasons,
getRenderStats reports 3d-webgl/tubes/GPU — zero console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…31 P4)

Restructure the Svelte example into the DD-031 §4.7 two tiers, both driving the
real @chestnutlabs/gcode-preview-svelte via the deliberate .svelte subpath:

- Minimal.svelte — smallest real integration: <GcodePreview {source}> + fixture
  picker + layer slider, ordinary reactive state driving declarative props.
- Showcase.svelte — full declarative surface in Svelte idiom: capability-gated
  color modes with reasons, declarative hiddenFeatureRoles, diagnostics/picking via
  the bound handle (viewer.preview.controls); the handle's store-contract `state`
  read for the ready-omitted fields. Shared demo-kit styling.
- index landing, multi-page vite (plugin-svelte), publicDir=test-data, fs.allow.
- Replaces the single App.svelte/main.js.

Verified headless: minimal loads 3DBenchy (240 layers) and vase (1, spiral);
showcase parses skirt-brim (454 seg / 14 layers / 3m 04s), badges tier correctly,
3 modes gate with reasons, getRenderStats reports 3d-webgl/tubes/GPU — zero errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…1 P4)

Greenfield vanilla-JS example (there was none), driving the published
<gcode-preview> element from @chestnutlabs/gcode-preview-element:

- minimal.js — smallest real integration: import /define to register, set the
  `source` property, listen for `ready`; the layer slider drives the `layer-range`
  attribute. Teaches the attribute/property split in ~40 lines.
- showcase.js — full surface in vanilla JS mirroring the Feature Lab: objects
  (source, colorMode, hiddenFeatureRoles) set as properties; primitives
  (layer-range, view) as attributes; capability-gated color modes with reasons;
  diagnostics/picking via element.controls; disclosure read from the WC's wrapped
  { text } detail. Shared demo-kit styling.
- index landing, multi-page vite, publicDir=test-data, fs.allow demo-kit.

Verified headless: minimal loads 3DBenchy (240 layers, layer-range attr path) and
mach3; showcase parses skirt-brim (454 seg / 14 layers / 3m 04s), badges tier,
3 modes gate, getRenderStats reports 3d-webgl/tubes/GPU, hiddenFeatureRoles=[6,7],
colorMode/layer-range/showTravel mutations all apply — zero console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…31 P4)

- React/Svelte README "Example" → "Examples": describe the minimal + showcase
  tiers and the correct --prefix run command (tools/* are not workspaces).
- Vue/Element READMEs: add the missing "Examples" section (both now have real
  example apps — a greenfield Vue app and the first Web Component example).
- adapters.md: add a "Try the examples" table (adapter → dir → port) and the
  minimal/showcase split.

docs:links OK (245 internal links).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rity (DD-031 P4)

- Each showcase publishes its handle as window.gcodePreview after `ready` (devtools/
  inspection convenience, mirroring the Feature Lab's window.viewer; also what the
  documentation screenshot harness composites through).
- Web Component: on build-complete, a null getRenderStats() read now renders nothing
  instead of "(no stats — renderer not ready)", matching the three framework
  showcases (stats populate a tick after build-complete; the button reads on demand).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rfaces

Add a 2026-08-29 (DD-031) coverage-delta section: the Feature Lab rebuild and the
four two-tier adapter examples are new *demonstration surfaces* (no new engine
capability), and getRenderStats/pickSegment are now reachable through the public
adapter surface. Update section 10's adapter row + a capability-aware-UX row.

Honest media status: dark app-UI review screenshots were captured but are NOT yet
canonical docs/media assets — the manifest harness produces the mid-grey capability
presentation, not app chrome. Deferred (recorded) to the next Visual Review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…minimals (DD-031 live-pass)

Fixes from the owner's live UX pass:

- Feature Lab: the rail-collapse (☰) button was pinned to the viewport's top-right
  corner, overlapping the camera cluster's projection (perspective/orthographic)
  toggle. Moved it to a vertically-centered handle on the rail seam, clear of the
  camera controls.
- Web Component showcase: "Show travel moves" read as off (checkbox unchecked) but
  travel still rendered — the element keeps its own defaults (showTravel=true) and
  the showcase never pushed the initial state. Now applies the initial toggle state
  on startup, so the control matches what's drawn. (The framework showcases bind
  showTravel declaratively and already applied it on mount.)
- Minimals (all four): default travel moves off (showTravel={false}) for a clean
  first-render, matching the showcases.

Verified headless: Feature Lab camera cluster unobstructed; WC showcase travel off
by default and toggles on correctly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…apter (DD-031)

Make interactive source-model viewing (STL/3MF) a first-class, declarative half of
the SDK — the Prepare side alongside the toolpath Preview side (owner decision).

gcode-model-renderer (new, framework-neutral):
- createModelPreviewController — the Prepare-side analogue of gcode-preview-core's
  toolpath controller: lazy engine on bindCanvas (the engine takes its canvas at
  construction; the controller defers + rebuilds on canvas replace, replaying the last
  source), an op queue, and a reactive state snapshot (getState/onStateChange) derived
  from the engine's events. Wraps the existing createModelViewer unchanged (no renderer
  redesign). ModelPreviewControls/State contract exported.
- /testing subpath: runModelBehavioralSuite + controls/state completeness parity guards
  + shared stub GL/controls + STL/coloured source makers.

gcode-preview-react/model (new subpath):
- useModelViewer hook (useSyncExternalStore over the controller) + <ModelViewer>
  component shell. Thin bridges — never a separate viewer.

Tests: model-renderer 69 (controller: lazy bind, pre-bind queue, capability passthrough,
rebind-replay, unsupported-renderer); react 20 (model behavioral suite: both parity
guards pass through the adapter). No regressions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rs (DD-031)

Complete the model-viewer adapter family — source-model (Prepare) viewing now has
first-class declarative parity across all four frameworks, each a thin shell over the
shared createModelPreviewController (never a separate viewer):

- gcode-preview-vue/model — useModelViewer composable + <ModelViewer> component.
- gcode-preview-svelte/model — createModelViewer store/action + ModelViewer.svelte
  (raw component via the /model/ModelViewer.svelte subpath + copy-svelte step).
- gcode-preview-element/model — <gcode-model-viewer> element + defineGcodeModelViewer
  (+ /model/define auto-register subpath); tag avoids the reserved <model-viewer>.

Each adds the gcode-model-renderer dep + a /model subpath export, and runs the portable
runModelBehavioralSuite with both parity guards (controls + state completeness) through
its own public surface.

Tests green, no regressions: vue 39 (33+6), svelte 22 (16+6), element 23 (17+6),
react 20 (14+6), model-renderer 69.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…showcase (DD-031)

- demo-kit/models.js: synthetic MIT-clean source-model fixtures (STL tower →
  materials unavailable; colored 3MF → materials known), each source() returning a
  ready ModelSourceInput. Plus model-3mf-fixture.js (the generated base64 3MF).
- example-react showcase: a Preview/Prepare mode toggle demonstrates both halves of
  the SDK in one app — <GcodePreview> (sliced G-code) and <ModelViewer> (source model,
  via /model), with the model side surfacing the materials capability tier + object/
  placement counts.
- example-react: new model.html minimal — the smallest <ModelViewer source> integration,
  linked from the landing as a third tier.

Verified headless: Prepare loads the colored 3MF (3 objects, materials KNOWN), toggles
back to Preview cleanly; minimal model loads the STL (1 object, materials unavailable).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ll showcases (DD-031)

Demonstrate both halves of the SDK everywhere consumers look — sliced G-code (Preview)
and source models (Prepare), like a slicer's two modes:

- Feature Lab (tools/demo): a Preview/Prepare header toggle swaps the toolpath viewer
  for a source-model viewer (lazy createModelPreviewController on #modelView), a Prepare
  tab + "Source model" panel (objects/placements/materials tier/plates), fixtures swap to
  the model set, camera presets route to the active viewer.
- Vue / Svelte / Web Component showcases: the same Preview/Prepare toggle via each
  framework's <ModelViewer> adapter, mirroring the React reference (built by subagents;
  reviewed + verified). Fixed a Svelte var collision (the color-mode item was named
  `mode`, clobbering the workflow `mode` → Prepare never activated; renamed to
  colorModeItem).
- Minimal model page per framework (model.html + a tiny <ModelViewer source> file),
  linked from each landing as a third tier — a discoverable smallest model integration.
- demo-kit: models.js already added (synthetic STL + colored 3MF fixtures).

Verified headless across all five surfaces: Prepare loads the colored 3MF (3 objects,
materials KNOWN) and toggles back to Preview (454 seg / 14 layers) cleanly; minimals load
the STL (1 object, materials unavailable). All builds clean, zero console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-031)

Both had a `display` rule that beat the UA [hidden] rule, so in Prepare the Feature
Lab still showed the toolpath "N segments / M layers" count pill (misleading beside a
source model) and the layers/segments/time scrub strip (inert for a model). Add
[hidden] guards + hide the scrub strip on mode switch. The rail "Source model" panel
already carries the model's object/placement/materials info.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- adapters.md: new "Two viewers: Preview and Prepare" section (the two halves of the
  SDK, the /model subpath, per-framework import table); examples note the model tier;
  <gcode-model-viewer> tag noted.
- 4 adapter READMEs: a "Model viewing (Prepare side)" section each (framework import +
  minimal example + honest materials-tier note + pointer to model.html); model-renderer
  README documents createModelPreviewController + the /testing suite.
- CLAUDE.md parity check: covers both viewer surfaces + the model parity guard.
- VISUAL_FEATURE_COVERAGE.md: interactive model viewer now demonstrated everywhere;
  new model-adapter row; DD-031 delta records the Prepare integration.
- changeset: model-renderer + 4 adapters minor (createModelPreviewController + /model
  subpaths); additive, toolpath-only consumers don't pull the model renderer.

docs:links OK (250).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…itest (DD-031)

CI's test:packages runs the adapter suites against sibling workspaces resolved from
SOURCE via vitest aliases (no built dist required) — the model behavioral suite broke
that by importing @chestnutlabs/gcode-model-renderer/testing, which only resolved from
built dist locally. Add source aliases for gcode-model-renderer, its /testing subpath,
and its transitive gcode-containers to all four adapter vitest configs, matching the
existing gcode-preview-core/testing aliasing.

Verified: with packages/gcode-model-renderer/dist removed, the model behavioral suite
still passes via source. All four adapter suites green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…del adapters (DD-031)

Address the defects the release gate surfaced on the model-adapter work:

- consumer-vue fixture: add gcode-model-renderer to the pack/build list + fixture deps
  and regenerate the lockfile — the Vue package's new dependency was unresolvable (its
  dist was never built in the fixture, and its transitive @ChestnutLabs deps resolved
  from the registry instead of the local tarballs, breaking the D3 reproducibility guard).
- pack-check: regenerate snapshots for the new model dist files (model-preview,
  model-testing, and each adapter's dist/model/*), and add the raw
  ./model/ModelViewer.svelte entrypoint to the documented attw exclusion (same reason as
  ./GcodePreview.svelte — consumer-compiled, attw can't model it).
- prettier: format the model-adapter + demo/example files.

Full local gate sweep green: lint, typeCheck, build, test (292), test:packages,
test:consumer-vue, pack:check, license:check, docs:links.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…CI run (DD-031)

The feature branch's first CI run flagged dormant issues:
- tools/pack-check.mjs: prettier formatting of the edited attw exclusion.
- tools/demo/src/main.js: drop the now-unused `bytes` import and `$` helper.
- capture.test.ts: annotate the intentional definite-assignment forward reference
  (prefer-const) that the stub↔renderer construction cycle requires.

Full lint green (0 errors).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat(DD-031): consumer UX + framework parity + source-model adapter family
* release: version packages (lockstep)

* docs: fold v0.20.0 release notes + resolve the release review

- docs/README "Current state" leads with v0.20.0 (source-model viewing as a
  first-class declarative half of the SDK + toolpath dark-capability closure +
  Feature Lab + two-tier examples, DD-031); v0.19.0 demoted to Prior. Release-history
  line appended.
- RELEASE_REVIEW.md: all seven changed packages reviewed; Product/Docs/Visual markers
  resolved, with reconciliation notes (incl. the deferred app-UI media + the two-surface
  parity coverage). RELEASE_NOTES_DRAFT.md folded in and removed.

docs:release-check PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathaniel Chestnut <sobechestnut-dev@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@sobechestnut-dev
sobechestnut-dev merged commit 887ef7c into main Aug 30, 2026
9 checks passed

This branch was previously deployed

1 inactive deployment
github-pages — c6b819c1 Deployed Aug 30, 2026 by sobechestnut-dev via deploy #174
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant