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/types/settings.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// three-slicer/settings
|
|
2
2
|
import type { SlicerSettings, SettingKey, Point } from './settings-keys.d.ts'
|
|
3
|
-
|
|
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 {}
|