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.
Files changed (43) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +310 -22
  3. package/THIRD-PARTY-NOTICES.md +37 -0
  4. package/components/README.md +2 -0
  5. package/components/dist/SettingsPanel.js +92 -92
  6. package/data/config-schema.json +698 -0
  7. package/data/filaments.js +1 -1
  8. package/data/preset-keys.json +1 -0
  9. package/data/printers.json +1 -1
  10. package/data/processes.js +1 -1
  11. package/data/ui-tree.json +342 -0
  12. package/engine/README.md +279 -3
  13. package/engine/examples/sla_headless.mjs +51 -0
  14. package/engine/index.d.ts +77 -5
  15. package/engine/index.js +15 -4
  16. package/engine/src/client.js +165 -0
  17. package/engine/src/data.js +3 -0
  18. package/engine/src/preset_file.js +99 -0
  19. package/engine/src/settings.js +232 -0
  20. package/engine/src/sla_core.js +188 -0
  21. package/engine/src/sla_request.js +185 -0
  22. package/engine/src/slicer.worker.js +76 -4
  23. package/engine/src/slicer_core.js +0 -0
  24. package/engine/src/slicer_core.mt.js +0 -0
  25. package/package.json +26 -11
  26. package/types/client.d.ts +88 -0
  27. package/types/components.d.ts +10 -0
  28. package/types/data/preset-keys.json.d.ts +20 -0
  29. package/types/data/printers.json.d.ts +2 -2
  30. package/types/data.d.ts +4 -0
  31. package/types/settings-keys.d.ts +107 -1
  32. package/types/settings.d.ts +116 -1
  33. package/types/sla.d.ts +167 -0
  34. package/types/viewer.d.ts +59 -1
  35. package/types/worker.d.ts +95 -0
  36. package/viewer/README.md +163 -3
  37. package/viewer/dist/Viewport.js +3633 -3137
  38. package/viewer/dist/model_loaders.js +1 -1
  39. package/viewer/dist/parse_3mf-C2X_W442.js +300 -0
  40. package/viewer/dist/parse_3mf.worker.js +1 -1
  41. package/viewer/styles.css +5 -0
  42. package/types/gen_settings_types.mjs +0 -70
  43. package/viewer/dist/parse_3mf-8oCnCJNK.js +0 -216
@@ -1,6 +1,7 @@
1
1
  // three-slicer/settings
2
2
  import type { SlicerSettings, SettingKey, Point } from './settings-keys.d.ts'
3
- export type { SlicerSettings, SettingKey, Point }
3
+ import type { PrinterEntry } from './data/printers.json.d.ts'
4
+ export type { SlicerSettings, SettingKey, Point, PrinterEntry }
4
5
 
5
6
  /** The config-schema default value (undefined for unknown keys) */
6
7
  export function schemaDefault(key: string): unknown
