three-slicer 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,142 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.2 — 2026-09-21
4
+
5
+ ### Added
6
+
7
+ - The prime tower is set per plate. The Prime tower card carries the same Global | Plate switch as the Process,
8
+ Printer and Filament cards: in plate scope its mode, width, purge destination and purging table become that
9
+ plate's override. The position was already per plate (`wipe_tower_x/y[plate]`) and stays in the global map.
10
+ - A saved `.3mf` carries the per-plate overrides and the global map's non-schema keys (`wipe_tower_real`,
11
+ `sla_antialias`) in a member of its own, `Metadata/three_slicer_settings.json`, and an import restores them.
12
+ Upstream has no place for either and ignores the member, so OrcaSlicer still opens the file on the global preset.
13
+ - The kernel can tag every extrusion run with upstream's `;TYPE:` (`gcode_role_tags`, opt-in; the viewer turns it
14
+ on), from the same role the preview draws. A saved G-code read back as text colours as the slice did.
15
+ - "Export all" writes one `.gcode.3mf` (upstream's "Export all plate sliced file") instead of one `.gcode` download
16
+ per plate: each plate's G-code as `Metadata/plate_N.gcode` with its MD5, the estimate in `slice_info.config`, no
17
+ meshes. Opening one (drop, picker or `files`) puts every plate's G-code back on its plate and makes the viewer
18
+ preview-only until it is closed from the top bar or a model is loaded. The `gcode` prop also takes a
19
+ `{ plateIndex: text }` map. A resin plate still exports as its own `.sl1`.
20
+ - The sidebar's Export G-code button saves every sliced plate in one `.gcode.3mf` (upstream's "Export all sliced
21
+ file"). Its ▾ menu holds the viewed plate alone as a `.gcode.3mf` and the plain `.gcode`. It also works on an
22
+ opened `.gcode.3mf`, so a print job can be saved again.
23
+
24
+ - The Open button and the drop target take a plain `.gcode` / `.gco` / `.g`. It opens on the selected plate
25
+ through the same path a `.gcode.3mf` takes: the top bar names it and closes it. A file with no printable move is
26
+ refused before it opens. The demo app's own Open G-code button is gone.
27
+ - An exported G-code states its filament colours (`; filament_colour` in the config block, where upstream reads
28
+ settings), so it opens in its colours here and in OrcaSlicer. A file that already states a palette keeps it; the
29
+ kernel's G-code itself is unchanged.
30
+
31
+ ### Changed
32
+
33
+ - The ring / real tower choice is the settings key `wipe_tower_real` (a viewer knob, like `sla_antialias`) instead
34
+ of component state, so it follows plate overrides and survives a save. Absent means the ring, as before.
35
+ - The tower stand-ins are decided per plate: a plate gets one only when it changes tools itself, and each plate
36
+ draws its own width and on/off. A dragged or typed tower position is kept on the bed.
37
+ - The tower stand-in is selected alone and only translated. It no longer joins a multi-selection, takes a
38
+ rotate/scale gizmo, or adds an undo entry that undid nothing.
39
+
40
+ ### Fixed
41
+
42
+ - An opened multi-material G-code drew its model as prime tower in the Feature view: the multi-material path wrote
43
+ no role marks, so everything after a tower's comment inherited it until the next layer.
44
+ - A loaded G-code was drawn in the session's palette instead of its own. The Filament view reads each plate's
45
+ palette from its result (the file's, with the session's filling the holes), and every tool the result used gets
46
+ a colour, so a file with more tools than the session has filaments no longer shows T3 in three different colours
47
+ across the toolpath, the stats card and the legend. The G-code reader reports per-tool filament
48
+ (`filament_mm_by_tool`).
49
+ - The drop overlay and the load-rejection message listed STL/OBJ/3MF/AMF/PLY by hand: neither named STEP, which the
50
+ demo registers, and the overlay named neither SL1 nor G-code. Both now read `SUPPORTED_EXT`.
51
+ - The G-code reader dropped a `;TYPE:` written between a layer marker and the layer's first move (Cura's
52
+ `;LAYER:` files, this kernel's raft layers), reading that run as wall.
53
+ - The drop highlight stayed on after a drop the host handled itself (the demo app's `.gcode` drop): the canvas's
54
+ own handler never ran and a drop fires no `dragleave`. The window's capture phase now clears it.
55
+ - Injected G-code moved half a bed off its plate whenever the plate grid was re-laid out (adding a plate, editing
56
+ the bed): the re-layout set every display offset to the plate origin, dropping the bed-corner offset injected
57
+ G-code carries. Offsets now move by the origin's delta.
58
+ - Two objects on the same spot sliced to nothing. The kernel slices the merge of every object as one mesh and filled
59
+ the layer loops even-odd, so coincident shells counted as "inside twice". Segments are now oriented by the facet
60
+ normal and filled NonZero, upstream's Regular slicing mode, in the FFF, multi-material and SLA paths. Measured: a
61
+ project imported twice printed 1,210 mm of a 42,984 mm model before, the full model now. Clean meshes slice the
62
+ same regions (0 area difference on the fixtures, under 0.0003 mm² per layer on the Benchy), but a loop can start
63
+ at a different vertex, so G-code of models other than the golden fixtures may differ in point order.
64
+ - A saved `.3mf` with a tower position on some plates and automatic placement on others wrote `null` into
65
+ `wipe_tower_x/y`. OrcaSlicer's loader stops reading the whole file at an array entry that is not a string, which
66
+ dropped the 17 settings after it, `z_hop` and `z_offset` among them. The hole is now written as the schema default
67
+ for upstream and kept as a hole in `Metadata/three_slicer_settings.json`.
68
+ - The GPU SL1 mask path (`sla_antialias`, `sl1_parity_gpu.js`) counted surfaces above the plane as a parity, so two
69
+ coincident objects came out empty in the masks while the slice and its supports treated them as solid. The count
70
+ is now signed by facing (NonZero), the kernel's fill rule.
71
+ - Painting one plate and then another discarded the first plate's paint, and a copy placed where the original sits on
72
+ its own plate took the original's paint over (the original then sliced single-material, the copy printed both).
73
+ Paint now lives on each object (`core/paint_store.js`): the selector is written back to it before it switches
74
+ mesh and loaded from it after; slice-all pool workers load their plate's paint; a 3mf save writes every plate's
75
+ brush strokes (it used to save them only for a single-plate project); copy, duplicate and paste carry the paint,
76
+ and a split hands each part the marks on its own facets.
77
+ - A brush stroke painted only the first object of the plate being painted: the hit facet was sent in the hit
78
+ object's own numbering, not the plate merge's. A stroke now also carries across plates — reaching an object on
79
+ another plate selects that plate and keeps painting there, and an object added to the plate while the brush is
80
+ open is painted too.
81
+ - Dragging a painted object no longer drags the paint of the other objects on its plate along with it.
82
+ - A paste pressed right after a copy pastes that copy; a double-pressed delete records one undo step; a drag
83
+ committed while a slice loads its plate's paint no longer reaches the worker before that slice.
84
+ - A paint export the worker fails no longer discards the unsaved strokes (the swap stops instead), and Clear
85
+ pressed during a plate switch clears the plate it lands on instead of doing nothing. Strokes made right after
86
+ switching between the support and material brushes are no longer saved as the other kind of paint.
87
+ - Switching between the support and material brushes with the section plane on no longer leaves the kernel a
88
+ shifted plane on plates past the first; support-only paint stays drawn after a drag on its plate; a slice that
89
+ leaves support paint out under material paint says so again.
90
+ - Paint for a filament that is not configured (T3 painted, then the list cut to two) no longer widens the extruder
91
+ count on a slice-all pool worker only; every path leaves it out and the slice says so.
92
+ Every plate's paint stays drawn, not only the plate being painted.
93
+ - Review fixes to the paint store, each reproduced before the fix: a slice-all pool worker printed the previous
94
+ plate's paint on an unpainted plate; opening the support brush filed another plate's material paint as support
95
+ paint; a 3mf save wrote every object under one paint attribute and let an empty support map hide material paint;
96
+ a worker replaced by the watchdog wiped the stored paint of the plate it held; and a save waiting on a worker
97
+ that was then terminated stayed on "Saving…" with the viewport blank. Worker replies now echo a `requestId`, so
98
+ an error reply ends only the request it belongs to.
99
+
100
+ ## 0.3.1 — 2026-09-16
101
+
102
+ ### Added
103
+
104
+ - `three-slicer-viewer/settings` (and so `three-slicer/settings`) exports the kernel derivation's own fallbacks:
105
+ `FFF_FALLBACKS`, `SLA_FALLBACKS`, `AUTO_LINE_WIDTH`, `BED_FALLBACK`, `MACHINE_LIMITS`. Frozen; they are the values
106
+ `deriveKernelParams` / `deriveSlaParams` use when neither the settings map nor the schema gives one, and they are
107
+ deliberately not the schema defaults.
108
+ - Theming: both shadow roots take their colours from 43 custom properties (`--vp-accent`, `--vp-dark-surface`,
109
+ `--vp-light-text`, …) a host can set on any ancestor. `VIEWER.md` ("Theming") lists them with their defaults.
110
+
111
+ ### Changed
112
+
113
+ - `deriveKernelParams` with an empty or malformed `printable_area` now derives a 200 x 200 bed (the schema's own
114
+ default), not 256 x 256. Every viewer fallback already assumed 200; a well-formed value is unaffected.
115
+ - `buildSegmentData(layers)` without a default line width falls back to 0.42 (the kernel's auto width), not 0.4.
116
+ Callers that pass one, as the viewer does, are unaffected.
117
+ - One grey for "no colour to read": a blank filament slot, a stats swatch past the palette, an unparseable hex in
118
+ the toolpath palette and an unpainted facet (`UNPAINTED_COLOR`) are all `#888888` (were four different greys).
119
+ - The toolpath legend (speed / fan / temperature views) falls back to the schema default for a value the settings
120
+ map holds but cannot parse, instead of literals that disagreed with it (support speed 35 vs 80, nozzle 210 vs 200).
121
+ - The stylesheets carried 152 literal colours, many of them near-identical shades of one role; each group now uses
122
+ its most common member, so a few shades move slightly. Visible: the "advanced" badge is the info blue
123
+ (`#2b6cff`, was `#3673c3`), the "simple" badge the accent green, and the prime-tower card's number inputs are
124
+ light like every other sidebar input (they were styled for the dark viewport).
125
+ - Vendor process presets now carry `support_type`, so applying one sets the support type it was authored with.
126
+
127
+ ### Fixed
128
+
129
+ - Importing a project that places objects on more than one plate failed with "dropPlateResult is not defined"
130
+ and left every object on the selected plate (since 0.2.5). `test_3mf_project.mjs` now loads a two-plate project
131
+ through the model loader.
132
+ - The Process card's Global|Plate toggle has the ↺ that drops the plate's whole override, like the other settings
133
+ cards; the viewer never passed it the handler.
134
+ - Importing a project kept its filament colours in the viewer but not in the settings map, so a blank entry saved
135
+ back as blank and a list past 16 filaments saved whole.
136
+ - `three-slicer@0.3.0` shipped a tool-state file under `types/.omc/`, and `three-slicer-viewer` would have shipped
137
+ one from `src/settings/.omc/`. Both `files` lists now end in `!**/.omc`, and `pack_check.sh` fails on any
138
+ dot-path in either tarball.
139
+
3
140
  ## 0.3.0 — 2026-09-08
4
141
 
5
142
  The viewer is its own package. Everything that displays — model loading, G-code parsing, the GPU toolpath
@@ -33,7 +170,7 @@ split followed is `packages/RELICENSE.md`.
33
170
  - The two packages publish as a **locked pair**: same version, and `three-slicer` pins `three-slicer-viewer`
34
171
  exactly (`test_version_lockstep.mjs`). A release goes through the root `Makefile` (`make publish`), which
35
172
  publishes the viewer first — the pin means `three-slicer@0.3.0` cannot be installed before it exists.
36
- - `packages-mit/` is mirrored to `github.com/kimgh06/three-slicer-viewer` (a `git subtree split`); the monorepo
173
+ - `viewer-package/` is mirrored to `github.com/kimgh06/three-slicer-viewer` (a `git subtree split`); the monorepo
37
174
  stays the source of truth.
38
175
 
39
176
  ### Fixed
package/README.md CHANGED
@@ -4,7 +4,7 @@ Browser/WASM 3D-printing slicer package derived from [OrcaSlicer](https://github
4
4
 
5
5
  The package is published as a single npm package, `three-slicer`, with subpath exports for the engine, viewer, components, worker, and extracted OrcaSlicer data.
6
6
 
7
- ![A sliced Benchy in the viewer's Preview tab — organic tree supports, per-feature toolpath colors, dual layer-range slider, filament and print-time estimates](https://raw.githubusercontent.com/kimgh06/Web_Three_Slicer/main/web/viewer/public/usage.png)
7
+ ![A sliced Benchy in the viewer's Preview tab — organic tree supports, per-feature toolpath colors, dual layer-range slider, filament and print-time estimates](https://raw.githubusercontent.com/kimgh06/Three_Slicer/main/web/viewer/public/usage.png)
8
8
 
9
9
  ## Links
10
10
 
@@ -14,7 +14,7 @@ The package is published as a single npm package, `three-slicer`, with subpath e
14
14
  composition. Which code carries which licence, and why: [`PROVENANCE.md`](PROVENANCE.md).
15
15
 
16
16
  - Package: [npmjs.com/package/three-slicer](https://www.npmjs.com/package/three-slicer)
17
- - Source: [kimgh06/Web_Three_Slicer](https://github.com/kimgh06/Web_Three_Slicer)
17
+ - Source: [kimgh06/Three_Slicer](https://github.com/kimgh06/Three_Slicer)
18
18
  - Demo: [slicer.kimgh06.com](https://slicer.kimgh06.com/)
19
19
 
20
20
  ## Start Here
@@ -25,7 +25,7 @@ reading whole; everything else is lookup.
25
25
  | Your case | Path | Copy this | Then read |
26
26
  | --- | --- | --- | --- |
27
27
  | "Just the numbers" — quotes, farms, automation. No UI, no React | **Headless** | [Quick Start: Headless Slicing](#quick-start-headless-slicing) | [engine/README](engine/README.md) (134 lines), params via [PARAMS.md](engine/PARAMS.md) as lookup |
28
- | A slicer inside your existing page | **Embed** | [Quick Start: React Viewer](#quick-start-react-viewer) | [viewer/README](../packages-mit/VIEWER.md) (330 lines — the props contracts live there) |
28
+ | A slicer inside your existing page | **Embed** | [Quick Start: React Viewer](#quick-start-react-viewer) | [viewer/README](../viewer-package/VIEWER.md) (330 lines — the props contracts live there) |
29
29
  | The full slicer UI — viewport + settings panel | **Full UI** | [Full React Example](#full-react-example) | viewer/README + [components/README](components/README.md) |
30
30
 
31
31
  Whichever path: read [Before You Ship](#before-you-ship) before deploying — those traps return plausible
@@ -172,7 +172,7 @@ export default function App() {
172
172
  `position: relative` and a real height. In a plain static `<div>` it escapes to the page instead. There is no width
173
173
  or height prop.
174
174
 
175
- The viewer handles model loading, drag and drop, transform controls, multi-plate layout, worker slicing, GPU toolpath preview, and G-code export. Its keyboard and mouse bindings, the undo boundary, and what a host cannot drive are documented in [../packages-mit/VIEWER.md](../packages-mit/VIEWER.md). It supports STL, OBJ, 3MF (including the production extension used by Orca/Bambu/Prusa), AMF, and PLY out of the box; other formats such as STEP can be added with `registerLoader()`. A `.3mf` written by a slicer is treated as a project, not just geometry: its plate layout, project settings, and support/material painting are restored on import (where a facet carries both paint kinds, material paint wins and the dropped support paint is reported). Viewer and component styles are bundled into their Shadow DOM roots, so host app CSS does not need to import package CSS.
175
+ The viewer handles model loading, drag and drop, transform controls, multi-plate layout, worker slicing, GPU toolpath preview, and G-code export. Its keyboard and mouse bindings, the undo boundary, and what a host cannot drive are documented in [../viewer-package/VIEWER.md](../viewer-package/VIEWER.md). It supports STL, OBJ, 3MF (including the production extension used by Orca/Bambu/Prusa), AMF, and PLY out of the box; other formats such as STEP can be added with `registerLoader()`. A `.3mf` written by a slicer is treated as a project, not just geometry: its plate layout, project settings, and support/material painting are restored on import (where a facet carries both paint kinds, material paint wins and the dropped support paint is reported). Viewer and component styles are bundled into their Shadow DOM roots, so host app CSS does not need to import package CSS.
176
176
 
177
177
  ## Quick Start: Settings Panel
178
178
 
@@ -277,7 +277,7 @@ Some of the connections are not imports, and knowing which is which explains mos
277
277
  | --- | --- | --- |
278
278
  | `wasm-core` → `engine` | `build.sh` (emscripten) commits its output into `engine/src/` | not an import — the golden byte-identical gate and the invariant suite verify kernel changes against the engine's output |
279
279
  | `data` → `engine`/`components`/`viewer` | `/data` subpath imports | the source of truth is `extract_all.py` over the upstream checkout |
280
- | `types` → `engine` | the generator **executes** `deriveKernelParams` (probing) and writes `engine/PARAMS.md` + `../packages-mit/src/settings/kernel_setting_keys.js` back into the engine | `test_kernel_params.mjs` is the staleness gate |
280
+ | `types` → `engine` | the generator **executes** `deriveKernelParams` (probing) and writes `engine/PARAMS.md` + `../viewer-package/src/settings/kernel_setting_keys.js` back into the engine | `test_kernel_params.mjs` is the staleness gate |
281
281
  | `types` → `data` | `gen_settings_types.mjs` generates `settings-keys.d.ts` (976 keys) from the schema | run automatically by the build |
282
282
  | `viewer` ↔ `components` | **no direct link** | the host shares one settings map with both as props, and mounts `<SettingsPanel embedded/>` into the viewer's panel slots |
283
283
  | inside `viewer` | `core` (pure, node-runnable) ← `scene` (three/DOM) ← `actions` ← `ui` | `test_layers.mjs` enforces the boundary |
@@ -392,7 +392,7 @@ options as arrays of strings — the same shape [3MF Projects](#3mf-projects) us
392
392
  through the same serializer.
393
393
 
394
394
  The viewer adds the zip forms and a UI: the printer card's **Load** and **Save** read and write these files, and a
395
- save routes through [`onExport`](../packages-mit/VIEWER.md#taking-the-saves) like every other download.
395
+ save routes through [`onExport`](../viewer-package/VIEWER.md#taking-the-saves) like every other download.
396
396
 
397
397
  ## Settings UI: Enable/Disable Rules
398
398
 
@@ -787,7 +787,7 @@ the layout by hand.
787
787
 
788
788
  ## Before You Ship
789
789
 
790
- The traps below were all hit while building the [integration demos](https://github.com/kimgh06/Web_Three_Slicer/tree/main/examples)
790
+ The traps below were all hit while building the [integration demos](https://github.com/kimgh06/Three_Slicer/tree/main/examples)
791
791
  and the live landing embed — each one returns something plausible instead of an error, which is why they
792
792
  are listed **in the order they bite**, not by topic. The later a trap fires, the more it costs — and none of
793
793
  them fails a build or throws, so nothing surfaces them for you.
@@ -837,4 +837,4 @@ production while `npm run dev` passed. The no-argument form now emits a real wor
837
837
 
838
838
  ## License
839
839
 
840
- AGPL-3.0-or-later. This package is derived from OrcaSlicer. Source is available at [kimgh06/Web_Three_Slicer](https://github.com/kimgh06/Web_Three_Slicer). If you embed it in a web app, make sure your app complies with the AGPL network-use requirements, including offering source code to users where required.
840
+ AGPL-3.0-or-later. This package is derived from OrcaSlicer. Source is available at [kimgh06/Three_Slicer](https://github.com/kimgh06/Three_Slicer). If you embed it in a web app, make sure your app complies with the AGPL network-use requirements, including offering source code to users where required.