three-slicer 0.2.5 → 0.3.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 (44) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/README.md +13 -8
  3. package/THIRD-PARTY-NOTICES.md +7 -2
  4. package/components/dist/SettingsPanel.js +12 -198
  5. package/data/config-schema-lean.json +1 -0
  6. package/data/processes.js +1 -1
  7. package/data/ui-tree-keys.json +1 -0
  8. package/engine/src/client.js +9 -0
  9. package/engine/src/data.js +6 -0
  10. package/engine/src/settings.js +12 -627
  11. package/engine/src/sla_core.js +14 -8
  12. package/engine/src/toggle_eval.js +9 -77
  13. package/package.json +24 -17
  14. package/types/client.d.ts +3 -0
  15. package/types/components.d.ts +3 -29
  16. package/types/settings.d.ts +15 -0
  17. package/types/toggle.d.ts +2 -22
  18. package/types/viewer-gcode.d.ts +2 -29
  19. package/types/viewer-loaders.d.ts +1 -33
  20. package/types/viewer-toolpath.d.ts +3 -113
  21. package/types/viewer.d.ts +6 -213
  22. package/viewer/dist/Viewport.js +9 -6571
  23. package/viewer/dist/gcode_reexport.js +1 -0
  24. package/viewer/dist/loaders_reexport.js +1 -0
  25. package/viewer/dist/toolpath_reexport.js +1 -0
  26. package/components/README.md +0 -44
  27. package/components/styles.css +0 -88
  28. package/engine/src/kernel_setting_keys.js +0 -132
  29. package/engine/src/preset_file.js +0 -99
  30. package/types/.omc/state/sessions/02e5ddf5-4378-46e1-8fca-e90412c30804/pre-tool-advisory-throttle.json +0 -10
  31. package/viewer/README.md +0 -423
  32. package/viewer/dist/gcode_parse.js +0 -190
  33. package/viewer/dist/make_worker.js +0 -31
  34. package/viewer/dist/model_loaders.js +0 -184
  35. package/viewer/dist/parse_3mf-C2X_W442.js +0 -300
  36. package/viewer/dist/parse_3mf.worker.js +0 -10
  37. package/viewer/dist/sl1_encode.worker.js +0 -10
  38. package/viewer/dist/sl1_write-CtX8cVL7.js +0 -302
  39. package/viewer/dist/sla_reconstruct-CXkYhux2.js +0 -176
  40. package/viewer/dist/sla_reconstruct.worker.js +0 -24
  41. package/viewer/dist/sla_slice.worker.js +0 -74
  42. package/viewer/dist/toolpath_gpu-4foc4FaU.js +0 -482
  43. package/viewer/dist/toolpath_gpu.js +0 -13
  44. package/viewer/styles.css +0 -394
@@ -10,7 +10,13 @@
10
10
  // Determinism: iteration order is the STL's own triangle order, stitching maps insert in encounter order, and
11
11
  // vertices on a slicing plane are pushed up by a fixed epsilon — same input bytes, same output bytes.
12
12
 
13
- const ROLE_CONTOUR = 1 // rendered as 'wall' by the preview's feature colouring
13
+ // The toolpath stream and binary STL layouts. This worker is standalone (no imports), so it keeps its own copy of
14
+ // numbers the viewer holds in core/toolpath_encoding.js and core/stl_format.js; TOOLPATH_SPEC.md is the contract.
15
+ const STRIDE = 8 // floats per segment: [x0,y0,z0,enc, x1,y1,z1,enc]
16
+ const ROLE_CONTOUR = 1 // ROLE.WALL — rendered as 'wall' by the preview's feature colouring
17
+ const STL_HEADER_BYTES = 80
18
+ const STL_DATA_OFFSET = 84 // header + the uint32 triangle count
19
+ const STL_TRIANGLE_BYTES = 50
14
20
  const CONTOUR_WIDTH = 0.2 // display width of a contour segment (SLA has no bead width)
15
21
  const PLANE_EPS = 1e-9 // a vertex exactly on a plane counts as above it — deterministic tie-break
16
22
  const KEY_SCALE = 1e4 // endpoint welding: 0.1 micrometre grid
@@ -18,13 +24,13 @@ const KEY_SCALE = 1e4 // endpoint welding: 0.1 micrometre grid
18
24
  /** Binary STL -> Float32Array of 9 floats per triangle (vertices only; normals are recomputed). */
