three-slicer 0.1.6 → 0.2.0
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 +35 -0
- package/README.md +310 -22
- package/THIRD-PARTY-NOTICES.md +37 -0
- package/components/README.md +2 -0
- package/components/dist/SettingsPanel.js +92 -92
- package/data/config-schema.json +698 -0
- package/data/filaments.js +1 -1
- package/data/preset-keys.json +1 -0
- package/data/printers.json +1 -1
- package/data/processes.js +1 -1
- package/data/ui-tree.json +342 -0
- package/engine/README.md +279 -3
- package/engine/examples/sla_headless.mjs +51 -0
- package/engine/index.d.ts +77 -5
- package/engine/index.js +15 -4
- package/engine/src/client.js +165 -0
- package/engine/src/data.js +3 -0
- package/engine/src/preset_file.js +99 -0
- package/engine/src/settings.js +232 -0
- package/engine/src/sla_core.js +188 -0
- package/engine/src/sla_request.js +185 -0
- package/engine/src/slicer.worker.js +76 -4
- package/engine/src/slicer_core.js +0 -0
- package/engine/src/slicer_core.mt.js +0 -0
- package/package.json +26 -11
- package/types/client.d.ts +88 -0
- package/types/components.d.ts +10 -0
- package/types/data/preset-keys.json.d.ts +20 -0
- package/types/data/printers.json.d.ts +2 -2
- package/types/data.d.ts +4 -0
- package/types/settings-keys.d.ts +107 -1
- package/types/settings.d.ts +116 -1
- package/types/sla.d.ts +167 -0
- package/types/viewer.d.ts +59 -1
- package/types/worker.d.ts +95 -0
- package/viewer/README.md +163 -3
- package/viewer/dist/Viewport.js +3633 -3137
- package/viewer/dist/model_loaders.js +1 -1
- package/viewer/dist/parse_3mf-C2X_W442.js +300 -0
- package/viewer/dist/parse_3mf.worker.js +1 -1
- package/viewer/styles.css +5 -0
- package/types/gen_settings_types.mjs +0 -70
- package/viewer/dist/parse_3mf-8oCnCJNK.js +0 -216
package/viewer/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|

