three-slicer 0.1.0 → 0.1.1

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.
Files changed (58) hide show
  1. package/README.md +342 -24
  2. package/components/README.md +1 -1
  3. package/components/dist/SettingsPanel.js +3 -4
  4. package/engine/index.d.ts +3 -1
  5. package/engine/src/data.js +12 -0
  6. package/engine/src/settings.js +1 -1
  7. package/engine/src/slicer.worker.js +2 -1
  8. package/engine/src/slicer_core.js +0 -0
  9. package/engine/src/slicer_core.mt.js +0 -0
  10. package/engine/src/toggle_eval.js +1 -2
  11. package/package.json +54 -26
  12. package/types/components.d.ts +19 -0
  13. package/types/data/config-schema.json.d.ts +55 -0
  14. package/types/data/invalidation-map.json.d.ts +15 -0
  15. package/types/data/toggle-rules.json.d.ts +20 -0
  16. package/types/data/ui-tree.json.d.ts +19 -0
  17. package/types/data.d.ts +17 -0
  18. package/types/gen_settings_types.mjs +70 -0
  19. package/types/settings-keys.d.ts +1704 -0
  20. package/types/settings.d.ts +19 -0
  21. package/types/toggle.d.ts +22 -0
  22. package/types/viewer-loaders.d.ts +33 -0
  23. package/types/viewer-toolpath.d.ts +105 -0
  24. package/types/viewer.d.ts +15 -0
  25. package/types/wasm.d.ts +5 -0
  26. package/types/worker.d.ts +3 -0
  27. package/viewer/README.md +1 -1
  28. package/viewer/dist/Viewport.js +674 -617
  29. package/viewer/dist/model_loaders.js +220 -108
  30. package/viewer/styles.css +2 -0
  31. package/data/config-schema-builddump.json +0 -12921
  32. package/viewer/src/Viewport.jsx +0 -1353
  33. package/viewer/src/assets/add.svg +0 -1
  34. package/viewer/src/assets/arrange.svg +0 -1
  35. package/viewer/src/assets/boolean.svg +0 -1
  36. package/viewer/src/assets/cut.svg +0 -1
  37. package/viewer/src/assets/delete.svg +0 -1
  38. package/viewer/src/assets/deleteall.svg +0 -1
  39. package/viewer/src/assets/duplicate.svg +0 -1
  40. package/viewer/src/assets/measure.svg +0 -1
  41. package/viewer/src/assets/mmu.svg +0 -1
  42. package/viewer/src/assets/move.svg +0 -1
  43. package/viewer/src/assets/negative.svg +0 -1
  44. package/viewer/src/assets/onbed.svg +0 -1
  45. package/viewer/src/assets/open.svg +0 -1
  46. package/viewer/src/assets/orient.svg +0 -1
  47. package/viewer/src/assets/paint.svg +0 -1
  48. package/viewer/src/assets/rotate.svg +0 -1
  49. package/viewer/src/assets/scale.svg +0 -1
  50. package/viewer/src/assets/seam.svg +0 -1
  51. package/viewer/src/assets/split.svg +0 -1
  52. package/viewer/src/assets/textmark.svg +0 -1
  53. package/viewer/src/assets/varlayer.svg +0 -1
  54. package/viewer/src/icons.js +0 -23
  55. package/viewer/src/make_worker.js +0 -9
  56. package/viewer/src/model_loaders.js +0 -178
  57. package/viewer/src/shadow_host.jsx +0 -30
  58. package/viewer/src/toolpath_gpu.js +0 -430
package/README.md CHANGED
@@ -1,44 +1,362 @@
1
1
  # three-slicer
2
2
 