19
25
  export function parseBinarySTL(bytes) {
20
26
  if (!(bytes instanceof Uint8Array)) bytes = new Uint8Array(bytes)
21
- if (bytes.byteLength < 84) return { error: 'not a binary STL (shorter than its own header)' }
27
+ if (bytes.byteLength < STL_DATA_OFFSET) return { error: 'not a binary STL (shorter than its own header)' }
22
28
  const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)
23
- const count = dv.getUint32(80, true)
24
- if (84 + 50 * count !== bytes.byteLength) return { error: 'not a binary STL (triangle count does not match the byte length)' }
29
+ const count = dv.getUint32(STL_HEADER_BYTES, true)
30
+ if (STL_DATA_OFFSET + STL_TRIANGLE_BYTES * count !== bytes.byteLength) return { error: 'not a binary STL (triangle count does not match the byte length)' }
25
31
  const tris = new Float32Array(count * 9)
26
32
  for (let i = 0; i < count; i++) {
27
- const base = 84 + 50 * i + 12 // skip the stored normal — recomputed from the winding below
33
+ const base = STL_DATA_OFFSET + STL_TRIANGLE_BYTES * i + 12 // skip the stored normal — recomputed from the winding below
28
34
  for (let f = 0; f < 9; f++) tris[i * 9 + f] = dv.getFloat32(base + 4 * f, true)
29
35
  }
30
36
  return { tris, count }