@@ -18,6 +19,27 @@ export function settingScalar(settings: SlicerSettings | null | undefined, key:
18
19
  */
19
20
  export function deriveKernelParams(settings: SlicerSettings | null | undefined, opts?: { plate?: number }): Record<string, unknown>
20
21
 
22
+ /** Which slicing technology the settings map's printer profile declares. Defaults to FFF. */
23
+ export function printerTechnology(settings: SlicerSettings | null | undefined): 'FFF' | 'SLA'
24
+
25
+ /**
26
+ * Settings map -> SLA (resin) slice params for the pure-JS contour slicer + the display geometry the SL1 raster
27
+ * export needs. Separate from deriveKernelParams — that one feeds the WASM kernel and its key set is pinned.
28
+ */
29
+ export function deriveSlaParams(settings: SlicerSettings | null | undefined): {
30
+ layer_height: number
31
+ initial_layer_height: number
32
+ exposure_time: number
33
+ initial_exposure_time: number
34
+ faded_layers: number
35
+ display_width: number
36
+ display_height: number
37
+ display_pixels_x: number
38
+ display_pixels_y: number
39
+ supports_enable: boolean
40
+ pad_enable: boolean
41
+ }
42
+
21
43
  /**
22
44
  * A 3mf project's raw `Metadata/project_settings.config` -> a settings map this API accepts.
23
45
  * Upstream writes every option as a string ("0"/"1" for a bool, "0.2" for a float, one entry per extruder for a
@@ -37,6 +59,99 @@ export function normalizeProjectSettings(raw: Record<string, unknown> | null | u
37
59
  */
38
60
  export function serializeProjectSettings(settings: SlicerSettings | null | undefined): Record<string, string | string[]>
39
61
 
62
+ // ---- Preset files -----------------------------------------------------------
63
+ // The `.json` OrcaSlicer's "Config files" dialog imports and its "Export preset" writes. One file, one preset,
64
+ // one type. The value encoding is the same all-strings shape `project_settings.config` uses — same writer
65
+ // upstream (ConfigBase::save_to_json) — so these reuse the coercion above rather than repeating it.
66
+
67
+ /** Upstream's own `type` field: machine = printer, process = print settings, filament = material. */
68
+ export type PresetType = 'machine' | 'process' | 'filament'
69
+
70
+ /** The option keys that belong in a preset of this type, from upstream's `Preset::printer_options()` and friends. */
71
+ export function presetOptionKeys(type: PresetType): string[]
72
+
73
+ export interface WritePresetOptions {
74
+ /** Defaults to `'machine'`. */
75
+ type?: PresetType
76
+ /** Goes in the file's `name` field, and is what an importer shows. Defaults to `'Custom'`. */
77
+ name?: string
78
+ /**
79
+ * `true` (the default) writes every option of that type, filling unset ones from the config-schema default, so
80
+ * the file stands on its own. `false` writes only what the settings map holds — a diff-shaped file, readable
81
+ * only next to whatever it was derived from.
82
+ */
83
+ complete?: boolean
84
+ version?: string
85
+ }
86
+
87
+ /**
88
+ * A settings map -> the object a preset `.json` holds. Written **without `inherits`**: upstream saves a derived
89
+ * preset as the diff against its parent, which only means something beside the vendor database it came from.
90
+ */
91
+ export function writePresetFile(settings: SlicerSettings | null | undefined, options?: WritePresetOptions): Record<string, unknown>
92
+
93
+ /** The same, already stringified — what an export actually writes to disk. */
94
+ export function presetFileText(settings: SlicerSettings | null | undefined, options?: WritePresetOptions): string
95
+
96
+ export interface ReadPresetResult {
97
+ /** The parent's values with the file's own on top, since the file is the diff. */
98
+ settings: SlicerSettings
99
+ type: PresetType
100
+ name: string
101
+ /** The parent named by the file, or `null`. */
102
+ inherits: string | null
103
+ /**
104
+ * Set to the parent's name when it was named but could not be resolved. The file's own values are still
105
+ * applied — a vendor preset without its parent still carries most of itself, and the caller decides whether
106
+ * that is good enough. Watch for it: the Bambu X1C machine file never states its own bed, so read alone it
107
+ * yields a printer with no `printable_area` at all.
108
+ */
109
+ missingParent: string | null
110
+ applied: number
111
+ skipped: string[]
112
+ }
113
+
114
+ /**
115
+ * A parsed preset `.json` -> a settings map. Pass `resolveParent` to follow `inherits`; `printerSettings` covers
116
+ * the machine case for the keys this package carries.
117
+ */
118
+ export function readPresetFile(raw: Record<string, unknown> | null | undefined,
119
+ options?: { resolveParent?: (name: string, type: PresetType) => SlicerSettings | null }): ReadPresetResult
120
+
121
+ // ---- Printer profiles -------------------------------------------------------
122
+ // printers.json is column-oriented; these hide that layout so no consumer decodes it by hand.
123
+
124
+ /**
125
+ * Every option key a printer profile can set. Delete these from the settings map before applying a different
126
+ * printer — a profile only carries the keys it sets, so without the clear the previous machine's values survive.
127
+ */
128
+ export const printerKeys: string[]
129
+
130
+ /** Vendor -> profile name -> entry, straight from the data. For building a picker. */
131
+ export const printersByVendor: Record<string, Record<string, PrinterEntry>>
132
+
133
+ /** Vendor -> slicing technology. Absent means FFF; only the resin vendor bundles are marked. */
134
+ export const printerTechByVendor: Record<string, 'SLA' | 'FFF'>
135
+
136
+ /** The resin material catalog (SLA vendor bundles, inherits flattened). `layerHeight` is the preset's
137
+ * compatibility condition reduced to a number. */
138
+ export const resinCatalog: Array<{
139
+ name: string; bundle: string; type: string; vendor: string; colour: string
140
+ exposure_time?: number; initial_exposure_time?: number; initial_layer_height?: number; layerHeight?: number
141
+ }>
142
+
143
+ /** The settings a resin material applies (exposure family + the remembered pick). `null` when unknown. */
144
+ export function resinSettingsFor(name: string): SlicerSettings | null
145
+
146
+ /** The settings a printer profile applies, ready to merge. `null` when the name is unknown. */
147
+ export function printerSettings(profileName: string): SlicerSettings | null
148
+
149
+ /** The vendor's recommended process preset for that printer, or `''` when the profile names none. */
150
+ export function printerDefaultPreset(profileName: string): string
151
+
152
+ /** The schema keys the kernel's machine limits are read from — for UI that shows which ones are in play. */
153
+ export const machineLimitKeys: string[]
154
+
40
155
  // ---- Lazily loaded presets --------------------------------------------------
41
156
  // Both facades hide the column layout of the artifact they wrap; the promise is created once and reused.
42
157
 
package/types/sla.d.ts ADDED
@@ -0,0 +1,167 @@
1
+ import type { SlicerSettings } from './settings-keys.d.ts'
2
+
3
+ export type SlaSupportStrategy = 'default' | 'branching' | 'organic'
4
+ export type SlaCapability = 'defaultSupport' | 'branchingSupport' | 'organicSupport' | 'manualSupportPoints' | 'modifierVolumes' | 'pad' | 'correction' | 'hollowing' | 'drainHoles'
5
+ export type SlaCapabilityStatus = 'wasm-required' | 'unsupported' | 'single-object-contours-only'
6
+ export type SlaMatrix4 = readonly [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]
7
+
8
+ export interface SlaSupportPoint {
9
+ readonly type: 'manual' | 'automatic' | 'island' | 'slope'
10
+ readonly position: readonly [number, number, number]
11
+ readonly radius?: number
12
+ readonly elevation?: number
13
+ readonly permanent?: boolean
14
+ readonly manual?: boolean
15
+ }
16
+
17
+ export interface SlaDrainHole {
18
+ readonly position: readonly [number, number, number]
19
+ readonly normal: readonly [number, number, number]
20
+ readonly radius: number
21
+ readonly height: number
22
+ }
23
+
24
+ export interface SlaModifierVolume {
25
+ readonly id: string
26
+ readonly kind: 'blocker' | 'enforcer'
27
+ readonly stl: ArrayBuffer | Uint8Array
28
+ readonly transform?: SlaMatrix4
29
+ readonly settings?: SlicerSettings
30
+ }
31
+
32
+ export interface SlaObjectInstance {
33
+ readonly id: string
34
+ readonly transform?: SlaMatrix4
35
+ readonly settings?: SlicerSettings
36
+ }
37
+
38
+ export interface SlaObject {
39
+ readonly id: string
40
+ readonly stl: ArrayBuffer | Uint8Array
41
+ readonly transform?: SlaMatrix4
42
+ readonly settings?: SlicerSettings
43
+ readonly instances?: readonly SlaObjectInstance[]
44
+ readonly supportPoints?: readonly SlaSupportPoint[]
45
+ readonly modifierVolumes?: readonly SlaModifierVolume[]
46
+ readonly drainHoles?: readonly SlaDrainHole[]
47
+ }
48
+
49
+ export interface SupportConfig {
50
+ readonly enabled?: boolean
51
+ readonly strategy?: SlaSupportStrategy
52
+ readonly enforcersOnly?: boolean
53
+ readonly headFrontDiameter?: number
54
+ readonly headPenetration?: number
55
+ readonly headWidth?: number
56
+ readonly pillarDiameter?: number
57
+ readonly smallPillarDiameterPercent?: number
58
+ readonly maxBridgesOnPillar?: number
59
+ readonly maxWeightOnModel?: number
60
+ readonly pillarConnectionMode?: 'zigzag' | 'cross' | 'dynamic'
61
+ readonly buildplateOnly?: boolean
62
+ readonly pillarWideningFactor?: number
63
+ readonly baseDiameter?: number
64
+ readonly baseHeight?: number
65
+ readonly baseSafetyDistance?: number
66
+ readonly criticalAngle?: number
67
+ readonly maxBridgeLength?: number
68
+ readonly maxPillarLinkDistance?: number
69
+ readonly objectElevation?: number
70
+ readonly branchingsupport_head_front_diameter?: number
71
+ readonly branchingsupport_head_penetration?: number
72
+ readonly branchingsupport_head_width?: number
73
+ readonly branchingsupport_pillar_diameter?: number
74
+ readonly branchingsupport_small_pillar_diameter_percent?: number
75
+ readonly branchingsupport_max_bridges_on_pillar?: number
76
+ readonly branchingsupport_max_weight_on_model?: number
77
+ readonly branchingsupport_pillar_connection_mode?: 'zigzag' | 'cross' | 'dynamic'
78
+ readonly branchingsupport_buildplate_only?: boolean
79
+ readonly branchingsupport_pillar_widening_factor?: number
80
+ readonly branchingsupport_base_diameter?: number
81
+ readonly branchingsupport_base_height?: number
82
+ readonly branchingsupport_base_safety_distance?: number
83
+ readonly branchingsupport_critical_angle?: number
84
+ readonly branchingsupport_max_bridge_length?: number
85
+ readonly branchingsupport_max_pillar_link_distance?: number
86
+ readonly branchingsupport_object_elevation?: number
87
+ }
88
+
89
+ export interface PadConfig {
90
+ readonly enabled?: boolean
91
+ readonly wallThickness?: number
92
+ readonly wallHeight?: number
93
+ readonly brimSize?: number
94
+ readonly maxMergeDistance?: number
95
+ readonly wallSlope?: number
96
+ readonly aroundObject?: boolean
97
+ readonly aroundObjectEverywhere?: boolean
98
+ readonly objectGap?: number
99
+ readonly objectConnectorStride?: number
100
+ readonly objectConnectorWidth?: number
101
+ readonly objectConnectorPenetration?: number
102
+ }
103
+
104
+ export interface SlaCorrectionConfig {
105
+ readonly relative?: readonly [number, number]
106
+ readonly relativeX?: number
107
+ readonly relativeY?: number
108
+ readonly relativeZ?: number
109
+ readonly absolute?: number
110
+ readonly elephantFootMinWidth?: number
111
+ readonly zCorrectionLayers?: number
112
+ readonly closingRadius?: number
113
+ }
114
+
115
+ export interface SlaDisplayConfig {
116
+ readonly width?: number
117
+ readonly height?: number
118
+ readonly pixelsX?: number
119
+ readonly pixelsY?: number
120
+ readonly mirrorX?: boolean
121
+ readonly mirrorY?: boolean
122
+ readonly orientation?: 'landscape' | 'portrait'
123
+ readonly gamma?: number
124
+ readonly archiveFormat?: 'SL1'
125
+ }
126
+
127
+ export interface SlaHollowingConfig {
128
+ readonly enabled?: boolean
129
+ readonly minThickness?: number
130
+ readonly quality?: number
131
+ readonly closingDistance?: number
132
+ }
133
+
134
+ export interface SlaJob {
135
+ readonly version?: 1
136
+ readonly objects: readonly SlaObject[]
137
+ readonly settings?: SlicerSettings
138
+ readonly support?: SupportConfig
139
+ readonly pad?: PadConfig
140
+ readonly correction?: SlaCorrectionConfig
141
+ readonly display?: SlaDisplayConfig
142
+ readonly hollowing?: SlaHollowingConfig
143
+ readonly drainHoles?: readonly unknown[]
144
+ readonly requiredCapabilities?: readonly SlaCapability[]
145
+ }
146
+
147
+ export interface SlaCapabilities {
148
+ readonly defaultSupport: SlaCapabilityStatus
149
+ readonly branchingSupport: SlaCapabilityStatus
150
+ readonly organicSupport: SlaCapabilityStatus
151
+ readonly manualSupportPoints: SlaCapabilityStatus
152
+ readonly modifierVolumes: SlaCapabilityStatus
153
+ readonly pad: SlaCapabilityStatus
154
+ readonly correction: SlaCapabilityStatus
155
+ readonly hollowing: SlaCapabilityStatus
156
+ readonly drainHoles: SlaCapabilityStatus
157
+ readonly jsFallback: SlaCapabilityStatus
158
+ }
159
+
160
+ export type SlaErrorCode = 'SLA_INVALID_REQUEST' | 'SLA_UNSUPPORTED_ORGANIC' | 'SLA_UNSUPPORTED_HOLLOWING' | 'SLA_FALLBACK_MULTI_OBJECT' | 'SLA_FALLBACK_SUPPORTS' | 'SLA_FALLBACK_PAD' | 'SLA_FALLBACK_OBJECT_CONTEXT'
161
+
162
+ export class SlaRequestError extends Error {
163
+ readonly code: SlaErrorCode
164
+ }
165
+
166
+ export const SLA_JOB_VERSION: 1
167
+ export const SLA_CAPABILITIES: SlaCapabilities
package/types/viewer.d.ts CHANGED
@@ -21,8 +21,32 @@ export interface ViewportProps {
21
21
  /**
22
22
  * Per-panel visibility. Every panel is visible unless its key is explicitly `false`, so a host only opts out —
23
23
  * and a panel added in a later version does not disappear for hosts that listed the ones they wanted.
24
+ *
25
+ * A {@link LockablePanel} also accepts `'readonly'`: the panel is drawn but nothing inside it can be clicked,
26
+ * typed into or tabbed to — including any node the host passed into it. That is the shape a host wants when it
27
+ * presets the printer, process and filament itself and does not want the user changing them.
28
+ *
29
+ * Note what it locks: the UI path, not the value. `settings` is still the host's own prop, and other paths
30
+ * inside the viewer still write it — importing a 3mf project applies that project's settings either way.
24
31
  */
25
- panels?: Partial<Record<ViewportPanel, boolean>>
32
+ panels?: Partial<Record<ViewportPanel, boolean>> & Partial<Record<LockablePanel, boolean | 'readonly'>>
33
+ /**
34
+ * Behaviour switches, following the same opt-out rule as {@link ViewportProps.panels}: everything is on unless
35
+ * its key is explicitly `false`. These are the things the component does *outside* its own box — take the page's
36
+ * keyboard, load the WASM kernel, write to the console — which a host embedding it in a larger app may already
37
+ * be doing itself. See {@link ViewportFeature}.
38
+ */
39
+ features?: Partial<Record<ViewportFeature, boolean>>
40
+ /**
41
+ * Intercepts every file the viewer would otherwise hand to the browser as a download — the 3mf project, the STL,
42
+ * and each plate's G-code. Return anything truthy to say it is handled and suppress the download; return nothing
43
+ * to let it proceed as well. This is the only way in: the save buttons live inside the component.
44
+ *
45
+ * ```jsx
46
+ * <Viewport onExport={(blob, filename) => { upload(blob, filename); return true }} />
47
+ * ```
48
+ */
49
+ onExport?: (file: Blob, filename: string) => boolean | void
26
50
  /**
27
51
  * G-code text to render instead of a slice result. Parsed into the same layer stream the kernel produces and
28
52
  * shown on the selected plate; the kernel is never started. While it is set, auto re-slice leaves that plate alone.
@@ -41,10 +65,44 @@ export interface ViewportProps {
41
65
  onSliced?: (result: { plate: number; stats: Record<string, unknown>; gcode: string }) => void
42
66
  }
43
67
 
68
+ /**
69
+ * Behaviour keys accepted by {@link ViewportProps.features}. All default to enabled.
70
+ *
71
+ * - `shortcuts` — the keyboard bindings. They are installed on `window`, so while the viewer is mounted they fire
72
+ * wherever focus is (except inside inputs) and `Ctrl+C` in particular preventDefaults. Turn them off when the
73
+ * host page has its own.
74
+ * - `warmup` — loading the WASM kernel on mount, ahead of the first slice. Off, nothing is downloaded or compiled
75
+ * until something actually slices — which for a `gcode`-only viewer is never.
76
+ * - `drop` — drag and drop onto the canvas.
77
+ * - `filePicker` — the file dialog, from every button that opens it.
78
+ * - `contextMenu` — the right-click menu. Note that the browser's own menu stays suppressed over the canvas either
79
+ * way: OrbitControls preventDefaults `contextmenu` itself.
80
+ * - `logs` — console diagnostics, from the component and from the slice worker.
81
+ */
82
+ export type ViewportFeature = 'shortcuts' | 'warmup' | 'drop' | 'filePicker' | 'contextMenu' | 'logs'
83
+
84
+ /**
85
+ * The panels that accept `'readonly'` as well as `true`/`false` — the right column and the cards in it. Everything
86
+ * else takes a boolean only: locking the gizmo rail or the plate tabs is what `features` and `panels: false` are
87
+ * for, and pretending otherwise would mean a `'readonly'` that silently does nothing on half the keys.
88
+ *
89
+ * `sidebar: 'readonly'` locks the whole column in one go, so the per-card keys are for mixing — a locked printer
90
+ * card above a live object list, say.
91
+ */
92
+ export type LockablePanel =
93
+ | 'sidebar' | 'printerCard' | 'filamentCard' | 'objectList' | 'towerCard'
94
+ | 'previewControls' | 'processCard' | 'sliceBar'
95
+
44
96
  /** Panel keys accepted by {@link ViewportProps.panels}. `sidebar: false` hides the whole right column at once. */
45
97
  export type ViewportPanel =
46
98
  | 'topBar' | 'gizmoRail' | 'objectToolbar' | 'paintPanel' | 'statsCard' | 'plateBar' | 'emptyHint' | 'status'
47
99
  | 'sidebar' | 'printerCard' | 'filamentCard' | 'objectList' | 'previewControls' | 'processCard' | 'sliceBar'
100
+ /** The over-the-bed warning, shown in Prepare when something leaves the printable area. */
101
+ | 'bedWarn'
102
+ /** The prime tower card. Only rendered anyway once a second filament exists. */
103
+ | 'towerCard'
104
+ /** The resin (SLA) card. Takes the filament card's place when the printer profile declares SLA. */
105
+ | 'resinCard'
48
106
 
49
107
  /** Value changes reported through {@link ViewportProps.onEvent}. Not fired for the initial values. */
50
108
  export type ViewportEvent =
package/types/worker.d.ts CHANGED
@@ -1,3 +1,98 @@
1
1
  // three-slicer/worker — the slice worker script. Not a module you import, but the target of
2
2
  // `new Worker(new URL('three-slicer/worker', import.meta.url), { type: 'module' })`.
3
+ //
4
+ // The protocol below is the raw message contract. `createSlicerClient()` from `three-slicer/client` wraps it in
5
+ // promises and is the easier way in; these types are here for hosts driving the worker directly, and because the
6
+ // shape has traps that only a written-down contract makes visible — see the slice request and `erase`.
7
+ import type { SliceResult } from '../engine/index.d.ts'
8
+ import type { SlaErrorCode, SlaJob } from './sla.d.ts'
9
+
10
+ /** Brush geometry shared by paint and erase: the hit facet, the hit point, the camera, the radius. */
11
+ export interface BrushArgs {
12
+ facet: number
13
+ hx: number; hy: number; hz: number
14
+ cx: number; cy: number; cz: number
15
+ radius: number
16
+ }
17
+
18
+ /**
19
+ * Painting state, following OrcaSlicer's own `EnforcerBlockerType`: one enum serving two jobs.
20
+ * `1` is both the support ENFORCER and Extruder 1, `2` is both the BLOCKER and Extruder 2, `3..16` are
21
+ * Extruders 3 to 16. `0` (NONE) is deliberately not a value here — see the `erase` command.
22
+ */
23
+ export type PaintState = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16
24
+
25
+ /** Selection tools that are not the radius brush. All three take the mesh's own topology instead of a radius. */
26
+ export type PaintTool = 'smart' | 'bucket' | 'triangle'
27
+
28
+ export type SlicerRequest =
29
+ /** Load the kernel (and spawn the mt thread pool) ahead of the first slice. Reply: `warm`. */
30
+ | { cmd: 'warmup' }
31
+ /**
32
+ * Register a mesh for painting. `keepPaint` says this is the same model in a new place, so the marks carry
33
+ * over — the reply reports whether they actually did. Reply: `prepared`.
34
+ */
35
+ | { cmd: 'prepare'; stl: ArrayBuffer; keepPaint?: boolean }
36
+ /**
37
+ * Paint. With `state` it addresses any extruder; with `enforcer` it stays on the original boolean pair, where
38
+ * `false` means BLOCKER. `states` asks for those states' counts back. Reply: `painted`.
39
+ */
40
+ | (BrushArgs & { cmd: 'paint'; state?: PaintState; enforcer?: boolean; tool?: PaintTool
41
+ angle?: number; cursor?: 'sphere' | 'circle'; states?: PaintState[] })
42
+ /**
43
+ * Return the brushed facets to the default extruder. Its OWN command rather than `{cmd:'paint', state:0}`:
44
+ * embind coerces a JS `false` to the int `0` == NONE, and the legacy blocker brush sends exactly that `false`,
45
+ * so admitting `0` on the state path would let a stray boolean erase silently. Reply: `painted`.
46
+ */
47
+ | (BrushArgs & { cmd: 'erase'; tool?: PaintTool; angle?: number; states?: PaintState[] })
48
+ /**
49
+ * Load painting out of a 3mf. REPLACES every mark (the kernel's deserialize resets first), so it belongs
50
+ * immediately after a `prepare` and nowhere else. Reply: `painted`, with `applied`.
51
+ */
52
+ | { cmd: 'importPaint'; facets: Int32Array | number[]; hex: string; states?: PaintState[] }
53
+ /** Every marked facet's split tree, in the CURRENT selector's numbering. Reply: `paintExport`. */
54
+ | { cmd: 'exportPaint' }
55
+ /** Wipe every state at once. Reply: `painted`, all zero. */
56
+ | { cmd: 'clear'; states?: PaintState[] }
57
+ /** The painted overlay triangles. `enf`/`blk` always; `states` adds those states. Reply: `overlay`. */
58
+ | { cmd: 'overlay'; states?: PaintState[] }
59
+ /**
60
+ * Legacy single-object SLA (resin) slice. `params` accepts a JSON string or an object (this path parses either). Same reply stream as
61
+ * a slice: `progress` and `layer` while it runs, then `done` (stats only; layers arrived as `layer`) — or `error`.
62
+ */
63
+ | { cmd: 'sla'; stl: ArrayBuffer; params: string | object }
64
+ /** Object-aware SLA protocol. The worker preserves the ordered objects; it never merges them for a fallback. */
65
+ | { cmd: 'slaJob'; job: SlaJob }
66
+ /**
67
+ * Slice — and note it carries **no `cmd`**: slicing is the worker's default action, and leaving the field off
68
+ * is what selects it. `params` must be a JSON **string**; the worker hands it straight to the kernel, which
69
+ * parses JSON text. (`createSlicer().slice()` on the direct handle also accepts an object and stringifies it.)
70
+ * Replies: `progress` and `layer` while it runs, then `done` — or `error`.
71
+ */
72
+ | { stl: ArrayBuffer; params: string }
73
+
74
+ export type SlicerResponse =
75
+ | { type: 'warm' }
76
+ | { type: 'prepared'; facets: number; kept: boolean }
77
+ /**
78
+ * `enf`/`blk` are the counts for states 1 and 2 and are always present, so a listener predating the
79
+ * state-addressed protocol keeps working. `counts` appears only when the request named `states`.
80
+ */
81
+ | { type: 'painted'; enf: number; blk: number; counts?: Record<number, number>; applied?: number }
82
+ /** `supported: false` from a kernel built before the export binding existed — it does not throw. */
83
+ | { type: 'paintExport'; supported: boolean; facets: number[]; hex: string }
84
+ | { type: 'overlay'; enf: Float32Array; blk: Float32Array; overlays?: Record<number, Float32Array> }
85
+ /**
86
+ * Sent once, unprompted, by the multithreaded kernel only: the address of the support-progress counter and of
87
+ * the cancel flag, inside a SharedArrayBuffer. Writing 1 to the cancel flag stops a slice the worker is
88
+ * currently blocked inside. A single-threaded kernel has no shared buffer and never sends this.
89
+ */
90
+ | { type: 'supsab'; buf: SharedArrayBuffer; ptr: number; cancelPtr: number }
91
+ | { type: 'progress'; done: number; total: number }
92
+ /** One sliced layer, its typed arrays transferred rather than copied. */
93
+ | { type: 'layer'; z: number; idx: number; gcode: string; paths: Float32Array; widths: Float32Array }
94
+ /** `result.stats.streamed` says whether the G-code came through `layer` messages or is on the result. */
95
+ | { type: 'done'; result: SliceResult }
96
+ | { type: 'error'; error: string; code?: SlaErrorCode }
97
+
3
98
  export {}