|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm i three-slicer
|
|
8
|
+
npm i three-slicer react react-dom three # the three are optional peers; the viewer needs all of them
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
```jsx
|
|
@@ -14,12 +14,26 @@ import Viewport from 'three-slicer/viewer'
|
|
|
14
14
|
|
|
15
15
|
function App() {
|
|
16
16
|
const [settings, setSettings] = useState({}) // OrcaSlicer schema keys; sparse — defaults fill the rest
|
|
17
|
-
|
|
17
|
+
// The container matters — see Layout below.
|
|
18
|
+
return (
|
|
19
|
+
<div style={{ position: 'relative', width: '100%', height: '100vh' }}>
|
|
20
|
+
<Viewport settings={settings} setSettings={setSettings} />
|
|
21
|
+
</div>
|
|
22
|
+
)
|
|
18
23
|
}
|
|
19
24
|
```
|
|
20
25
|
|
|
21
26
|
Styles are injected into the component's Shadow DOM root — nothing to import, and host CSS cannot collide.
|
|
22
27
|
|
|
28
|
+
## Layout
|
|
29
|
+
|
|
30
|
+
**Give it a positioned, sized container.** The shadow host is `display: contents`, so it contributes no box of its
|
|
31
|
+
own, and the shell inside is `position: absolute; inset: 0`. It therefore fills the nearest *positioned* ancestor —
|
|
32
|
+
`position: relative` (or absolute/fixed) with a real height. Drop it into a plain static `<div>` and it escapes to
|
|
33
|
+
the initial containing block instead, which usually looks like the viewer covering the whole page.
|
|
34
|
+
|
|
35
|
+
There is no width or height prop: the component always fills that container, and resizes with it.
|
|
36
|
+
|
|
23
37
|
Slice parameters are derived from `settings` via `three-slicer`'s schema mapping — pair it with `three-slicer/components`' `<SettingsPanel/>` sharing the same state for a full slicer UI.
|
|
24
38
|
|
|
25
39
|
A `.3mf` written by a slicer (OrcaSlicer/BambuStudio save, MakerWorld download) imports as a **project**: plate layout, project settings, and support/material painting are restored, not just the meshes. Where a facet carries both paint kinds, material paint wins and the dropped support paint is reported.
|
|
@@ -49,7 +63,13 @@ Every panel can be switched off, and the values the component owns can be seeded
|
|
|
49
63
|
- **`panels`** — `{name: false}` hides one. Everything is visible by default, so a host only ever opts out and a
|
|
50
64
|
panel added in a later version does not vanish for hosts that listed the ones they wanted. `sidebar: false` drops
|
|
51
65
|
the whole right column; the rest are `topBar`, `gizmoRail`, `objectToolbar`, `paintPanel`, `statsCard`, `plateBar`,
|
|
52
|
-
`emptyHint`, `status`, `printerCard`, `filamentCard`, `objectList`, `previewControls`, `processCard`,
|
|
66
|
+
`emptyHint`, `status`, `printerCard`, `filamentCard`, `resinCard`, `objectList`, `previewControls`, `processCard`,
|
|
67
|
+
`sliceBar`. Which of `filamentCard`/`resinCard` renders follows the printer profile's technology: a profile whose
|
|
68
|
+
`printer_technology` says SLA swaps the filament card (and the prime tower, and the painting brushes) for the
|
|
69
|
+
resin card, and slicing routes to the kernel's `slice_sla` — PrusaSlicer's ported support/pad chain — with an
|
|
70
|
+
`.sl1` export instead of G-code (portrait masks, like every SL1-family machine). The preview lifts the model by
|
|
71
|
+
`stats.lift_layers` (pad + elevation), and a request the port does not cover (hollowing, organic trees,
|
|
72
|
+
`pad_around_object`) surfaces as a typed error instead of a wrong print.
|
|
53
73
|
- **`gcode`** — G-code text drawn on the selected plate instead of a slice result. `parseGcode` recovers roles from
|
|
54
74
|
`;TYPE:` (OrcaSlicer/PrusaSlicer/Cura), from `;_EXTRUSION_ROLE:` tags and from this kernel's own feature comments;
|
|
55
75
|
bead width comes from `;WIDTH:` or, absent that, from E. What the file never states cannot be recovered: an
|
|
@@ -63,6 +83,55 @@ Every panel can be switched off, and the values the component owns can be seeded
|
|
|
63
83
|
second while slicing.
|
|
64
84
|
- **`onSliced`** — `{plate, stats, gcode}` when a slice is cached. Switching plate tabs does not re-fire it.
|
|
65
85
|
|
|
86
|
+
## Keyboard and mouse
|
|
87
|
+
|
|
88
|
+
Which keys are live depends on the tab, and every one is ignored while an input has focus. Letter shortcuts match
|
|
89
|
+
the **physical** key, so they keep working under a non-Latin keyboard layout — with an IME on, the Korean layout
|
|
90
|
+
reports `'ㅁ'` for M, and matching on the character would silently kill every letter shortcut while leaving the
|
|
91
|
+
arrows and Delete working.
|
|
92
|
+
|
|
93
|
+
| Both tabs | |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| `Ctrl/⌘ + R` | Slice the current plate |
|
|
96
|
+
| `Ctrl/⌘ + C` / `V` / `X` | Copy · paste · cut the selection |
|
|
97
|
+
| `Ctrl/⌘ + K` or `Ctrl/⌘ + D` | Duplicate |
|
|
98
|
+
| `Ctrl/⌘ + A` | Select all |
|
|
99
|
+
| `Ctrl/⌘ + Z` | Undo — bound to the component root, so it never reaches your app's own Ctrl+Z |
|
|
100
|
+
| `Ctrl/⌘ + Shift + Z` or `Ctrl/⌘ + Y` | Redo |
|
|
101
|
+
|
|
102
|
+
| Prepare | |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| `M` or `G` · `R` · `S` | Move · rotate · scale gizmo |
|
|
105
|
+
| `Arrow keys` | Nudge 10mm — `Shift` for 1mm |
|
|
106
|
+
| `PageUp` / `PageDown` | Rotate ±45° |
|
|
107
|
+
| `Delete` / `Backspace` | Remove the selection |
|
|
108
|
+
| `Z` · `B` | Zoom to all · zoom to bed |
|
|
109
|
+
| `Esc` | Cancel the current tool |
|
|
110
|
+
| `?` | Shortcut help overlay |
|
|
111
|
+
|
|
112
|
+
| Preview | |
|
|
113
|
+
| --- | --- |
|
|
114
|
+
| `↑` / `↓` | Step one layer — `Shift` for ten |
|
|
115
|
+
| `L` · `T` | Single-layer view · travel moves |
|
|
116
|
+
| `Z` · `B` | Zoom to all · zoom to bed |
|
|
117
|
+
| `Esc` | Back to Prepare |
|
|
118
|
+
|
|
119
|
+
Mouse selection follows upstream's rules: a plain click **replaces** the selection, `Ctrl/⌘ + click` adds or
|
|
120
|
+
removes, a plain click on something already selected **keeps** the set (which is what makes dragging several
|
|
121
|
+
objects work), `Shift + drag` is a box select, and clicking empty space clears. Alt is not a de-select, in
|
|
122
|
+
upstream or here.
|
|
123
|
+
|
|
124
|
+
## Undo and redo
|
|
125
|
+
|
|
126
|
+
The history covers the viewport's **own** state: object transforms, additions, removals, per-object extruder and
|
|
127
|
+
visibility. Fifty steps, with repeats of the same action inside half a second folded into one — so a held arrow key
|
|
128
|
+
undoes as a single move rather than forty.
|
|
129
|
+
|
|
130
|
+
What it deliberately does not cover, and why the boundary sits there: `settings` is **yours**, passed in as a prop,
|
|
131
|
+
so nothing inside the component can put it back. Painting is outside it too (restoring a step would need a kernel
|
|
132
|
+
re-`prepare` for every entry), as are the prime tower and the plate count, which write host settings. If you want
|
|
133
|
+
those undoable, undo them on your side of the prop.
|
|
134
|
+
|
|
66
135
|
## Materials and painting
|
|
67
136
|
|
|
68
137
|
The filament card holds **one material per extruder**: add an extruder, pick its colour, and pick its filament preset from the vendor catalog (`filamentPresets()` in `three-slicer/settings` — the shortlist is the printer model's own recommendation, the full list everything compatible). Selecting a row aims the material picker and the settings form at that extruder; the colours feed the object meshes, the prime tower and the preview's **Filament** view type, which colours every segment by the extruder that printed it.
|
|
@@ -76,6 +145,97 @@ Two limits to expect while using it:
|
|
|
76
145
|
|
|
77
146
|
If you consume `three-slicer/viewer/toolpath` directly, note that the stride-8 role field `paths[k+3]` now carries the printing extruder alongside the role as `role + tool * 16`. Mask it — `& 15` for the role, `>>> 4` for the tool. Streams produced before this encoding are entirely below 16 and decode to their own role with tool 0, so older data still reads correctly.
|
|
78
147
|
|
|
148
|
+
## Turning behaviour off
|
|
149
|
+
|
|
150
|
+
`panels` controls what is drawn; `features` controls what the component *does* outside its own box. Same rule —
|
|
151
|
+
opt-out only, everything on unless you say `false`, an unknown key stays on.
|
|
152
|
+
|
|
153
|
+
```jsx
|
|
154
|
+
<Viewport
|
|
155
|
+
gcode={text}
|
|
156
|
+
panels={{ sidebar: false, topBar: false }}
|
|
157
|
+
features={{ warmup: false, shortcuts: false, logs: false }}
|
|
158
|
+
/>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
| Key | Off means |
|
|
162
|
+
| --- | --- |
|
|
163
|
+
| `shortcuts` | No keyboard bindings. They are installed on `window`, so while the viewer is mounted they fire wherever focus is (inputs excepted) — and `Ctrl+C` preventDefaults, which takes a host page's own copy. Turn them off when your app has its own. |
|
|
164
|
+
| `warmup` | The WASM kernel is not loaded on mount. Nothing is downloaded or compiled until something actually slices — which for a `gcode`-only viewer is never, so this is several megabytes and a thread pool you stop paying for. |
|
|
165
|
+
| `drop` | No drag and drop onto the canvas. |
|
|
166
|
+
| `filePicker` | The file dialog never opens, from any of the buttons that open it. |
|
|
167
|
+
| `contextMenu` | No right-click menu. The browser's own menu stays suppressed over the canvas either way — OrbitControls preventDefaults `contextmenu` itself. |
|
|
168
|
+
| `logs` | No console output, from the component or from the slice worker. |
|
|
169
|
+
|
|
170
|
+
### Read-only panels
|
|
171
|
+
|
|
172
|
+
A sidebar panel can also be shown but not editable — the shape you want when the host picks the printer, process
|
|
173
|
+
and filament itself and does not want the user changing them. It is a third value on the same `panels` key:
|
|
174
|
+
|
|
175
|
+
```jsx
|
|
176
|
+
<Viewport
|
|
177
|
+
settings={presetSettings}
|
|
178
|
+
panels={{ printerCard: 'readonly', filamentCard: 'readonly', processCard: 'readonly' }}
|
|
179
|
+
/>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Lockable: `sidebar`, `printerCard`, `filamentCard`, `objectList`, `towerCard`, `previewControls`, `processCard`,
|
|
183
|
+
`sliceBar`. `sidebar: 'readonly'` locks the whole column at once; the per-card keys are for mixing, such as a
|
|
184
|
+
locked printer card above a live object list. Every other panel takes `true`/`false` only — a `'readonly'` that
|
|
185
|
+
silently did nothing on half the keys would be worse than not offering it.
|
|
186
|
+
|
|
187
|
+
The panel is drawn normally and keeps showing real values; it just cannot be clicked, typed into or tabbed to, and
|
|
188
|
+
that includes any node you passed into it (`motionPanel`, `filamentPanel`, `processPanel`). Implemented with the
|
|
189
|
+
`inert` attribute, so it needs Chrome 102+, Safari 15.5+ or Firefox 112+.
|
|
190
|
+
|
|
191
|
+
**It locks the UI path, not the value.** `settings` is still your prop, and other paths inside the viewer still
|
|
192
|
+
write it — importing a 3mf project applies that project's settings whether or not the cards are locked.
|
|
193
|
+
|
|
194
|
+
### Printer preset files
|
|
195
|
+
|
|
196
|
+
The printer card carries **Load** and **Save**. Save writes an OrcaSlicer preset: a machine `.json` on its own, or
|
|
197
|
+
an `.orca_printer` bundle when the settings map also names a process or filament preset (the cards record those as
|
|
198
|
+
`printer_settings_id` / `print_settings_id` / `filament_settings_id`, so nothing extra has to be tracked). Load
|
|
199
|
+
accepts the same set upstream's dialog does — `.json`, `.orca_printer`, `.orca_bundle`, `.orca_filament`, `.zip` —
|
|
200
|
+
and applies every preset it finds, clearing that type's keys first.
|
|
201
|
+
|
|
202
|
+
`inherits` is followed through the shipped printer catalog, so a vendor file loads with its bed intact; when the
|
|
203
|
+
parent is unknown the file's own values are still applied and the notice says so. Codec details and the reason
|
|
204
|
+
that matters are in the [package README](../README.md#preset-files).
|
|
205
|
+
|
|
206
|
+
Load opens a file dialog, so it respects `features.filePicker`; Save goes through `onExport` like every other
|
|
207
|
+
download.
|
|
208
|
+
|
|
209
|
+
### Taking the saves
|
|
210
|
+
|
|
211
|
+
The save buttons are inside the component, so `onExport` is the only way to send a file somewhere other than the
|
|
212
|
+
browser's download folder. It sees the 3mf project, the STL and each plate's G-code. Return truthy to say you
|
|
213
|
+
handled it:
|
|
214
|
+
|
|
215
|
+
```jsx
|
|
216
|
+
<Viewport onExport={(file, filename) => { uploadToServer(file, filename); return true }} />
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Return nothing and the download happens as well, which is useful for logging what was saved without changing it.
|
|
220
|
+
|
|
221
|
+
## What the host cannot drive
|
|
222
|
+
|
|
223
|
+
The component owns its scene, and the props are the whole interface — there is no ref, no imperative handle, and no
|
|
224
|
+
`models` prop. Worth knowing before you design around it:
|
|
225
|
+
|
|
226
|
+
- **Models enter through the UI only** — the file dialog or drag and drop. A host cannot hand a mesh in, and cannot
|
|
227
|
+
remove or transform one. What it *can* do is watch: the `objects` event reports `{id, name, extruder, visible}`
|
|
228
|
+
for every object as the set changes.
|
|
229
|
+
- **Slicing is triggered from the UI or by `defaultAutoSlice`**, which unlike the in-app toggle also performs the
|
|
230
|
+
first slice — that is what makes a panel-less embed able to slice at all. The result arrives on `onSliced`.
|
|
231
|
+
- **`gcode` is one-way**: pass G-code text and it is drawn on the selected plate instead of a slice result, and
|
|
232
|
+
auto re-slice leaves that plate alone while it is set.
|
|
233
|
+
- Everything else the component owns — camera, selection, plate count, paint state — is reported through `onEvent`
|
|
234
|
+
and settable only by the user.
|
|
235
|
+
|
|
236
|
+
If you need programmatic control over the scene, build on the subpath exports (`three-slicer/viewer/toolpath`,
|
|
237
|
+
`/loaders`, `/gcode`) and `three-slicer/client` rather than on `<Viewport/>`.
|
|
238
|
+
|
|
79
239
|
## Multithreaded slicing (automatic)
|
|
80
240
|
|
|
81
241
|
The engine ships two WASM kernels: single-threaded (default) and `-pthread` multithreaded (~2× wall-clock on layer-parallel wall generation, measured 12× on the wall pass itself). The worker picks the mt kernel automatically when the page is [cross-origin isolated](https://developer.mozilla.org/en-US/docs/Web/API/Window/crossOriginIsolated) — i.e. served with:
|