@@ -149,15 +155,15 @@ export function sliceSla(stlBytes, params = {}, hooks = {}) {
149
155
  for (const pts of loops) { area += loopArea(pts); segCount += pts.length / 2 }
150
156
  area = Math.max(0, area)
151
157
  volume += area * thickness
152
- const paths = new Float32Array(segCount * 8)
158
+ const paths = new Float32Array(segCount * STRIDE)
153
159
  const widths = new Float32Array(segCount)
154
160
  let w = 0
155
161
  for (const pts of loops) {
156
162
  const n = pts.length / 2
157
163
  for (let p = 0; p < n; p++) {
158
164
  const q = (p + 1) % n
159
- paths[w * 8] = pts[p * 2]; paths[w * 8 + 1] = pts[p * 2 + 1]; paths[w * 8 + 2] = top; paths[w * 8 + 3] = ROLE_CONTOUR
160
- paths[w * 8 + 4] = pts[q * 2]; paths[w * 8 + 5] = pts[q * 2 + 1]; paths[w * 8 + 6] = top; paths[w * 8 + 7] = ROLE_CONTOUR
165
+ paths[w * STRIDE] = pts[p * 2]; paths[w * STRIDE + 1] = pts[p * 2 + 1]; paths[w * STRIDE + 2] = top; paths[w * STRIDE + 3] = ROLE_CONTOUR
166
+ paths[w * STRIDE + 4] = pts[q * 2]; paths[w * STRIDE + 5] = pts[q * 2 + 1]; paths[w * STRIDE + 6] = top; paths[w * STRIDE + 7] = ROLE_CONTOUR
161
167
  widths[w] = CONTOUR_WIDTH
162
168
  w++
163
169
  }
@@ -1,77 +1,9 @@
1
- // Stage 25 S5.1: partial translation of toggle-rules — upstream C++ toggle_options conditions (enable_if) -> JS.
2
- // Scope: among the rules touching keys the viewer handles, only those "fully" translatable with the hardcoded locals below.
3
- // Untranslatable ones (unknown locals, enum comparisons, …) fail open (stay enabled) — avoids wrongly disabling (honest partial implementation).
4
- // Translating all 907 keys / 231 rules is out of scope (noted in the README). Reference: toggle_print_fff_options.locals in toggle-rules.json.
5
- import { toggleRules as toggles, schema } from './data.js'
6
-
7
- // Settings value accessor (settings map first, schema default otherwise). Percentages ("15%") become numbers.
8
- export function makeCfg(settings) {
9
- const val = k => {
10
- let v = settings ? settings[k] : undefined
11
- if (v === undefined || v === '') { const d = schema[k]?.default; v = Array.isArray(d) ? d[0] : d }
12
- return v
13
- }
14
- const num = k => { const v = val(k); const n = parseFloat(v); return Number.isFinite(n) ? n : 0 }
15
- return {
16
- bool: k => { const v = val(k); return v === true || v === 1 || v === '1' || v === 'true' },
17
- int: k => Math.trunc(num(k)),
18
- float: k => num(k),
19
- has: k => k in schema,
20
- }
21
- }
22
-
23
- // Upstream locals translated inline (viewer-related conditions only). Each value is a boolean.
24
- function makeLocals(cfg) {
25
- const have_raft = cfg.int('raft_layers') > 0
26
- const has_spiral_vase = cfg.bool('spiral_mode')
27
- const has_top_shell = cfg.int('top_shell_layers') > 0 || (has_spiral_vase && cfg.int('bottom_shell_layers') > 1)
28
- const has_bottom_shell = cfg.int('bottom_shell_layers') > 0
29
- return {
30
- have_raft,
31
- have_perimeters: cfg.int('wall_loops') > 0,
32
- have_infill: cfg.float('sparse_infill_density') > 0,
33
- has_spiral_vase,
34
- has_top_shell,
35
- has_bottom_shell,
36
- has_solid_infill: has_top_shell || has_bottom_shell,
37
- have_skirt: cfg.int('skirt_loops') > 0,
38
- have_support_material: cfg.bool('enable_support') || have_raft,
39
- have_support_interface: cfg.int('support_interface_top_layers') > 0 || cfg.int('support_interface_bottom_layers') > 0,
40
- have_prime_tower: cfg.bool('enable_prime_tower'),
41
- }
42
- }
43
-
44
- // Evaluates enable_if (up to the first comma) to a boolean. Returns null (= stays enabled) when not fully translatable.
45
- export function evalEnableIf(expr, locals, cfg) {
46
- let s = String(expr).split(',')[0].trim()
47
- if (!s) return null
48
- // Direct config access pattern -> value substitution
49
- s = s.replace(/config->opt_bool\(\s*"([^"]+)"\s*\)/g, (_, k) => cfg.bool(k) ? 'true' : 'false')
50
- s = s.replace(/config->opt_int\(\s*"([^"]+)"\s*\)/g, (_, k) => String(cfg.int(k)))
51
- s = s.replace(/config->opt_float\(\s*"([^"]+)"\s*\)/g, (_, k) => String(cfg.float(k)))
52
- // Substitute known locals (longest name first — prevents partial matches)
53
- for (const name of Object.keys(locals).sort((a, b) => b.length - a.length))
54
- s = s.replace(new RegExp('\\b' + name + '\\b', 'g'), locals[name] ? 'true' : 'false')
55
- // Check the remaining string is a safe boolean expression (only true/false/numbers/operators/parens) — otherwise unknown -> null
56
- const stripped = s.replace(/\btrue\b|\bfalse\b/g, '1')
57
- if (!/^[\s()!<>=&|0-9.]*$/.test(stripped)) return null
58
- try { return !!Function('"use strict";return (' + s + ')')() } catch { return null }
59
- }
60
-
61
- // Map of keys disabled under the current settings { key: condition }. Only rules that are unambiguously false.
62
- export function disabledKeys(cfg) {
63
- const locals = makeLocals(cfg)
64
- const groups = ['toggle_print_fff_options', 'toggle_filament_options', 'toggle_printer_options',
65
- 'TabFilament::toggle_options', 'TabPrinter::toggle_options']
66
- const out = {}
67
- for (const gname of groups) {
68
- const g = toggles[gname]
69
- if (!g || !Array.isArray(g.rules)) continue
70
- for (const rule of g.rules) {
71
- if (!rule.enable_if || !Array.isArray(rule.fields)) continue
72
- const en = evalEnableIf(rule.enable_if, locals, cfg)
73
- if (en === false) for (const k of rule.fields) if (!(k in out)) out[k] = rule.enable_if
74
- }
75
- }
76
- return out
77
- }
1
+ // three-slicer/toggle — the evaluator from the permissive package, bound to upstream's toggle rules.
2
+ // The rules (toggle-rules.json, extracted from OrcaSlicer's toggle_options) and the full schema are this
3
+ // package's data; the evaluator itself is three-slicer-viewer's. Same surface as before the split.
4
+ import { makeToggle, evalEnableIf } from 'three-slicer-viewer/toggle'
5
+ import { toggleRules, schema } from './data.js'
6
+ const bound = makeToggle(toggleRules, schema)
7
+ export const makeCfg = bound.makeCfg
8
+ export const disabledKeys = bound.disabledKeys
9
+ export { evalEnableIf }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-slicer",
3
- "version": "0.2.5",
3
+ "version": "0.3.1",
4
4
  "description": "Browser/WASM 3D-printing slicer reverse-engineered from OrcaSlicer: slicing engine (Arachne walls, tree/grid supports, multi-material), SLA resin slicing with PrusaSlicer's ported support/pad chain and .sl1 export, React viewer with GPU toolpath preview, and schema-driven settings UI.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "type": "module",
@@ -39,15 +39,15 @@
39
39
  },
40
40
  "./viewer/toolpath": {
41
41
  "types": "./types/viewer-toolpath.d.ts",
42
- "default": "./viewer/dist/toolpath_gpu.js"
42
+ "default": "./viewer/dist/toolpath_reexport.js"
43
43
  },
44
44
  "./viewer/loaders": {
45
45
  "types": "./types/viewer-loaders.d.ts",
46
- "default": "./viewer/dist/model_loaders.js"
46
+ "default": "./viewer/dist/loaders_reexport.js"
47
47
  },
48
48
  "./viewer/gcode": {
49
49
  "types": "./types/viewer-gcode.d.ts",
50
- "default": "./viewer/dist/gcode_parse.js"
50
+ "default": "./viewer/dist/gcode_reexport.js"
51
51
  },
52
52
  "./components": {
53
53
  "types": "./types/components.d.ts",
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "sideEffects": false,
67
67
  "scripts": {
68
- "build": "node types/gen_settings_types.mjs && node types/gen_kernel_params.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",
68
+ "build": "node types/gen_settings_types.mjs && node types/gen_kernel_params.mjs && vite build --config components/vite.config.js && vite build --config viewer/vite.config.js",
69
69
  "check": "bash pack_check.sh"
70
70
  },
71
71
  "peerDependencies": {
@@ -74,9 +74,15 @@
74
74
  "three": "^0.160.0"
75
75
  },
76
76
  "peerDependenciesMeta": {
77
- "react": { "optional": true },
78
- "react-dom": { "optional": true },
79
- "three": { "optional": true }
77
+ "react": {
78
+ "optional": true
79
+ },
80
+ "react-dom": {
81
+ "optional": true
82
+ },
83
+ "three": {
84
+ "optional": true
85
+ }
80
86
  },
81
87
  "devDependencies": {
82
88
  "typescript": "^5.6.0",
@@ -84,25 +90,24 @@
84
90
  },
85
91
  "files": [
86
92
  "engine",
87
- "!engine/**/.omc",
88
93
  "types",
89
- "!**/test_*.mjs",
94
+ "!**/tests/**",
90
95
  "!types/gen_*.mjs",
91
96
  "components/dist",
92
97
  "viewer/dist",
93
- "viewer/styles.css",
94
- "components/styles.css",
95
98
  "data",
99
+ "data/ui-tree-keys.json",
100
+ "data/config-schema-lean.json",
96
101
  "!data/config-schema-builddump.json",
97
- "!data/**/.omc",
98
102
  "README.md",
99
103
  "CHANGELOG.md",
100
104
  "THIRD-PARTY-NOTICES.md",
101
- "LICENSE.txt"
105
+ "LICENSE.txt",
106
+ "!**/.omc"
102
107
  ],
103
108
  "repository": {
104
109
  "type": "git",
105
- "url": "git+https://github.com/kimgh06/Web_Three_Slicer.git",
110
+ "url": "git+https://github.com/kimgh06/Three_Slicer.git",
106
111
  "directory": "packages"
107
112
  },
108
113
  "homepage": "https://slicer.kimgh06.com",
@@ -127,6 +132,8 @@
127
132
  "3d",
128
133
  "mesh",
129
134
  "clipping"
130
- ]
135
+ ],
136
+ "dependencies": {
137
+ "three-slicer-viewer": "0.3.1"
138
+ }
131
139
  }
