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, and
Svelte integrations that are thin adapters over one shared, framework-neutral engine.
Status: published. All ten
@chestnutlabs/*packages are on npm (latestv0.2.0, lockstep-versioned with npm provenance). E0–E9 of the master plan are closed; E10 (motion-model correctness) is in progress. Install from npm — see Quick start below.

GcodeParseSession) with streaming input,
progressive preview for large files, resource limits, and an adversarial-input corpus behind it.known | inferred | approximated | unavailable — the stack refuses to
fabricate what it cannot know..gcode.3mf container support — zero-dependency, bounded ZIP extraction with multi-plate
selection, hardened against adversarial archives.ToolpathIR) — structure-of-arrays geometry + metadata + source
index; the seam between parsing and everything else.ProgressObservation contract
mapped onto the toolpath with tiered confidence: a precise cut + marker when the source position
is known, an uncertainty band when it is approximated, stale-signal handling, and user scrub
always winning.<GcodePreview> component and
a lower-level surface, with the same capabilities, options, events, and TypeScript contracts,
enforced by a shared behavioral suite that runs against all three in CI.| Honest live progress | Layer clipping & scrub |
|---|---|
![]() |
![]() |
| Completed cut + translucent remaining-path ghost + byte-exact position marker (uncertainty band when the signal is approximate) | Draw-range layer clipping — no geometry rebuilds; segment-level scrub works the same way |
| Package | What it is |
|---|---|
@chestnutlabs/toolpath-core |
ToolpathIR, capability model, progress mapping |
@chestnutlabs/gcode-parser |
Worker parse core + session client (streaming, limits, workers) |
@chestnutlabs/gcode-dialects |
Slicer/firmware dialect annotators |
@chestnutlabs/gcode-containers |
.gcode.3mf / ZIP container adapters |
@chestnutlabs/gcode-renderer-three |
Three.js toolpath renderer (peer: three) |
@chestnutlabs/gcode-preview-core |
Framework-neutral preview controller + portable behavioral suite |
@chestnutlabs/gcode-preview-vue |
Vue 3 component + useGcodePreview() composable |
@chestnutlabs/gcode-preview-react |
React component + useGcodePreview() hook |
@chestnutlabs/gcode-preview-svelte |
Svelte component + createGcodePreview() store/action |
@chestnutlabs/gcode-preview-element |
Framework-free <gcode-preview> Web Component (no peer framework) |
Install the adapter for your framework plus three (the renderer declares three as a
peerDependency, range ^0.178.0 — npm ≥ 7 installs it automatically; pnpm/yarn users add it
explicitly):
npm install @chestnutlabs/gcode-preview-vue three # or -react / -svelte
Each adapter has two adoption levels — a complete component, and a lower-level API for building your own controls (composable / hook / store) — documented in its package README.
<script setup>
import { GcodePreview } from '@chestnutlabs/gcode-preview-vue';
import { shallowRef } from 'vue';
const file = shallowRef(null);
</script>
<template>
<input type="file" accept=".gcode,.3mf" @change="file = $event.target.files?.[0] ?? null" />
<div style="height: 70vh">
<GcodePreview :source="file" @ready="(s) => console.log(`${s.segments} segments`)" />
</div>
</template>
Lower level: useGcodePreview() — canvas ref, worker
parse, controls, reactive state summaries.
import { GcodePreview } from '@chestnutlabs/gcode-preview-react';
function Viewer({ file }) {
return (
<div style={{ height: '70vh' }}>
<GcodePreview source={file} onReady={(s) => console.log(`${s.segments} segments`)} />
</div>
);
}
StrictMode-safe. Lower level: useGcodePreview()
(useSyncExternalStore-backed state, identity-stable handle).
<script>
import GcodePreview from '@chestnutlabs/gcode-preview-svelte/GcodePreview.svelte';
let file = null;
</script>
<div style="height: 70vh">
<GcodePreview source={file} on:ready={(e) => console.log(`${e.detail.segments} segments`)} />
</div>
Ships as raw .svelte (your bundler's Svelte plugin compiles it). Lower level:
createGcodePreview() — store contract +
use: canvas action.
All three components share the same defaulted prop surface — source, parseOptions,
buildVolume, quality, colorMode, layerRange, scrub, showTravel, progress,
createWorker — with matching events/callbacks. <GcodePreview source={file} /> is the whole
thin path; the full viewer is reachable without switching APIs.
.gcode.3mf support — via the bundler-native new Worker(new URL(...)) pattern.
Vite resolves it out of the box (tested in CI).createWorker for the slim build, custom dialect adapters, other bundlers, or
strict-CSP environments. Both paths are documented in the
Vue package README (shared across adapters by design)..gcode (plain), .gcode.3mf (sliced-plate container; multi-plate via
parseOptions.plate).G90/G91), extruder mode (M82/M83), and the G92 E-datum are modeled
(E10 phase 1); arc planes (G17–G19) and work-coordinate systems are still in progress — see
G-code motion coverage.renderStill — a single
non-interactive image from a Worker OffscreenCanvas, Electron hidden window, or headless
Chromium (server-side thumbnails).tools/demo — the showcase: full control panel over the whole pipeline (corpus picker,
dialect annotations, quality/color modes, layer clip + scrub, simulated live-progress tiers),
plus a Vue-component parity page and the visual-regression harness. npm run dev inside the
directory.tools/example-react, tools/example-svelte — complete Vite apps per framework, run the same
way. All three apps consume the packages exactly as an external consumer would.Docs-first: every architecture-sensitive epic passes a Design Document gate before
implementation. The master plan controls direction; the
docs index tracks epic status; accepted designs live in
docs/design/. Current state: E0–E9 closed and accepted (parser, dialects,
containers, renderer, live progress, multi-framework integration, the v0.1.0 release, and
v0.2.0's toolpath annotations + renderer options); E10 (motion-model correctness) is in
progress — its phase 1 (M82/M83, G90/G91, the G92 E-datum) has shipped, with arc
planes and coordinate systems to follow.
Contributions: see CONTRIBUTING.md · security policy: SECURITY.md.
# Node >= 22
npm ci
npm run build # inherited engine build (rollup)
npm run test # root suite (IR goldens, manifest validation, adapters)
npm run test:packages # all workspace package suites
npm run lint && npm run typeCheck && npm run license:check
npm run test:consumer-vue # tarball consumer fixture
npm run pack:check # packaged-artifact gate (pack snapshots + publint + attw)
This project began as a fork of
xyz-tools/gcode-preview (project identity
remcoder/gcode-preview) by Remco Veldkamp and contributors, MIT-licensed. Chestnut Labs has
since rebuilt it into the worker-based multi-package stack described above; the inherited Git
history is preserved, upstream copyright notices are retained in LICENSE, and the
full attribution and provenance record lives in NOTICE.md,
docs/UPSTREAM_PROVENANCE.md, and the
upstream & licensing policy.
Upstream changes are adopted deliberately through review, never auto-synced.
MIT — inherited code © 2017–2025 Remco Veldkamp and the xyz-tools/gcode-preview
contributors; Chestnut Labs additions © 2026 Chestnut Labs.