3
- Browser/WASM 3D-printing slicer, reverse-engineered from [OrcaSlicer](https://github.com/SoftFever/OrcaSlicer).
4
- Slices STL to G-code entirely in the browser (or Node) — no server.
3
+ Browser/WASM 3D-printing slicer package derived from [OrcaSlicer](https://github.com/OrcaSlicer/OrcaSlicer). It can slice binary STL files to G-code in Node or the browser, and it also ships React UI pieces for building a browser slicer: a three.js viewport, GPU toolpath preview, and a schema-driven settings panel.
5
4
 
6
- - **Engine** — WASM kernel: Arachne variable-width walls, gyroid/honeycomb/crosshatch infill,
7
- tree/grid supports, support painting, raft/brim/skirt, ironing, arc fitting, multi-material,
8
- layer streaming (OOM-tolerant), multithreaded kernel auto-selected on cross-origin-isolated sites.
9
- - **Viewer** — React `<Viewport/>`: model import (STL/OBJ/3MF/AMF/PLY), transform gizmos,
10
- multi-plate, GPU toolpath preview (libvgcode port). Shadow-DOM isolated — no CSS collisions.
11
- - **Settings UI** — React `<SettingsPanel/>`: 907 options driven by the extracted OrcaSlicer
12
- config schema, with search, mode filters, and custom widget registry.
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.
13
6
 
14
- ## Install
7
+ ## Links
8
+
9
+ - Package: [npmjs.com/package/three-slicer](https://www.npmjs.com/package/three-slicer)
10
+ - Source: [kimgh06/Web_Three_Slicer](https://github.com/kimgh06/Web_Three_Slicer)
11
+ - Demo: [slicer.kimgh06.com](https://slicer.kimgh06.com/)
12
+
13
+ ## Features
14
+
15
+ - WASM slicing engine with Arachne walls, infill patterns, supports, raft/brim/skirt, ironing, arc fitting, multi-material paths, and layer streaming.
16
+ - Headless SDK for Node or browser use with no `three.js` dependency.
17
+ - Browser worker entry for off-main-thread slicing.
18
+ - React `<Viewport/>` for model import, plate layout, transform controls, slicing, G-code export, and GPU toolpath preview.
19
+ - React `<SettingsPanel/>` generated from extracted OrcaSlicer metadata.
20
+ - Extracted data files for custom UIs: config schema, UI tree, toggle rules, and invalidation map.
21
+ - Automatic multithreaded WASM selection on cross-origin-isolated browser pages.
22
+
23
+ ## Installation
15
24
 
16
25
  ```bash
17
- npm i three-slicer # engine only (Node-safe)
18
- npm i three-slicer react react-dom three # + viewer/components
26
+ npm i three-slicer
19
27
  ```
20
28
 
21
- ## Use
29
+ `react`, `react-dom`, and `three` are peer dependencies and npm installs them for you. They stay peers rather than dependencies because React and three must be single instances — a duplicate copy breaks hooks and `instanceof`.
30
+
31
+ Only the viewer and components import them. If you use the headless engine, they are installed into `node_modules` but never enter your bundle:
32
+
33
+ | Import path | Needs react/three at runtime |
34
+ | --- | --- |
35
+ | `three-slicer`, `/settings`, `/toggle`, `/worker`, `/wasm`, `/data` | no |
36
+ | `three-slicer/viewer`, `/viewer/toolpath`, `/viewer/loaders` | yes |
37
+ | `three-slicer/components` | react only |
38
+
39
+ ## Quick Start: Headless Slicing
40
+
41
+ Use the root import when you only need STL-to-G-code slicing.
22
42
 
23
43
  ```js
24
- // Headless slicing (Node or browser main thread)
25
44
  import { createSlicer } from 'three-slicer'
26
- const s = await createSlicer()
27
- const { gcode, stats } = s.slice(stlArrayBuffer, params)
28
45
 
29
- // React viewer + settings panel
46
+ const slicer = await createSlicer()
47
+
48
+ const result = slicer.slice(stlArrayBuffer, {
49
+ layer_height: 0.2,
50
+ first_layer_height: 0.2,
51
+ line_width: 0.42,
52
+ wall_loops: 2,
53
+ infill_density: 0.15,
54
+ nozzle_diameter: 0.4,
55
+ filament_diameter: 1.75,
56
+ })
57
+
58
+ console.log(result.stats.layers)
59
+ console.log(result.gcode)
60
+
61
+ slicer.dispose()
62
+ ```
63
+
64
+ `slice()` accepts a binary STL as an `ArrayBuffer` or `Uint8Array`. Parameters can be either a kernel params object or a JSON string.
65
+
66
+ ## Streaming Layers
67
+
68
+ For large models, pass callbacks to receive each sliced layer as it is produced. This avoids keeping the full G-code and layer payload in memory at once.
69
+
70
+ ```js
71
+ const chunks = []
72
+
73
+ const result = slicer.slice(stlArrayBuffer, params, {
74
+ onProgress(done, total) {
75
+ console.log(`${done}/${total}`)
76
+ },
77
+ onLayer(layer) {
78
+ chunks.push(layer.gcode)
79
+ },
80
+ })
81
+
82
+ const gcode = chunks.join('')
83
+ console.log(result.stats)
84
+ ```
85
+
86
+ When `onLayer` is set, the returned result carries stats; assemble G-code from the layer callback if you need the full file.
87
+
88
+ ## Quick Start: React Viewer
89
+
90
+ Use `three-slicer/viewer` when you want a ready-made browser slicer viewport.
91
+
92
+ ```jsx
93
+ import { useState } from 'react'
94
+ import Viewport from 'three-slicer/viewer'
95
+
96
+ export default function App() {
97
+ const [settings, setSettings] = useState({})
98
+
99
+ return (
100
+ <Viewport
101
+ settings={settings}
102
+ setSettings={setSettings}
103
+ />
104
+ )
105
+ }
106
+ ```
107
+
108
+ The viewer handles model loading, drag and drop, transform controls, multi-plate layout, worker slicing, GPU toolpath preview, and G-code export. 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()`. Viewer and component styles are bundled into their Shadow DOM roots, so host app CSS does not need to import package CSS.
109
+
110
+ ## Quick Start: Settings Panel
111
+
112
+ Use `three-slicer/components` when you want the OrcaSlicer-style settings UI without building the form yourself.
113
+
114
+ ```jsx
115
+ import { useState } from 'react'
116
+ import SettingsPanel from 'three-slicer/components'
117
+
118
+ export default function App() {
119
+ const [settings, setSettings] = useState({})
120
+
121
+ return (
122
+ <SettingsPanel
123
+ settings={settings}
124
+ setSettings={setSettings}
125
+ />
126
+ )
127
+ }
128
+ ```
129
+
130
+ `settings` is a sparse object keyed by OrcaSlicer setting names. Store only edited values; missing keys fall back to schema defaults.
131
+
132
+ ## Full React Example
133
+
134
+ The viewer and settings panel are designed to share the same `settings` state.
135
+
136
+ ```jsx
137
+ import { useState } from 'react'
30
138
  import Viewport from 'three-slicer/viewer'
31
139
  import SettingsPanel from 'three-slicer/components'
32
- // <Viewport settings={settings} setSettings={setSettings} />
33
140
 
34
- // Extracted data
35
- import schema from 'three-slicer/data/config-schema.json'
141
+ export default function App() {
142
+ const [settings, setSettings] = useState({})
143
+
144
+ return (
145
+ <main style={{ display: 'flex', height: '100vh' }}>
146
+ <Viewport
147
+ settings={settings}
148
+ setSettings={setSettings}
149
+ />
150
+ <SettingsPanel
151
+ settings={settings}
152
+ setSettings={setSettings}
153
+ />
154
+ </main>
155
+ )
156
+ }
36
157
  ```
37
158
 
38
- Vite consumers need `worker: { format: 'es' }` and `build: { target: 'es2022' }`.
39
- Serve with COOP/COEP headers to enable the multithreaded kernel (~2.2× faster).
159
+ The same sparse settings map can feed the settings panel, the viewer, and `deriveKernelParams()`.
160
+
161
+ ## Import Paths
162
+
163
+ ```js
164
+ import { createSlicer, engineWorkerURL } from 'three-slicer'
165
+ import { deriveKernelParams } from 'three-slicer/settings'
166
+ import { disabledKeys, makeCfg } from 'three-slicer/toggle'
167
+ import Viewport from 'three-slicer/viewer'
168
+ import SettingsPanel from 'three-slicer/components'
169
+ import { schema, uiTree } from 'three-slicer/data'
170
+ ```
171
+
172
+ Available subpaths:
173
+
174
+ | Import path | Use |
175
+ | --- | --- |
176
+ | `three-slicer` | Headless WASM engine SDK |
177
+ | `three-slicer/settings` | Schema defaults and settings-to-kernel mapping |
178
+ | `three-slicer/toggle` | Enable/disable rule evaluation for settings UIs |
179
+ | `three-slicer/worker` | Browser worker entry |
180
+ | `three-slicer/wasm` | Single-threaded Emscripten WASM glue |
181
+ | `three-slicer/wasm-mt` | Multithreaded Emscripten WASM glue |
182
+ | `three-slicer/viewer` | React `<Viewport/>` |
183
+ | `three-slicer/viewer/toolpath` | GPU toolpath renderer utilities |
184
+ | `three-slicer/viewer/loaders` | Model loaders |
185
+ | `three-slicer/components` | React `<SettingsPanel/>` |
186
+ | `three-slicer/data` | Named exports for extracted metadata |
187
+ | `three-slicer/data/*.json` | Extracted OrcaSlicer metadata |
188
+
189
+ ## TypeScript
190
+
191
+ Type declarations ship with the package — no `@types/*` needed. All 907 setting keys are typed from the config schema, enum values included:
192
+
193
+ ```ts
194
+ import { createSlicer, type SlicerSettings } from 'three-slicer'
195
+ import { deriveKernelParams } from 'three-slicer/settings'
196
+
197
+ const settings: SlicerSettings = {
198
+ layer_height: 0.2,
199
+ sparse_infill_pattern: 'gyroid', // autocompletes; 'nope' is a type error
200
+ }
201
+
202
+ const slicer = await createSlicer()
203
+ slicer.slice(stlArrayBuffer, deriveKernelParams(settings))
204
+ ```
205
+
206
+ Requires `"moduleResolution": "bundler"`, `"node16"`, or `"nodenext"`. The declarations are wired through the `exports` field, which the legacy `"node"` resolution ignores.
207
+
208
+ ## Settings Model
209
+
210
+ There are two related settings shapes:
211
+
212
+ | Shape | Used by | Description |
213
+ | --- | --- | --- |
214
+ | Sparse OrcaSlicer settings map | `<SettingsPanel/>`, `<Viewport/>` | Object keyed by original OrcaSlicer schema keys. Missing keys use schema defaults. |
215
+ | Kernel params | `slicer.slice()` | Flat object consumed directly by the WASM kernel. |
216
+
217
+ To convert UI settings to kernel params:
218
+
219
+ ```js
220
+ import { deriveKernelParams } from 'three-slicer/settings'
221
+
222
+ const settings = {
223
+ layer_height: 0.25,
224
+ sparse_infill_density: 15,
225
+ wall_loops: 3,
226
+ }
227
+
228
+ const params = deriveKernelParams(settings)
229
+ const result = slicer.slice(stlArrayBuffer, params)
230
+ ```
231
+
232
+ `deriveKernelParams()` maps the curated set of schema keys currently supported by the kernel. Other schema keys can still be displayed by the UI, but they may not affect slicing output yet. Vector options are simplified to their first element.
233
+
234
+ ## Worker Usage
235
+
236
+ Use a module worker to run slicing off the browser main thread.
237
+
238
+ ```js
239
+ import { engineWorkerURL } from 'three-slicer'
240
+
241
+ const worker = new Worker(engineWorkerURL(), { type: 'module' })
242
+
243
+ worker.onmessage = (event) => {
244
+ const message = event.data
245
+
246
+ if (message.type === 'progress') {
247
+ console.log(message.done, message.total)
248
+ }
249
+
250
+ if (message.type === 'layer') {
251
+ console.log(message.idx, message.z, message.gcode)
252
+ }
253
+
254
+ if (message.type === 'done') {
255
+ console.log(message.stats)
256
+ }
257
+
258
+ if (message.type === 'error') {
259
+ console.error(message.error)
260
+ }
261
+ }
262
+ ```
263
+
264
+ The worker protocol emits `progress`, `layer`, `done`, and `error` messages. For bundler-specific setups, `three-slicer/worker` exposes the worker entry directly.
265
+
266
+ ## Bundler Notes
267
+
268
+ Vite consumers should enable ES module workers and an ES2022 build target:
269
+
270
+ ```js
271
+ import { defineConfig } from 'vite'
272
+
273
+ export default defineConfig({
274
+ worker: { format: 'es' },
275
+ build: { target: 'es2022' },
276
+ })
277
+ ```
278
+
279
+ For Next.js or webpack apps, render the viewer on the client side and disable Node-only module aliases used by Emscripten guards.
280
+
281
+ ```js
282
+ module.exports = {
283
+ webpack: (config) => {
284
+ for (const moduleName of [
285
+ 'node:module',
286
+ 'node:fs',
287
+ 'node:path',
288
+ 'node:url',
289
+ 'node:crypto',
290
+ 'node:worker_threads',
291
+ ]) {
292
+ config.resolve.alias[moduleName] = false
293
+ }
294
+ return config
295
+ },
296
+ }
297
+ ```
298
+
299
+ ## Multithreaded WASM
300
+
301
+ The engine ships single-threaded and multithreaded WASM builds. The browser worker automatically uses the multithreaded kernel when the page is cross-origin isolated.
302
+
303
+ Serve these headers to enable it:
304
+
305
+ ```txt
306
+ Cross-Origin-Opener-Policy: same-origin
307
+ Cross-Origin-Embedder-Policy: require-corp
308
+ ```
309
+
310
+ Without those headers, the engine falls back to the single-threaded kernel.
311
+
312
+ ## Data Files
313
+
314
+ The package includes extracted OrcaSlicer metadata for custom interfaces:
315
+
316
+ | File | Use |
317
+ | --- | --- |
318
+ | `three-slicer/data/config-schema.json` | Setting definitions, defaults, labels, units, and option metadata |
319
+ | `three-slicer/data/ui-tree.json` | Tab, page, group, and option layout |
320
+ | `three-slicer/data/toggle-rules.json` | Original enable/disable rule metadata |
321
+ | `three-slicer/data/invalidation-map.json` | Setting invalidation/dependency metadata |
322
+
323
+ ## API Reference
324
+
325
+ | API | Description |
326
+ | --- | --- |
327
+ | `createSlicer()` | Loads the WASM kernel and returns a slicer handle |
328
+ | `slicer.slice(stl, params, callbacks?)` | Slices binary STL input to G-code or streamed layers |
329
+ | `slicer.paintPrepare(stl)` | Prepares support painting against a model |
330
+ | `slicer.paint(args)` | Paints support enforcer/blocker data |
331
+ | `slicer.paintClear()` | Clears support painting data |
332
+ | `slicer.overlay(enforcer)` | Returns support painting overlay data |
333
+ | `slicer.heapSize()` | Returns current WASM heap size |
334
+ | `slicer.dispose()` | Releases the slicer handle for garbage collection |
335
+ | `engineWorkerURL()` | Returns a browser worker URL |
336
+ | `deriveKernelParams(settings)` | Converts sparse OrcaSlicer settings to kernel params |
337
+ | `<Viewport/>` | React slicer viewport |
338
+ | `<SettingsPanel/>` | React settings form |
339
+
340
+ ## Runtime Support
341
+
342
+ | Environment | Supported use |
343
+ | --- | --- |
344
+ | Node ESM | Headless slicing |
345
+ | Browser main thread | Headless slicing |
346
+ | Browser worker | Off-main-thread slicing and streaming |
347
+ | React | Viewer and settings panel |
348
+ | three.js | Required by `three-slicer/viewer` |
349
+
350
+ ## Known Limits
351
+
352
+ - `slice()` currently takes binary STL input at the engine API boundary.
353
+ - The viewer can import STL, OBJ, 3MF, AMF, and PLY, then converts them for slicing.
354
+ - `registerLoader(exts, fn)` from `three-slicer/viewer/loaders` adds any other format. Formats needing a heavy dependency are kept out of the package so it stays runtime-dependency-free — see `web/viewer/src/step_loader.js` for a STEP loader built on `occt-import-js` (OCCT WASM).
355
+ - Not every OrcaSlicer schema key is wired into the WASM kernel yet.
356
+ - Some vector settings are simplified to their first element.
357
+ - Multithreaded WASM requires cross-origin isolation.
358
+ - `three` is pinned as a peer dependency because viewer internals depend on the `TransformControls` API shape.
40
359
 
41
360
  ## License
42
361
 
43
- AGPL-3.0-or-later — derived from OrcaSlicer.
44
- Source: https://github.com/kimgh06/Web_Three_Slicer
362
+ 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.
@@ -1,6 +1,6 @@
1
1
  # three-slicer/components
2
2
 
3
- Reusable React components for the browser slicer. Props-driven — no global state, no React context, no router coupling (proven standalone by the tarball consumer gate `web/pack_check.sh`).
3
+ Reusable React components for the browser slicer. Props-driven — no global state, no React context, no router coupling (proven standalone by the tarball consumer gate `packages/pack_check.sh`).
4
4
 
5
5
  ## `<SettingsPanel/>`
6
6
 
@@ -1,7 +1,6 @@
1
1
  import e, { useRef as R, useState as f, useLayoutEffect as F, useEffect as J, useMemo as z } from "react";
2
2
  import { createPortal as O } from "react-dom";
3
- import C from "three-slicer/data/config-schema.json";
4
- import M from "three-slicer/data/ui-tree.json";
3
+ import { uiTree as M, schema as C } from "three-slicer/data";
5
4
  import { settingRaw as P } from "three-slicer/settings";
6
5
  import { disabledKeys as I, makeCfg as B } from "three-slicer/toggle";
7
6
  function D({ css: t, className: r, children: n }) {
@@ -163,7 +162,7 @@ function V({ optKey: t, settings: r, setSettings: n, disabled: s, onOptionOpen:
163
162
  }), c = (o == null ? void 0 : o.label) || (o == null ? void 0 : o.full_label) || t;
164
163
  return /* @__PURE__ */ e.createElement("div", { className: "row" + (m ? " disabled" : ""), title: m ? `비활성 조건: ${i}` : (o == null ? void 0 : o.tooltip) ?? "", "data-testid": `row-${t}` }, /* @__PURE__ */ e.createElement("span", { className: "lbl-cell" }, h && /* @__PURE__ */ e.createElement("span", { className: "dirty-dot", title: "기본값에서 변경됨", "data-testid": `dirty-${t}` }), l ? /* @__PURE__ */ e.createElement("button", { type: "button", className: "lbl lbl-link", onClick: () => l(t), title: "상세" }, c) : /* @__PURE__ */ e.createElement("span", { className: "lbl" }, c)), /* @__PURE__ */ e.createElement("code", { className: "key" }, t), /* @__PURE__ */ e.createElement(X, { mode: o == null ? void 0 : o.mode }), /* @__PURE__ */ e.createElement("span", { className: "widget-cell" }, /* @__PURE__ */ e.createElement(Y, { def: o, optKey: t, settings: r, setSettings: n, disabled: m, customWidgets: d }), h && /* @__PURE__ */ e.createElement("button", { className: "reset-btn", onClick: u, title: "기본값으로 리셋", "data-testid": `reset-${t}` }, "↺")));
165
164
  }
166
- function re({ settings: t, setSettings: r, onOptionOpen: n, embedded: s = !1, customWidgets: l }) {
165
+ function ne({ settings: t, setSettings: r, onOptionOpen: n, embedded: s = !1, customWidgets: l }) {
167
166
  const [d, o] = f(j[0] ?? ""), [i, m] = f(0), [h, u] = f("all"), [c, x] = f(""), g = M[d] ?? [], y = g[Math.min(i, g.length - 1)], v = z(() => I(B(t)), [t]), w = c.trim().toLowerCase(), N = z(() => w ? Object.entries(C).filter(([a, p]) => {
168
167
  var b, k;
169
168
  return a.includes(w) || ((b = p.label) == null ? void 0 : b.toLowerCase().includes(w)) || ((k = p.full_label) == null ? void 0 : k.toLowerCase().includes(w));
@@ -176,5 +175,5 @@ function re({ settings: t, setSettings: r, onOptionOpen: n, embedded: s = !1, cu
176
175
  })) : /* @__PURE__ */ e.createElement("p", { className: "muted" }, "빌더 없음"))));
177
176
  }
178
177
  export {
179
- re as default
178
+ ne as default
180
179
  };
package/engine/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- // Type definitions for @three-slicer/engine
1
+ // Type definitions for three-slicer (engine entry point)
2
+ export type { SlicerSettings, SettingKey, Point } from '../types/settings-keys.d.ts'
3
+
2
4
  export interface SliceLayer { z: number; idx: number; gcode: string; paths: Float32Array; widths: Float32Array }
3
5
  export interface SliceCallbacks {
4
6
  onProgress?: (done: number, total: number) => void
@@ -0,0 +1,12 @@
1
+ // 추출 JSON 4종의 유일한 import 지점.
2
+ //
3
+ // 왜 한 군데로 모으는가: JSON 은 Node 22+ ESM 에서 `with { type: 'json' }` 이 필수인데,
4
+ // Vite/esbuild 는 번들 출력에서 이 attribute 를 떼어낸다(build.target·importAttributesKey 로
5
+ // 막을 수 없음 — 실측). 그래서 같은 JSON 을 "attribute 있는 원본(engine/src/*.js)" 과
6
+ // "attribute 없는 번들(components/dist)" 이 동시에 가리키면 소비자 번들러가
7
+ // "inconsistent import attributes" 로 경고한다. 여기 한 곳만 JSON 을 잡고 나머지는
8
+ // 이 모듈을 external 로 import → 번들에 JSON import 자체가 남지 않아 불일치가 성립하지 않는다.
9
+ export { default as schema } from 'three-slicer/data/config-schema.json' with { type: 'json' }
10
+ export { default as uiTree } from 'three-slicer/data/ui-tree.json' with { type: 'json' }
11
+ export { default as toggleRules } from 'three-slicer/data/toggle-rules.json' with { type: 'json' }
12
+ export { default as invalidationMap } from 'three-slicer/data/invalidation-map.json' with { type: 'json' }
@@ -1,7 +1,7 @@
1
1
  // 우측 설정 패널(편집 가능)의 실제 값 → 커널 슬라이스 파라미터 매핑.
2
2
  // - 설정 상태는 sparse 맵(key→value): 편집한 키만 저장, 없으면 config-schema default.
3
3
  // - 벡터형(coFloats/coInts 등)은 첫 원소만 사용/편집(단순화).
4
- import schema from 'three-slicer/data/config-schema.json'
4
+ import { schema } from './data.js'
5
5
 
6
6
  export function schemaDefault(key) { return schema[key]?.default }
7
7
  export function settingRaw(settings, key) { return (settings && key in settings) ? settings[key] : schemaDefault(key) }
@@ -47,8 +47,9 @@ self.onmessage = async (e) => {
47
47
  try {
48
48
  // Module.HEAPU8 은 emscripten 6.x 글루가 노출하지 않음 — embind typed_memory_view 로 버퍼 획득
49
49
  const v = Module.sup_progress_view && Module.sup_progress_view()
50
+ const c = Module.cancel_flag_view && Module.cancel_flag_view()
50
51
  if (v && v.buffer instanceof SharedArrayBuffer)
51
- self.postMessage({ type: 'supsab', buf: v.buffer, ptr: v.byteOffset })
52
+ self.postMessage({ type: 'supsab', buf: v.buffer, ptr: v.byteOffset, cancelPtr: c ? c.byteOffset : 0 })
52
53
  } catch {}
53
54
  }
54
55
  // 기본: 슬라이스. 레이어 싱크 등록 → 커널이 레이어마다 콜백(z, idx, gcodeChunk, pathsF32, widthsF32).
Binary file
Binary file
@@ -2,8 +2,7 @@
2
2
  // 범위: 뷰어가 다루는 키에 관련된 규칙 중, 아래 하드코딩 로컬로 "완전히" 번역 가능한 것만 적용.
3
3
  // 번역 불가(모르는 로컬/enum 비교 등)는 fail-open(활성 유지) — 잘못된 비활성 방지(정직한 부분 구현).
4
4
  // 전체 907키·231규칙 완역은 범위 외(README 기록). 참조: toggle-rules.json 의 toggle_print_fff_options.locals.
5
- import toggles from 'three-slicer/data/toggle-rules.json'
6
- import schema from 'three-slicer/data/config-schema.json'
5
+ import { toggleRules as toggles, schema } from './data.js'
7
6
 
8
7
  // 설정값 접근기 (settings 맵 우선, 없으면 스키마 default). 퍼센트("15%")는 숫자로.
9
8
  export function makeCfg(settings) {
package/package.json CHANGED
@@ -1,55 +1,83 @@
1
1
  {
2
2
  "name": "three-slicer",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Browser/WASM 3D-printing slicer reverse-engineered from OrcaSlicer: slicing engine (Arachne walls, tree/grid supports, multi-material), React viewer with GPU toolpath preview, and schema-driven settings UI.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "type": "module",
7
7
  "exports": {
8
8
  ".": {
9
9
  "types": "./engine/index.d.ts",
10
- "import": "./engine/index.js"
10
+ "default": "./engine/index.js"
11
11
  },
12
- "./settings": "./engine/src/settings.js",
13
- "./toggle": "./engine/src/toggle_eval.js",
14
- "./worker": "./engine/src/slicer.worker.js",
15
- "./wasm": "./engine/src/slicer_core.js",
16
- "./wasm-mt": "./engine/src/slicer_core.mt.js",
17
- "./viewer": "./viewer/dist/Viewport.js",
18
- "./viewer/toolpath": "./viewer/dist/toolpath_gpu.js",
19
- "./viewer/loaders": "./viewer/dist/model_loaders.js",
20
- "./components": "./components/dist/SettingsPanel.js",
21
- "./data/*": "./data/*"
12
+ "./settings": {
13
+ "types": "./types/settings.d.ts",
14
+ "default": "./engine/src/settings.js"
15
+ },
16
+ "./toggle": {
17
+ "types": "./types/toggle.d.ts",
18
+ "default": "./engine/src/toggle_eval.js"
19
+ },
20
+ "./worker": {
21
+ "types": "./types/worker.d.ts",
22
+ "default": "./engine/src/slicer.worker.js"
23
+ },
24
+ "./wasm": {
25
+ "types": "./types/wasm.d.ts",
26
+ "default": "./engine/src/slicer_core.js"
27
+ },
28
+ "./wasm-mt": {
29
+ "types": "./types/wasm.d.ts",
30
+ "default": "./engine/src/slicer_core.mt.js"
31
+ },
32
+ "./viewer": {
33
+ "types": "./types/viewer.d.ts",
34
+ "default": "./viewer/dist/Viewport.js"
35
+ },
36
+ "./viewer/toolpath": {
37
+ "types": "./types/viewer-toolpath.d.ts",
38
+ "default": "./viewer/dist/toolpath_gpu.js"
39
+ },
40
+ "./viewer/loaders": {
41
+ "types": "./types/viewer-loaders.d.ts",
42
+ "default": "./viewer/dist/model_loaders.js"
43
+ },
44
+ "./components": {
45
+ "types": "./types/components.d.ts",
46
+ "default": "./components/dist/SettingsPanel.js"
47
+ },
48
+ "./data": {
49
+ "types": "./types/data.d.ts",
50
+ "default": "./engine/src/data.js"
51
+ },
52
+ "./data/*": {
53
+ "types": "./types/data/*.d.ts",
54
+ "default": "./data/*"
55
+ }
22
56
  },
23
57
  "scripts": {
24
- "build": "vite build --config components/vite.config.js && vite build --config viewer/vite.config.js && cp viewer/src/make_worker.js viewer/dist/make_worker.js"
58
+ "build": "node types/gen_settings_types.mjs && vite build --config components/vite.config.js && vite build --config viewer/vite.config.js && cp viewer/src/make_worker.js viewer/dist/make_worker.js",
59
+ "check": "bash pack_check.sh"
25
60
  },
26
61
  "peerDependencies": {
27
62
  "react": ">=18",
28
63
  "react-dom": ">=18",
29
64
  "three": "^0.160.0"
30
65
  },
31
- "peerDependenciesMeta": {
32
- "react": {
33
- "optional": true
34
- },
35
- "react-dom": {
36
- "optional": true
37
- },
38
- "three": {
39
- "optional": true
40
- }
41
- },
42
66
  "devDependencies": {
67
+ "typescript": "^5.6.0",
43
68
  "vite": "^5.4.11"
44
69
  },
45
70
  "files": [
46
71
  "engine",
72
+ "types",
47
73
  "components/dist",
48
74
  "viewer/dist",
49
- "viewer/src",
50
75
  "viewer/styles.css",
51
76
  "components/styles.css",
52
- "data/*.json",
77
+ "data/config-schema.json",
78
+ "data/ui-tree.json",
79
+ "data/toggle-rules.json",
80
+ "data/invalidation-map.json",
53
81
  "README.md",
54
82
  "LICENSE.txt"
55
83
  ],
@@ -0,0 +1,19 @@
1
+ // three-slicer/components
2
+ import type * as React from 'react'
3
+ import type { SlicerSettings } from './settings-keys.d.ts'
4
+
5
+ export interface SettingsPanelProps {
6
+ /** sparse 맵 — 편집한 키만. 없는 키는 config-schema default 가 쓰인다. */
7
+ settings: SlicerSettings
8
+ /** React setState 형태. 상태가 컴포넌트 밖으로 나가는 유일한 통로. */
9
+ setSettings: React.Dispatch<React.SetStateAction<SlicerSettings>>
10
+ /** 라벨 클릭 — 딥링크/상세용. 생략하면 평범한 라벨(라우터 결합 0). */
11
+ onOptionOpen?: (optKey: string) => void
12
+ /** 다른 패널 안에 끼워 넣을 때 */
13
+ embedded?: boolean
14
+ /** 스키마 구동 위젯을 키 단위로 교체 (예: `{ printable_area: MyBedEditor }`) */
15
+ customWidgets?: Record<string, React.ComponentType<any>>
16
+ }
17
+
18
+ declare const SettingsPanel: React.FC<SettingsPanelProps>
19
+ export default SettingsPanel
@@ -0,0 +1,55 @@
1
+ // three-slicer/data/config-schema.json — OrcaSlicer 원본에서 추출한 907개 옵션 정의.
2
+ // ponytail: 값을 리터럴로 좁히지 않는다. 907키 × 33필드를 리터럴로 추론시키면 소비자 tsc 가 기어간다.
3
+ // 키 단위 정확도가 필요하면 SlicerSettings(three-slicer/settings) 쪽을 쓸 것.
4
+
5
+ /** 원본 ConfigOptionDef 의 coXxx 타입 태그 */
6
+ export type ConfigOptionType =
7
+ | 'coBool' | 'coBools'
8
+ | 'coInt' | 'coInts'
9
+ | 'coFloat' | 'coFloats'
10
+ | 'coPercent' | 'coPercents'
11
+ | 'coFloatOrPercent' | 'coFloatsOrPercents'
12
+ | 'coString' | 'coStrings'
13
+ | 'coEnum' | 'coEnums'
14
+ | 'coPoint' | 'coPoints' | 'coPointsGroups'
15
+
16
+ /** 907키 중 `type` 과 `defined_in` 만 전부 존재한다. 나머지는 전부 optional. */
17
+ export interface ConfigOption {
18
+ type: ConfigOptionType
19
+ /** 추출된 원본 함수명 (예: 'init_common_params') */
20
+ defined_in: string
21
+ line?: number
22
+ mode?: string
23
+ label?: string
24
+ full_label?: string
25
+ tooltip?: string
26
+ sidetext?: string
27
+ category?: string
28
+ default?: unknown
29
+ default_type?: string
30
+ default_raw?: string
31
+ enum_type?: string
32
+ enum_values?: string[]
33
+ enum_labels?: string[]
34
+ enum_values_copied_from?: string
35
+ enum_labels_copied_from?: string
36
+ min?: number
37
+ max?: number
38
+ max_literal?: unknown
39
+ gui_type?: string
40
+ gui_flags?: string
41
+ ratio_over?: string
42
+ nullable?: boolean
43
+ readonly?: boolean
44
+ multiline?: boolean
45
+ full_width?: boolean
46
+ height?: number
47
+ cli?: string
48
+ cli_params?: string
49
+ aliases?: string[]
50
+ plugin_type?: string
51
+ generated_by_loop?: unknown
52
+ }
53
+
54
+ declare const schema: Record<string, ConfigOption>
55
+ export default schema