132
-
package/types/client.d.ts CHANGED
@@ -86,3 +86,6 @@ export interface SlicerClient {
86
86
  */
87
87
  export function createSlicerClient(worker?: Worker): SlicerClient
88
88
  export default createSlicerClient
89
+
90
+ /** The WASM kernel's worker, as a factory — what `three-slicer-viewer`'s `useSlicer` takes as `deps.makeWorker`. */
91
+ export function makeSlicerWorker(): Worker
@@ -1,29 +1,3 @@
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 map — only edited keys. Missing keys fall back to the config-schema default. */
7
- settings: SlicerSettings
8
- /** React setState shape. The only channel through which state leaves the component. */
9
- setSettings: React.Dispatch<React.SetStateAction<SlicerSettings>>
10
- /** Label click — for deep links / detail views. Omit for a plain label (zero router coupling). */
11
- onOptionOpen?: (optKey: string) => void
12
- /** When embedding inside another panel */
13
- embedded?: boolean
14
- /** Replace schema-driven widgets per key (e.g. `{ printable_area: MyBedEditor }`) */
15
- customWidgets?: Record<string, React.ComponentType<any>>
16
- /**
17
- * Pins the panel to one builder (optionally one page) and drops the search/group/page/mode chrome, so the form
18
- * can be folded into another card. This is how `<Viewport/>`'s `motionPanel` slot is meant to be filled:
19
- *
20
- * ```jsx
21
- * <SettingsPanel settings={settings} setSettings={setSettings} embedded
22
- * only={{ builder: 'TabPrinter::build_kinematics_page' }} />
23
- * ```
24
- */
25
- only?: { builder: string; page?: string }
26
- }
27
-
28
- declare const SettingsPanel: React.FC<SettingsPanelProps>
29
- export default SettingsPanel
1
+ // three-slicer/components — the permissive settings panel with upstream's data plugged in. Same surface.
2
+ export * from 'three-slicer-viewer/components'
3
+ export { default } from 'three-slicer-viewer/components'
@@ -172,6 +172,18 @@ export function printerDefaultPreset(profileName: string): string
172
172
  /** The schema keys the kernel's machine limits are read from — for UI that shows which ones are in play. */
