three-slicer 0.1.5 → 0.1.7
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/README.md +256 -21
- package/components/README.md +2 -2
- package/data/README.md +2 -2
- package/data/filaments.js +1 -1
- package/data/preset-keys.json +1 -0
- package/data/processes.js +1 -1
- package/engine/README.md +261 -5
- package/engine/index.d.ts +74 -5
- package/engine/index.js +9 -4
- package/engine/src/client.js +136 -0
- package/engine/src/data.js +3 -0
- package/engine/src/preset_file.js +99 -0
- package/engine/src/settings.js +120 -3
- package/engine/src/slicer.worker.js +30 -3
- package/engine/src/slicer_core.js +0 -0
- package/engine/src/slicer_core.mt.js +0 -0
- package/package.json +20 -10
- package/types/client.d.ts +74 -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.d.ts +90 -2
- package/types/viewer.d.ts +57 -1
- package/types/worker.d.ts +87 -0
- package/viewer/README.md +162 -3
- package/viewer/dist/Viewport.js +3350 -2273
- package/viewer/styles.css +31 -3
- package/types/gen_settings_types.mjs +0 -70
package/viewer/styles.css
CHANGED
|
@@ -18,12 +18,25 @@
|
|
|
18
18
|
.tb-btn { display: inline-flex; align-items: center; gap: 5px; background: #20272f; border: 1px solid #2c353d;
|
|
19
19
|
color: #cdd6dd; border-radius: 6px; padding: 4px 10px; cursor: pointer; font-size: 12px; }
|
|
20
20
|
.tb-btn img { width: 15px; height: 15px; }
|
|
21
|
-
.tb-btn:hover { background: #28313a; }
|
|
21
|
+
.tb-btn:hover:not(:disabled) { background: #28313a; }
|
|
22
|
+
.tb-btn:disabled { color: #5a6570; cursor: not-allowed; opacity: .6; }
|
|
23
|
+
/* The button that is mid-export. It is disabled too, so it must override the greyed-out look — the running action
|
|
24
|
+
is the one thing on screen that should not look inert. The animation is CSS so it keeps running while the main
|
|
25
|
+
thread is inside the synchronous half of the write; it stalls only for that stretch, which is the honest signal. */
|
|
26
|
+
.tb-btn.tb-busy:disabled { color: #cdd6dd; opacity: 1; cursor: progress; border-color: #00ae42; animation: tb-pulse 1s ease-in-out infinite; }
|
|
27
|
+
@keyframes tb-pulse { 0%, 100% { background: #20272f; } 50% { background: #23402c; } }
|
|
22
28
|
.tb-tabs { display: flex; border: 1px solid #2c353d; border-radius: 8px; overflow: hidden; flex: 0 0 auto; }
|
|
23
29
|
.tb-tabs button { padding: 6px 24px; border: 0; background: #1a2027; color: #9fb3c0; font-weight: 600; font-size: 13px; cursor: pointer; }
|
|
24
30
|
.tb-tabs button.on { background: #00ae42; color: #fff; }
|
|
25
31
|
.tb-tabs button:disabled { color: #5a6570; cursor: not-allowed; }
|
|
26
|
-
.
|
|
32
|
+
/* Undo/redo. Written while these two were permanent placeholders, so the BASE rule carried the disabled look —
|
|
33
|
+
dim text and cursor:not-allowed — and there was no enabled, hover or pressed state at all. Now that they work,
|
|
34
|
+
the base is the live look and :disabled carries the dim one, the same split .tb-btn above uses. */
|
|
35
|
+
.tb-icon { width: 28px; height: 28px; border: 1px solid #2c353d; background: #20272f; color: #cdd6dd;
|
|
36
|
+
border-radius: 6px; font-size: 15px; cursor: pointer; }
|
|
37
|
+
.tb-icon:hover:not(:disabled) { background: #28313a; color: #fff; border-color: #3a4550; }
|
|
38
|
+
.tb-icon:active:not(:disabled) { background: #171d23; }
|
|
39
|
+
.tb-icon:disabled { color: #5a6570; cursor: not-allowed; opacity: .6; }
|
|
27
40
|
|
|
28
41
|
/* S3 left gizmo rail */
|
|
29
42
|
.left-rail { flex: 0 0 48px; display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 9px 0;
|
|
@@ -143,7 +156,11 @@
|
|
|
143
156
|
.fil-paint.on { background: #2b6cff; border-color: #2b6cff; }
|
|
144
157
|
|
|
145
158
|
.obj-list2 { list-style: none; margin: 0 0 6px; padding: 0; }
|
|
146
|
-
|
|
159
|
+
|
|
160
|
+
.obj-list2 li { display: flex; align-items: center; gap: 6px; padding: 3px 0; font-size: 12px; cursor: pointer; }
|
|
161
|
+
/* A row of the object list that is part of the current selection. The card is light and the row text is near-black
|
|
162
|
+
(.obj-name is #24282e), so the tint has to be a LIGHT green — a dark one swallows the name it is highlighting. */
|
|
163
|
+
.obj-list2 li.obj-selected { background: #e3f6ea; box-shadow: inset 2px 0 0 #00ae42; }
|
|
147
164
|
.obj-list2 li.obj-hidden { opacity: .5; }
|
|
148
165
|
.obj-eye { border: 0; background: none; cursor: pointer; font-size: 13px; padding: 0; }
|
|
149
166
|
.obj-list2 .obj-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #24282e; }
|
|
@@ -179,6 +196,12 @@
|
|
|
179
196
|
|
|
180
197
|
.vp-canvas { position: absolute; inset: 0; }
|
|
181
198
|
.vp-canvas canvas { display: block; }
|
|
199
|
+
/* The 3D view holds focus so Ctrl+Z can be scoped to this component instead of window — the focus itself stays,
|
|
200
|
+
only its ring is dropped. :focus-visible has to go with it: the focus is taken by a script (`focus()` in the
|
|
201
|
+
view's own pointerdown), and a scripted focus matches :focus-visible in Chrome even when the pointer caused it,
|
|
202
|
+
so a plain click drew the ring the :focus rule below was written to prevent. CSS cannot tell that click apart
|
|
203
|
+
from a Tab, so a keyboard user gets no ring here; the gizmo rail and the panels keep theirs. */
|
|
204
|
+
.vp-canvas:focus, .vp-canvas:focus-visible { outline: none; }
|
|
182
205
|
.vp-canvas.fail { display: flex; align-items: center; justify-content: center; }
|
|
183
206
|
.vp-fallback { color: #f0c9a8; padding: 24px; text-align: center; max-width: 560px; line-height: 1.5; }
|
|
184
207
|
.vp-status { position: absolute; bottom: 8px; left: 12px; right: 12px; z-index: 1;
|
|
@@ -306,3 +329,8 @@
|
|
|
306
329
|
border-radius: 4px; padding: 2px 3px; font-size: 11px; }
|
|
307
330
|
.sc-num input { width: 62px; background: #1a2027; border: 1px solid #2c353d; color: #cdd6dd; border-radius: 4px;
|
|
308
331
|
padding: 2px 5px; font-size: 12px; margin-left: 4px; }
|
|
332
|
+
|
|
333
|
+
/* A panel shown but not editable (panels={{ printerCard: 'readonly' }}). `inert` on the wrapper already blocks
|
|
334
|
+
pointer, keyboard and focus — this only has to make that legible, or the card reads as broken rather than locked. */
|
|
335
|
+
.vp-readonly { opacity: .62; cursor: default; }
|
|
336
|
+
.vp-readonly * { cursor: default !important; }
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
// config-schema.json -> types/settings-keys.d.ts (the SlicerSettings interface, 907 keys).
|
|
2
|
-
// Regenerate: node types/gen_settings_types.mjs (do not hand-edit — fix this script instead)
|
|
3
|
-
//
|
|
4
|
-
// ponytail: mapping is driven purely by the schema's coXxx type. min/max and nullable are not reflected in types
|
|
5
|
-
// (they are runtime validation, not type validation, and 907 keys x branded number slows tsc down).
|
|
6
|
-
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'
|
|
7
|
-
import { dirname, resolve } from 'node:path'
|
|
8
|
-
import { fileURLToPath } from 'node:url'
|
|
9
|
-
|
|
10
|
-
const here = dirname(fileURLToPath(import.meta.url))
|
|
11
|
-
const schema = JSON.parse(readFileSync(resolve(here, '../data/config-schema.json'), 'utf8'))
|
|
12
|
-
|
|
13
|
-
const lit = (v) => "'" + String(v).replace(/\\/g, '\\\\').replace(/'/g, "\\'") + "'"
|
|
14
|
-
// Some coEnum entries have no enum_values (70/64 mismatch) -> fail open to string.
|
|
15
|
-
const enumOf = (o) => (Array.isArray(o.enum_values) && o.enum_values.length)
|
|
16
|
-
? o.enum_values.map(lit).join(' | ')
|
|
17
|
-
: 'string'
|
|
18
|
-
|
|
19
|
-
// Vector types are `T[] | T` — settingScalar() accepts both, and the UI edits only the first element (settings.js:9).
|
|
20
|
-
const vec = (t) => `${/\|/.test(t) ? `(${t})` : t}[] | ${/\|/.test(t) ? `(${t})` : t}`
|
|
21
|
-
|
|
22
|
-
function tsType(o) {
|
|
23
|
-
switch (o.type) {
|
|
24
|
-
case 'coBool': return 'boolean'
|
|
25
|
-
case 'coBools': return vec('boolean')
|
|
26
|
-
case 'coInt': case 'coFloat': case 'coPercent': return 'number'
|
|
27
|
-
case 'coInts': case 'coFloats': case 'coPercents': return vec('number')
|
|
28
|
-
case 'coFloatOrPercent': return 'number | string'
|
|
29
|
-
case 'coFloatsOrPercents': return vec('number | string')
|
|
30
|
-
case 'coString': return 'string'
|
|
31
|
-
case 'coStrings': return vec('string')
|
|
32
|
-
case 'coEnum': return enumOf(o)
|
|
33
|
-
case 'coEnums': return vec(enumOf(o))
|
|
34
|
-
case 'coPoint': return 'Point'
|
|
35
|
-
case 'coPoints': return 'Point[]'
|
|
36
|
-
case 'coPointsGroups': return 'Point[][]'
|
|
37
|
-
default: return 'unknown'
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const esc = (s) => String(s).replace(/\*\//g, '*\\/')
|
|
42
|
-
const ident = (k) => /^[A-Za-z_$][\w$]*$/.test(k) ? k : lit(k).replace(/^'|'$/g, (m) => m === "'" ? "'" : m)
|
|
43
|
-
|
|
44
|
-
const lines = []
|
|
45
|
-
for (const key of Object.keys(schema).sort()) {
|
|
46
|
-
const o = schema[key]
|
|
47
|
-
const doc = [o.label, o.sidetext ? `(${o.sidetext})` : '', o.tooltip].filter(Boolean).join(' — ')
|
|
48
|
-
if (doc) lines.push(` /** ${esc(doc).replace(/\s*\n\s*/g, ' ')} */`)
|
|
49
|
-
const name = /^[A-Za-z_$][\w$]*$/.test(key) ? key : lit(key)
|
|
50
|
-
lines.push(` ${name}?: ${tsType(o)}`)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
writeFileSync(resolve(here, 'settings-keys.d.ts'), `// AUTO-GENERATED by types/gen_settings_types.mjs — DO NOT EDIT.
|
|
54
|
-
// Source: data/config-schema.json (${Object.keys(schema).length} keys)
|
|
55
|
-
|
|
56
|
-
/** [x, y] — coPoint family */
|
|
57
|
-
export type Point = [number, number]
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Slicer settings map. Sparse — it holds only edited keys; missing keys use the config-schema default.
|
|
61
|
-
* If you need arbitrary key extension, widen it with \`SlicerSettings & Record<string, unknown>\`.
|
|
62
|
-
*/
|
|
63
|
-
export interface SlicerSettings {
|
|
64
|
-
${lines.join('\n')}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** Setting keys that exist in config-schema */
|
|
68
|
-
export type SettingKey = keyof SlicerSettings & string
|
|
69
|
-
`)
|
|
70
|
-
console.log(`settings-keys.d.ts written — ${Object.keys(schema).length} keys`)
|