173
173
  export const machineLimitKeys: string[]
174
174
 
175
+ /** deriveKernelParams' fallbacks when neither the settings map nor the schema gives a usable value, keyed by schema
176
+ * key. NOT the schema defaults — several differ on purpose. Frozen. */
177
+ export const FFF_FALLBACKS: Readonly<Record<string, number | boolean | string>>
178
+ /** deriveSlaParams' fallbacks (its reader treats non-positive values as absent). Frozen. */
179
+ export const SLA_FALLBACKS: Readonly<Record<string, number>>
180
+ /** What `line_width` 0 ("auto") resolves to. */
181
+ export const AUTO_LINE_WIDTH: number
182
+ /** The bed when `printable_area` is empty or malformed — the bbox of the schema's own default. */
183
+ export const BED_FALLBACK: Readonly<{ width: number; depth: number }>
184
+ /** Kernel machine-limit parameter -> [schema key, fallback]. Frozen. */
185
+ export const MACHINE_LIMITS: Readonly<Record<string, readonly [string, number]>>
186
+
175
187
  // ---- Lazily loaded presets --------------------------------------------------
176
188
  // Both facades hide the column layout of the artifact they wrap; the promise is created once and reused.
177
189
 
@@ -201,3 +213,6 @@ export interface FilamentPresetsApi {
201
213
  settingsFor(presetName: string): SlicerSettings | null
202
214
  }
203
215
  export function filamentPresets(): Promise<FilamentPresetsApi>
216
+
217
+ /** The nine catalog lookups above as one object — what `three-slicer-viewer`'s `<Viewport catalog>` takes. */
218
+ export const bundledCatalog: import('three-slicer-viewer').Catalog
package/types/toggle.d.ts CHANGED
@@ -1,22 +1,2 @@
1
- // three-slicer/toggle — partial evaluation of the enable_if expressions in toggle-rules.json.
2
- import type { SlicerSettings } from './settings-keys.d.ts'
3
-
4
- /** Settings accessor — schema default when a value is missing, [0] for vector types. */
5
- export interface ToggleCfg {
6
- bool(key: string): boolean
7
- int(key: string): number
8
- float(key: string): number
9
- /** Whether the key exists in config-schema */
10
- has(key: string): boolean
11
- }
12
-
13
- export function makeCfg(settings: SlicerSettings | null | undefined): ToggleCfg
14
-
15
- /**
16
- * Evaluates a single enable_if expression. Untranslatable expressions return `null` (= fail-open, stays enabled) —
17
- * make sure to treat that as distinct from `false`.
18
- */
19
- export function evalEnableIf(expr: string, locals: Record<string, unknown>, cfg: ToggleCfg): boolean | null
20
-
21
- /** Keys that must be disabled under the current settings -> the enable_if expression that disabled them. Only rules that are unambiguously false. */
22
- export function disabledKeys(cfg: ToggleCfg): Record<string, string>
1
+ // three-slicer/toggle — the permissive evaluator bound to upstream's toggle rules. Same surface.
2
+ export * from 'three-slicer-viewer/toggle'
@@ -1,29 +1,2 @@
1
- // three-slicer/viewer/gcode — G-code text -> kernel-shaped layer stream (renderable without slicing).
2
- // Feed the returned layers straight into buildSegmentData (three-slicer/viewer/toolpath).
3
-
4
- export interface GcodeLayer {
5
- z: number
6
- /** Stride 8: [x0,y0,z0,enc, x1,y1,z1,enc] per segment, enc = role + tool*16 (role 0 = travel). */
7
- paths: Float32Array
8
- /** One entry per segment; 0 means "use the default line width". */
9
- widths: Float32Array
10
- }
11
-
12
- export interface ParseGcodeResult {
13
- layers: GcodeLayer[]
14
- stats: { layers: number; path_segments: number; travel_segments: number; tools: number[] }
15
- }
16
-
17
- export interface ParseGcodeOptions {
18
- /** Used to derive bead width from E when the file has no ;WIDTH: comments. Default 1.75. */
19
- filamentDiameter?: number
20
- /** Bead-height fallback when a layer's height cannot be inferred from z steps. Default 0.2. */
21
- defaultLayerHeight?: number
22
- }
23
-
24
- /**
25
- * Parses G0/G1/G2/G3 (I/J arcs), G90/G91, M82/M83, G92, T<n>, and the layer/role comment conventions of
26
- * OrcaSlicer/PrusaSlicer (;TYPE: ;WIDTH: ;LAYER_CHANGE ;Z:), Cura (;TYPE: ;LAYER:) and this kernel's own output.
27
- * Recovery is lossy where G-code carries no data: unknown roles become wall(1), widths are derived from E.
28
- */
29
- export function parseGcode(text: string, opts?: ParseGcodeOptions): ParseGcodeResult
1
+ // Re-exported from the permissive package (MIT), where the implementation now lives.
2
+ export * from 'three-slicer-viewer/gcode'
@@ -1,33 +1 @@
1
- // three-slicer/viewer/loaders — pure loaders, independent of the kernel.
2
-
3
- /** The 5 built-ins plus any extension registered via `registerLoader()`, which pushes onto this array. */
4
- export const SUPPORTED_EXT: string[]
5
-
6
- /** Lowercased extension. Empty string when there is no dot. */
7
- export function fileExt(name: string): string
8
-
9
- export interface LoadedObject {
10
- name: string
11
- /** Triangle vertex coordinates (N*9, model z-up) */
12
- modelPos: Float32Array
13
- }
14
-
15
- /** A single file may contain several objects (3mf/amf/step) -> always an array. */
16
- export function loadModel(name: string, buffer: ArrayBuffer): Promise<LoadedObject[]>
17
-
18
- /**
19
- * Registers an extra format. Formats needing heavy dependencies (STEP=OCCT WASM, etc.) are not bundled here,
20
- * so the app wires them up itself. The `<Viewport/>` file dialog and drag-and-drop filters pick them up automatically.
21
- *
22
- * ```js
23
- * import { registerLoader } from 'three-slicer/viewer/loaders'
24
- * registerLoader('step,stp', async (buffer, name) => [{ name, modelPos }])
25
- * ```
26
- */
27
- export function registerLoader(
28
- exts: string | string[],
29
- fn: (buffer: ArrayBuffer, name: string) => LoadedObject[] | Promise<LoadedObject[]>,
30
- ): void
31
-
32
- /** Connected-component split. Returns `null` when there is only one component (cannot split) — not an empty array. */
33
- export function splitConnectedComponents(localPos: Float32Array): Float32Array[] | null
1
+ export * from 'three-slicer-viewer/loaders'
@@ -1,113 +1,3 @@
1
- // three-slicer/viewer/toolpath — kernel layers -> GPU-instanced toolpath.
2
- // Does not import three: makeToolpath takes the THREE namespace as an argument (guaranteeing a single instance).
3
-
4
- /** The 24 triangle indices of the 8-vertex diamond cross-section (from SegmentTemplate.cpp:18) */
5
- export const VERTEX_DATA: number[]
6
-
7
- /** Toolpath type -> color. 0=travel, 1=wall … 11=prime */
8
- export const TYPE_COLOR: Record<number, number[]>
9
- export const TYPE_LABEL: Record<number, string>
10
-
11
- /**
12
- * Per-extruder colors for the Filament view. Categorical, not semantic — the toolpath stream carries a tool index and
13
- * nothing about the material, and a machine may have more extruders than entries, so index it modulo its length.
14
- */
15
- export const TOOL_COLOR: number[][]
16
-
17
- /** Blue-to-red 11-color heatmap (libvgcode ColorRange.hpp:14) */
18
- export const DEFAULT_RANGES_COLORS: number[][]
19
-
20
- export interface ViewTypeDef {
21
- key: 'feature' | 'speed' | 'height' | 'width' | 'fan' | 'temp' | 'filament'
22
- label: string
23
- /** Whether values are continuous (heatmap). False means a fixed color. */
24
- cont: boolean
25
- unit: string
26
- }
27
- export const VIEW_TYPES: ViewTypeDef[]
28
-
29
- /** Per-vertex extra data */
30
- export interface SegmentMeta {
31
- vType: Uint8Array
32
- /** Printing extruder, decoded out of the role field's high bits. Untooled output decodes to 0, i.e. single material. */
33
- vTool: Uint8Array
34
- vWidth: Float32Array
35
- vHeight: Float32Array
36
- vLayer: Int32Array
37
- }
38
-
39
- export interface SegmentData {
40
- position: Float32Array
41
- hwa: Float32Array
42
- segIndex: Uint32Array
43
- nV: number
44
- nSeg: number
45
- layerSegPrefix: Uint32Array
46
- travelPos: Float32Array
47
- travelPrefix: Uint32Array
48
- nTrav: number
49
- layerCount: number
50
- maxAbs: number
51
- hasNaN: boolean
52
- meta: SegmentMeta
53
- /** Total extruded length per type (index = toolpath type, length 16) */
54
- typeLengths: Float64Array
55
- /** Null when there is not a single vertex */
56
- bbox: { min: [number, number, number]; max: [number, number, number] } | null
57
- }
58
-
59
- /** Kernel layers[{z, paths(stride8), widths[]}] -> GPU stream. */
60
- export function buildSegmentData(layers: unknown[], defaultLineWidth: number): SegmentData
61
-
62
- /** Length share per type (%), descending by pct. The kernel does not expose time per role, so length is used as an approximation. */
63
- export function roleRatios(typeLengths: Float64Array | number[]): Array<{
64
- type: number
65
- label: string
66
- pct: number
67
- color: number[]
68
- }>
69
-
70
- /**
71
- * speed/fan/temp are absent from the kernel toolpath and derived from settings — these are the values used for that.
72
- */
73
- export interface ColorContext {
74
- speedByType?: Record<number, number>
75
- firstLayerSpeed?: number
76
- fanByType?: Record<number, number>
77
- fanFirstLayers?: number
78
- tempNormal?: number
79
- tempFirst?: number
80
- closeFanLayers?: number
81
- }
82
-
83
- export interface ColorResult {
84
- /** Per-vertex RGBA (nV*4). The color is packed into `.r`. */
85
- color: Float32Array
86
- min: number
87
- max: number
88
- viewType: ViewTypeDef['key']
89
- label: string
90
- unit: string
91
- /** False means fixed colors — min/max are 0 and no legend should be drawn. */
92
- cont: boolean
93
- }
94
-
95
- export function computeColors(data: SegmentData, viewType: ViewTypeDef['key'], ctx: ColorContext): ColorResult
96
-
97
- export interface ToolpathHandle {
98
- /** THREE.Mesh — typed by the THREE namespace passed in */
99
- mesh: any
100
- /** THREE.LineSegments (travel) */
101
- travLines: any
102
- setLayerRange(lo: number, hi: number): void
103
- /** Backwards compatible — same as setLayerRange(0, n-1). */
104
- setVisibleLayers(n: number): void
105
- setTravelVisible(visible: boolean): void
106
- setColors(color: Float32Array): void
107
- dispose(): void
108
- nSeg: number
109
- layerCount: number
110
- }
111
-
112
- /** @param THREE - the `import * as THREE from 'three'` namespace. The consumer's instance is used as-is. */
113
- export function makeToolpath(THREE: any, data: SegmentData): ToolpathHandle
1
+ // Re-exported from the permissive package (MIT), where the implementation now lives.
2
+ // three-slicer/viewer/toolpath stays a valid entry point for every existing consumer.
3
+ export * from 'three-slicer-viewer'