three-slicer 0.2.3 → 0.2.5
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/components/dist/SettingsPanel.js +138 -116
- package/components/styles.css +4 -0
- package/engine/src/client.js +12 -2
- package/engine/src/slicer.worker.js +51 -1
- package/engine/src/slicer_core.js +0 -0
- package/engine/src/slicer_core.mt.js +0 -0
- package/package.json +1 -1
- package/types/.omc/state/sessions/02e5ddf5-4378-46e1-8fca-e90412c30804/pre-tool-advisory-throttle.json +10 -0
- package/types/client.d.ts +2 -2
- package/types/viewer.d.ts +41 -2
- package/types/worker.d.ts +30 -1
- package/viewer/README.md +69 -1
- package/viewer/dist/Viewport.js +5091 -3644
- package/viewer/dist/sl1_encode.worker.js +8 -8
- package/viewer/dist/sl1_write-CtX8cVL7.js +302 -0
- package/viewer/dist/sla_slice.worker.js +1 -1
- package/viewer/styles.css +45 -0
- package/viewer/dist/sl1_write-UHmQ_itC.js +0 -170
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
1
|
+
import { zlibSync as p } from "three/examples/jsm/libs/fflate.module.js";
|
|
2
|
+
import { s as m, r as l, e as g } from "./sl1_write-CtX8cVL7.js";
|
|
3
|
+
self.onmessage = async ({ data: { indices: r, paths: o, params: t, aa: f } }) => {
|
|
4
|
+
const a = m(t), e = [];
|
|
5
|
+
for (let s = 0; s < r.length; s++) {
|
|
6
|
+
const n = l(o[s], a, f || 1);
|
|
7
|
+
e.push(await g(n, a.px, a.py, { deflate: p })), (s & 7) === 7 && self.postMessage({ progress: s + 1 });
|
|
8
8
|
}
|
|
9
|
-
self.postMessage({ indices:
|
|
9
|
+
self.postMessage({ indices: r, pngs: e }, e.map((s) => s.buffer));
|
|
10
10
|
};
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { strToU8 as I, zipSync as z, zlibSync as O } from "three/examples/jsm/libs/fflate.module.js";
|
|
2
|
+
let M = !0;
|
|
3
|
+
function it(t) {
|
|
4
|
+
M = !!t;
|
|
5
|
+
}
|
|
6
|
+
const j = {
|
|
7
|
+
info: (...t) => {
|
|
8
|
+
M && console.info(...t);
|
|
9
|
+
},
|
|
10
|
+
warn: (...t) => {
|
|
11
|
+
M && console.warn(...t);
|
|
12
|
+
},
|
|
13
|
+
error: (...t) => {
|
|
14
|
+
M && console.error(...t);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function X(t) {
|
|
18
|
+
const e = [];
|
|
19
|
+
let n = null;
|
|
20
|
+
for (let r = 0; r < t.length; r += 8) {
|
|
21
|
+
const a = t[r], f = t[r + 1], l = t[r + 4], s = t[r + 5];
|
|
22
|
+
n && Math.abs(n.lx - a) < 1e-6 && Math.abs(n.ly - f) < 1e-6 ? (n.pts.push(l, s), n.lx = l, n.ly = s) : (n = { pts: [a, f, l, s], lx: l, ly: s }, e.push(n));
|
|
23
|
+
}
|
|
24
|
+
return e.map((r) => r.pts);
|
|
25
|
+
}
|
|
26
|
+
function R(t, e, n, r, a, f) {
|
|
27
|
+
const l = new Array(n).fill(null);
|
|
28
|
+
for (const c of t) {
|
|
29
|
+
const i = c.length / 2;
|
|
30
|
+
for (let o = 0; o < i; o++) {
|
|
31
|
+
const d = (o + 1) % i;
|
|
32
|
+
let u = r(c[o * 2], c[o * 2 + 1]), p = a(c[o * 2], c[o * 2 + 1]), g = r(c[d * 2], c[d * 2 + 1]), w = a(c[d * 2], c[d * 2 + 1]);
|
|
33
|
+
if (p === w) continue;
|
|
34
|
+
if (p > w) {
|
|
35
|
+
const y = u;
|
|
36
|
+
u = g, g = y;
|
|
37
|
+
const b = p;
|
|
38
|
+
p = w, w = b;
|
|
39
|
+
}
|
|
40
|
+
const m = Math.max(0, Math.ceil(p - 0.5));
|
|
41
|
+
if (m >= n || w < 0.5) continue;
|
|
42
|
+
const _ = { x: u + (m + 0.5 - p) / (w - p) * (g - u), dx: (g - u) / (w - p), yEnd: w };
|
|
43
|
+
(l[m] ?? (l[m] = [])).push(_);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const s = [];
|
|
47
|
+
for (let c = 0; c < n; c++) {
|
|
48
|
+
const i = c + 0.5;
|
|
49
|
+
l[c] && s.push(...l[c]);
|
|
50
|
+
for (let o = s.length - 1; o >= 0; o--) s[o].yEnd <= i && s.splice(o, 1);
|
|
51
|
+
s.sort((o, d) => o.x - d.x);
|
|
52
|
+
for (let o = 0; o + 1 < s.length; o += 2) {
|
|
53
|
+
const d = Math.max(0, Math.ceil(s[o].x - 0.5)), u = Math.min(e - 1, Math.floor(s[o + 1].x - 0.5));
|
|
54
|
+
u >= d && f(c, d, u);
|
|
55
|
+
}
|
|
56
|
+
for (const o of s) o.x += o.dx;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function Y(t, e, n = 1) {
|
|
60
|
+
const { px: r, py: a } = e, f = X(t), l = new Uint8Array(r * a);
|
|
61
|
+
if (n <= 1)
|
|
62
|
+
return R(
|
|
63
|
+
f,
|
|
64
|
+
r,
|
|
65
|
+
a,
|
|
66
|
+
(i, o) => e.map(i, o)[0],
|
|
67
|
+
(i, o) => e.map(i, o)[1],
|
|
68
|
+
(i, o, d) => {
|
|
69
|
+
l.fill(255, i * r + o, i * r + d + 1);
|
|
70
|
+
}
|
|
71
|
+
), l;
|
|
72
|
+
const s = new Uint16Array(r * a);
|
|
73
|
+
R(
|
|
74
|
+
f,
|
|
75
|
+
r * n,
|
|
76
|
+
a * n,
|
|
77
|
+
(i, o) => e.map(i, o)[0] * n,
|
|
78
|
+
(i, o) => e.map(i, o)[1] * n,
|
|
79
|
+
(i, o, d) => {
|
|
80
|
+
const u = i / n | 0;
|
|
81
|
+
for (let p = o; p <= d; p++) s[u * r + (p / n | 0)]++;
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
const c = n * n;
|
|
85
|
+
for (let i = 0; i < s.length; i++) l[i] = Math.round(s[i] * 255 / c);
|
|
86
|
+
return l;
|
|
87
|
+
}
|
|
88
|
+
const G = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]), W = (() => {
|
|
89
|
+
const t = new Uint32Array(256);
|
|
90
|
+
for (let e = 0; e < 256; e++) {
|
|
91
|
+
let n = e;
|
|
92
|
+
for (let r = 0; r < 8; r++) n = n & 1 ? 3988292384 ^ n >>> 1 : n >>> 1;
|
|
93
|
+
t[e] = n >>> 0;
|
|
94
|
+
}
|
|
95
|
+
return t;
|
|
96
|
+
})(), H = (t) => {
|
|
97
|
+
let e = 4294967295;
|
|
98
|
+
for (let n = 0; n < t.length; n++) e = W[(e ^ t[n]) & 255] ^ e >>> 8;
|
|
99
|
+
return (e ^ 4294967295) >>> 0;
|
|
100
|
+
}, E = (t, e) => {
|
|
101
|
+
const n = new Uint8Array(12 + e.length), r = new DataView(n.buffer);
|
|
102
|
+
r.setUint32(0, e.length);
|
|
103
|
+
for (let f = 0; f < 4; f++) n[4 + f] = t.charCodeAt(f);
|
|
104
|
+
n.set(e, 8);
|
|
105
|
+
const a = n.subarray(4, 8 + e.length);
|
|
106
|
+
return r.setUint32(8 + e.length, H(a)), n;
|
|
107
|
+
}, Z = async (t) => {
|
|
108
|
+
const e = new CompressionStream("deflate"), n = [], r = (async () => {
|
|
109
|
+
const c = e.readable.getReader();
|
|
110
|
+
for (; ; ) {
|
|
111
|
+
const { value: i, done: o } = await c.read();
|
|
112
|
+
if (o) break;
|
|
113
|
+
n.push(i);
|
|
114
|
+
}
|
|
115
|
+
})(), a = e.writable.getWriter();
|
|
116
|
+
await a.write(t), await a.close(), await r;
|
|
117
|
+
let f = 0;
|
|
118
|
+
for (const c of n) f += c.length;
|
|
119
|
+
const l = new Uint8Array(f);
|
|
120
|
+
let s = 0;
|
|
121
|
+
for (const c of n)
|
|
122
|
+
l.set(c, s), s += c.length;
|
|
123
|
+
return l;
|
|
124
|
+
};
|
|
125
|
+
async function q(t, e, n, r = {}) {
|
|
126
|
+
if (t.length !== e * n) throw new Error(`gray8: ${t.length} bytes for ${e}x${n}`);
|
|
127
|
+
const a = new Uint8Array(13), f = new DataView(a.buffer);
|
|
128
|
+
f.setUint32(0, e), f.setUint32(4, n), a[8] = 8, a[9] = 0;
|
|
129
|
+
const l = new Uint8Array(n * (1 + e));
|
|
130
|
+
for (let u = 0; u < n; u++) l.set(t.subarray(u * e, (u + 1) * e), u * (1 + e) + 1);
|
|
131
|
+
const s = typeof CompressionStream < "u" ? await Z(l) : r.deflate ? r.deflate(l) : (() => {
|
|
132
|
+
throw new Error("gray8: no CompressionStream and no deflate fallback injected");
|
|
133
|
+
})(), c = [G, E("IHDR", a), E("IDAT", s), E("IEND", new Uint8Array(0))];
|
|
134
|
+
let i = 0;
|
|
135
|
+
for (const u of c) i += u.length;
|
|
136
|
+
const o = new Uint8Array(i);
|
|
137
|
+
let d = 0;
|
|
138
|
+
for (const u of c)
|
|
139
|
+
o.set(u, d), d += u.length;
|
|
140
|
+
return o;
|
|
141
|
+
}
|
|
142
|
+
function J(t) {
|
|
143
|
+
const e = Number(t.display_width) > 0 ? Number(t.display_width) : 120.96, n = Number(t.display_height) > 0 ? Number(t.display_height) : 68.04, r = Number(t.display_pixels_x) > 0 ? Math.round(Number(t.display_pixels_x)) : 2560, a = Number(t.display_pixels_y) > 0 ? Math.round(Number(t.display_pixels_y)) : 1440, f = t.display_mirror_x !== !1, l = t.display_mirror_y === !0, s = (t.display_orientation ?? "portrait") !== "landscape", c = r / e, i = a / n, o = (u) => (f ? e / 2 - u : u + e / 2) * c, d = (u) => (l ? n / 2 - u : u + n / 2) * i;
|
|
144
|
+
return s ? {
|
|
145
|
+
px: a,
|
|
146
|
+
py: r,
|
|
147
|
+
mirrorX: f,
|
|
148
|
+
portrait: s,
|
|
149
|
+
// canvas columns run along the display's y axis, rows along the (mirrored) x axis
|
|
150
|
+
map: (u, p) => [d(p), o(u)]
|
|
151
|
+
} : {
|
|
152
|
+
px: r,
|
|
153
|
+
py: a,
|
|
154
|
+
mirrorX: f,
|
|
155
|
+
portrait: s,
|
|
156
|
+
map: (u, p) => [o(u), d(p)]
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function K(t, e, n) {
|
|
160
|
+
const r = e.length / 8;
|
|
161
|
+
if (!r) return 0;
|
|
162
|
+
let a = 0;
|
|
163
|
+
t.beginPath();
|
|
164
|
+
let f = NaN, l = NaN;
|
|
165
|
+
for (let s = 0; s < r; s++) {
|
|
166
|
+
const c = e[s * 8], i = e[s * 8 + 1], o = e[s * 8 + 4], d = e[s * 8 + 5];
|
|
167
|
+
(c !== f || i !== l) && (t.moveTo(...n.map(c, i)), a++), t.lineTo(...n.map(o, d)), f = o, l = d;
|
|
168
|
+
}
|
|
169
|
+
return t.fill("evenodd"), a;
|
|
170
|
+
}
|
|
171
|
+
const Q = (t) => String(t ?? "");
|
|
172
|
+
function P({ params: t, stats: e, jobName: n, timestamp: r }) {
|
|
173
|
+
const a = String(t.material_print_speed ?? "fast"), f = {
|
|
174
|
+
action: "print",
|
|
175
|
+
jobDir: n,
|
|
176
|
+
expTime: t.exposure_time,
|
|
177
|
+
expTimeFirst: t.initial_exposure_time,
|
|
178
|
+
expUserProfile: a === "slow" ? 1 : a === "fast" ? 0 : 2,
|
|
179
|
+
fileCreationTimestamp: r ?? "",
|
|
180
|
+
hollow: t.hollowing_enable ? 1 : 0,
|
|
181
|
+
layerHeight: t.layer_height,
|
|
182
|
+
materialName: t.sla_material_settings_id ?? "",
|
|
183
|
+
numFade: t.faded_layers,
|
|
184
|
+
numFast: e.layers,
|
|
185
|
+
numSlow: 0,
|
|
186
|
+
printProfile: t.sla_print_settings_id ?? "",
|
|
187
|
+
printTime: Number(e.time_estimate ?? 0).toFixed(6),
|
|
188
|
+
printerModel: t.printer_model ?? "",
|
|
189
|
+
printerProfile: t.printer_settings_id ?? "",
|
|
190
|
+
printerVariant: t.printer_variant ?? "",
|
|
191
|
+
prusaSlicerVersion: "three-slicer",
|
|
192
|
+
usedMaterial: Number(e.resin_ml ?? 0).toFixed(6)
|
|
193
|
+
};
|
|
194
|
+
return Object.keys(f).sort().map((l) => `${l} = ${Q(f[l])}`).join(`
|
|
195
|
+
`) + `
|
|
196
|
+
`;
|
|
197
|
+
}
|
|
198
|
+
const T = (t, e) => `${t}${String(e).padStart(5, "0")}.png`, tt = "Metadata/threeslicer_roles.bin", et = "Metadata/threeslicer_scene.bin";
|
|
199
|
+
function nt({ modelSTL: t, supportMesh: e, padMesh: n, lift: r = 0 }) {
|
|
200
|
+
const a = t instanceof Uint8Array ? t : new Uint8Array(t ?? 0), f = e instanceof Float32Array ? e : new Float32Array(e ?? 0), l = n instanceof Float32Array ? n : new Float32Array(n ?? 0), s = new Uint8Array(12 + a.length + 4 + f.length * 4 + 4 + l.length * 4), c = new DataView(s.buffer);
|
|
201
|
+
s.set([84, 83, 83, 49], 0), c.setFloat32(4, r, !0);
|
|
202
|
+
let i = 8;
|
|
203
|
+
c.setUint32(i, a.length, !0), i += 4, s.set(a, i), i += a.length;
|
|
204
|
+
for (const o of [f, l]) {
|
|
205
|
+
c.setUint32(i, o.length, !0), i += 4;
|
|
206
|
+
for (let d = 0; d < o.length; d++)
|
|
207
|
+
c.setFloat32(i, o[d], !0), i += 4;
|
|
208
|
+
}
|
|
209
|
+
return s;
|
|
210
|
+
}
|
|
211
|
+
function ot(t) {
|
|
212
|
+
const e = t.map(({ paths: l }) => {
|
|
213
|
+
const s = [];
|
|
214
|
+
for (let c = 0; c + 7 < l.length; c += 8) {
|
|
215
|
+
const i = l[c + 3] & 15;
|
|
216
|
+
if (i === 5 || i === 6) for (let o = 0; o < 8; o++) s.push(l[c + o]);
|
|
217
|
+
}
|
|
218
|
+
return s;
|
|
219
|
+
}), n = 8 + e.reduce((l, s) => l + 4 + s.length * 4, 0), r = new Uint8Array(n), a = new DataView(r.buffer);
|
|
220
|
+
r.set([84, 83, 82, 49], 0), a.setUint32(4, e.length, !0);
|
|
221
|
+
let f = 8;
|
|
222
|
+
for (const l of e) {
|
|
223
|
+
a.setUint32(f, l.length, !0), f += 4;
|
|
224
|
+
for (const s of l)
|
|
225
|
+
a.setFloat32(f, s, !0), f += 4;
|
|
226
|
+
}
|
|
227
|
+
return r;
|
|
228
|
+
}
|
|
229
|
+
function rt({ layers: t, params: e, makeWorker: n, workerCount: r, onProgress: a, aa: f = 1 }) {
|
|
230
|
+
return new Promise((l, s) => {
|
|
231
|
+
const c = new Array(t.length), i = new Array(r).fill(0);
|
|
232
|
+
let o = 0, d = !1;
|
|
233
|
+
const u = [], p = (g) => {
|
|
234
|
+
d = !0, u.forEach((w) => w.terminate()), s(g);
|
|
235
|
+
};
|
|
236
|
+
for (let g = 0; g < r; g++) {
|
|
237
|
+
const w = [], m = [];
|
|
238
|
+
for (let y = g; y < t.length; y += r)
|
|
239
|
+
w.push(y), m.push(t[y].paths);
|
|
240
|
+
const _ = n();
|
|
241
|
+
u.push(_), _.onerror = (y) => p(new Error("SL1 encode worker: " + ((y == null ? void 0 : y.message) || "failed"))), _.onmessage = ({ data: y }) => {
|
|
242
|
+
if (!d) {
|
|
243
|
+
if (y.progress != null) {
|
|
244
|
+
i[g] = y.progress, a == null || a(i.reduce((b, U) => b + U, 0), t.length);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
y.indices.forEach((b, U) => {
|
|
248
|
+
c[b] = y.pngs[U];
|
|
249
|
+
}), _.terminate(), ++o === r && l(c);
|
|
250
|
+
}
|
|
251
|
+
}, _.postMessage({ indices: w, paths: m, params: e, aa: f });
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
async function lt({ layers: t, params: e, stats: n, jobName: r = "plate", timestamp: a, makeCanvas: f, onProgress: l, scene: s = null, makeWorker: c = null, workerCount: i = 0, aa: o = 1, gpuRaster: d = null }) {
|
|
256
|
+
const u = f ?? null, p = J(e), g = {}, w = c && typeof Worker < "u" && t.length > 1 ? {
|
|
257
|
+
makeWorker: c,
|
|
258
|
+
workerCount: Math.max(1, Math.min(i > 0 ? i : 4, t.length))
|
|
259
|
+
} : null, m = () => performance.now(), _ = { canvas: 0, clear: 0, draw: 0, encode: 0, read: 0 }, y = (x, h) => {
|
|
260
|
+
const $ = m();
|
|
261
|
+
return _[x] += $ - h, $;
|
|
262
|
+
};
|
|
263
|
+
let b = 0, U = 0;
|
|
264
|
+
const B = async (x) => {
|
|
265
|
+
let h = m();
|
|
266
|
+
if (!u) {
|
|
267
|
+
const V = d ? await d(t[x].paths, p, o, t[x], x) : Y(t[x].paths, p, o);
|
|
268
|
+
h = y("draw", h);
|
|
269
|
+
const D = await q(V, p.px, p.py, { deflate: O });
|
|
270
|
+
return y("encode", h), b += D.length, D;
|
|
271
|
+
}
|
|
272
|
+
const $ = u(p.px, p.py), S = $.getContext("2d");
|
|
273
|
+
h = y("canvas", h), S.fillStyle = "#000", S.fillRect(0, 0, p.px, p.py), h = y("clear", h), S.fillStyle = "#fff", U += K(S, t[x].paths, p), h = y("draw", h);
|
|
274
|
+
const L = await $.convertToBlob({ type: "image/png" });
|
|
275
|
+
h = y("encode", h);
|
|
276
|
+
const C = new Uint8Array(await L.arrayBuffer());
|
|
277
|
+
return y("read", h), b += C.length, C;
|
|
278
|
+
}, F = m();
|
|
279
|
+
if (w) {
|
|
280
|
+
const x = await rt({ layers: t, params: e, onProgress: l, aa: o, ...w });
|
|
281
|
+
for (let h = 0; h < t.length; h++)
|
|
282
|
+
g[T(r, h)] = [x[h], { level: 0 }], b += x[h].length;
|
|
283
|
+
} else
|
|
284
|
+
for (let x = 0; x < t.length; x++)
|
|
285
|
+
g[T(r, x)] = [await B(x), { level: 0 }], x & 31 || l == null || l(x, t.length);
|
|
286
|
+
const v = m();
|
|
287
|
+
g["config.ini"] = I(P({ params: e, stats: n, jobName: r, timestamp: a })), g[tt] = [ot(t), { level: 6 }], s && (g[et] = [nt(s), { level: 6 }]);
|
|
288
|
+
const N = m(), k = z(g), A = (x) => x.toFixed(0);
|
|
289
|
+
return j.info(`[vp-prof] sl1 build: ${t.length} layers ${p.px}x${p.py},` + (w ? ` raster ${A(v - F)}ms (${w.workerCount} workers),` : ` ${U} loops, raster ${A(v - F)}ms (canvas ${A(_.canvas)} + clear ${A(_.clear)} + draw ${A(_.draw)} + encode ${A(_.encode)} + read ${A(_.read)}),`) + ` sidecar ${A(N - v)}ms, zip ${A(m() - N)}ms -> ${(k.byteLength / 1e6).toFixed(1)}MB (png ${(b / 1e6).toFixed(1)}MB)`), k;
|
|
290
|
+
}
|
|
291
|
+
export {
|
|
292
|
+
et as S,
|
|
293
|
+
tt as a,
|
|
294
|
+
X as b,
|
|
295
|
+
it as c,
|
|
296
|
+
K as d,
|
|
297
|
+
q as e,
|
|
298
|
+
j as l,
|
|
299
|
+
lt as m,
|
|
300
|
+
Y as r,
|
|
301
|
+
J as s
|
|
302
|
+
};
|
package/viewer/styles.css
CHANGED
|
@@ -82,6 +82,30 @@
|
|
|
82
82
|
.plate-tab.on { background: #00ae42; color: #fff; border-color: #00ae42; }
|
|
83
83
|
.plate-add { color: #7ad19a !important; } .plate-del { color: #e08a8a !important; }
|
|
84
84
|
.plate-bar button:disabled { opacity: .4; cursor: not-allowed; }
|
|
85
|
+
/* Per-plate override marker: this plate slices with something other than the global settings. */
|
|
86
|
+
.plate-tab { position: relative; }
|
|
87
|
+
.plate-dot { position: absolute; top: 2px; right: 2px; width: 5px; height: 5px; border-radius: 50%; background: #f0a542; }
|
|
88
|
+
.plate-tab.on .plate-dot { background: #fff; }
|
|
89
|
+
/* An all-plates run: what each plate is doing, independent of which one is selected. */
|
|
90
|
+
.plate-tab.run-queued { border-style: dashed; }
|
|
91
|
+
.plate-tab.run-busy { border-color: #00ae42; animation: tb-pulse 1s ease-in-out infinite; }
|
|
92
|
+
.plate-tab.run-busy.on { animation: none; }
|
|
93
|
+
.plate-tab.run-done { box-shadow: inset 0 -3px 0 #00ae42; }
|
|
94
|
+
.plate-tab.run-failed { border-color: #d9534f; }
|
|
95
|
+
/* Settings-scope toggle in the process card head: writes go to the global map or the selected plate's override. */
|
|
96
|
+
.scope-toggle { margin-left: auto; display: flex; gap: 0; border: 1px solid #d5d8dd; border-radius: 6px; overflow: hidden; }
|
|
97
|
+
.scope-toggle button { border: 0; background: #f3f5f7; color: #5a6472; font-size: 11px; font-weight: 600; padding: 3px 8px; cursor: pointer; }
|
|
98
|
+
.scope-toggle button.on { background: #00ae42; color: #fff; }
|
|
99
|
+
.sc-bed-warn { color: #a86a12; background: #fdf4e3; border-radius: 6px; padding: 5px 8px; font-size: 12px; line-height: 1.4; }
|
|
100
|
+
/* Object-list plate headers: which plate a row's object slices on (same colour language as the PlateBar). */
|
|
101
|
+
.obj-plate-head { display: flex; align-items: center; gap: 6px; padding: 4px 2px 2px; margin-top: 4px; cursor: pointer;
|
|
102
|
+
border-bottom: 1px solid #e6e9ec; font-size: 12px; font-weight: 700; color: #5a6472; list-style: none; }
|
|
103
|
+
.obj-plate-head.on { color: #00913a; border-bottom-color: #9adfb6; }
|
|
104
|
+
.obj-plate-head .obj-plate-tech { background: #6d7ce0; color: #fff; border-radius: 7px; padding: 0 6px; font-size: 10px; font-weight: 700; }
|
|
105
|
+
.obj-plate-head .obj-plate-dot { width: 6px; height: 6px; border-radius: 50%; background: #f0a542; }
|
|
106
|
+
.obj-plate-head .obj-plate-count { margin-left: auto; font-weight: 400; color: #97a1ac; }
|
|
107
|
+
.obj-plate-head .obj-plate-sup { display: inline-flex; align-items: center; gap: 3px; font-weight: 400; font-size: 11px; color: #5a6472; cursor: pointer; }
|
|
108
|
+
.obj-plate-head .obj-plate-sup input { margin: 0; }
|
|
85
109
|
.slice-dd { position: relative; flex: 1.4; }
|
|
86
110
|
.slice-dd .slice-btn { width: 100%; }
|
|
87
111
|
.slice-menu { position: absolute; bottom: calc(100% + 6px); left: 0; right: 0; background: #fff; border: 1px solid #d5d8dd;
|
|
@@ -89,6 +113,19 @@
|
|
|
89
113
|
.slice-menu button { display: block; width: 100%; text-align: left; padding: 9px 12px; border: 0; background: #fff;
|
|
90
114
|
color: #24282e; cursor: pointer; font-size: 13px; }
|
|
91
115
|
.slice-menu button:hover { background: #eef7f1; }
|
|
116
|
+
/* The worker-count row inside the menu: a value, not an action, so it is a label with a select. */
|
|
117
|
+
.slice-workers { display: flex; align-items: center; gap: 8px; padding: 7px 12px; font-size: 12px; color: #3b434b;
|
|
118
|
+
border-top: 1px solid #edf0f2; border-bottom: 1px solid #edf0f2; }
|
|
119
|
+
.slice-workers select { flex: 1; font-size: 12px; padding: 2px 4px; }
|
|
120
|
+
.kernel-badge { font-size: 10px; font-weight: 700; padding: 1px 6px; border-radius: 4px; letter-spacing: .04em; text-transform: uppercase; }
|
|
121
|
+
.kernel-badge.mt { background: #e2f5e8; color: #167a3a; }
|
|
122
|
+
.kernel-badge.st { background: #fbeaea; color: #a33b37; }
|
|
123
|
+
/* One entry per plate while an all-plates run is on — same colours as the plate tabs. */
|
|
124
|
+
.slice-plates { flex: 0 0 100%; display: flex; flex-wrap: wrap; gap: 4px 8px; margin: -2px 2px 0; font-size: 11px;
|
|
125
|
+
color: #5a646d; font-variant-numeric: tabular-nums; }
|
|
126
|
+
.slice-plate.busy { color: #167a3a; font-weight: 600; }
|
|
127
|
+
.slice-plate.done { color: #167a3a; }
|
|
128
|
+
.slice-plate.failed { color: #a33b37; }
|
|
92
129
|
|
|
93
130
|
/* Floating painting panel */
|
|
94
131
|
.brush-panel { position: absolute; top: 58px; left: 14px; width: 214px; background: rgba(22,27,33,.95);
|
|
@@ -106,6 +143,10 @@
|
|
|
106
143
|
.bp-radius { display: block; font-size: 12px; color: #aebcc6; margin-top: 8px; }
|
|
107
144
|
.bp-radius input { width: 100%; }
|
|
108
145
|
.bp-counts { margin-top: 6px; font-size: 11px; }
|
|
146
|
+
/* "On overhangs only" — a checkbox row in a panel whose other rows are buttons, so it borrows the label styling
|
|
147
|
+
of .bp-radius and only adds the inline layout a checkbox needs. */
|
|
148
|
+
.bp-check { display: flex; align-items: center; gap: 6px; font-size: 12px; color: #aebcc6; margin-top: 8px; cursor: pointer; }
|
|
149
|
+
.bp-check input { margin: 0; }
|
|
109
150
|
/* Material brush: the chip IS the filament colour, so its background is inline and only the framing is here.
|
|
110
151
|
The active ring is drawn outside the box (outline, not border) — a border would resize the chip on selection. */
|
|
111
152
|
.bp-chip { min-width: 30px; font-weight: 700; border-color: rgba(0,0,0,.35) !important; }
|
|
@@ -347,3 +388,7 @@
|
|
|
347
388
|
pointer, keyboard and focus — this only has to make that legible, or the card reads as broken rather than locked. */
|
|
348
389
|
.vp-readonly { opacity: .62; cursor: default; }
|
|
349
390
|
.vp-readonly * { cursor: default !important; }
|
|
391
|
+
|
|
392
|
+
/* The scope toggle's ↺ — drops the plate's whole override (ScopeToggle onReset). */
|
|
393
|
+
.scope-toggle .scope-reset { margin-left: 4px; padding: 0 6px; font-size: 12px; line-height: 18px; border: 1px solid #c9d3de; border-radius: 4px; background: transparent; cursor: pointer; }
|
|
394
|
+
.scope-toggle .scope-reset:hover { background: #eef2f6; }
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import { strToU8 as R, zipSync as T } from "three/examples/jsm/libs/fflate.module.js";
|
|
2
|
-
let F = !0;
|
|
3
|
-
function Z(e) {
|
|
4
|
-
F = !!e;
|
|
5
|
-
}
|
|
6
|
-
const C = {
|
|
7
|
-
info: (...e) => {
|
|
8
|
-
F && console.info(...e);
|
|
9
|
-
},
|
|
10
|
-
warn: (...e) => {
|
|
11
|
-
F && console.warn(...e);
|
|
12
|
-
},
|
|
13
|
-
error: (...e) => {
|
|
14
|
-
F && console.error(...e);
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
function O(e) {
|
|
18
|
-
const t = Number(e.display_width) > 0 ? Number(e.display_width) : 120.96, u = Number(e.display_height) > 0 ? Number(e.display_height) : 68.04, o = Number(e.display_pixels_x) > 0 ? Math.round(Number(e.display_pixels_x)) : 2560, i = Number(e.display_pixels_y) > 0 ? Math.round(Number(e.display_pixels_y)) : 1440, s = e.display_mirror_x !== !1, r = e.display_mirror_y === !0, n = (e.display_orientation ?? "portrait") !== "landscape", a = o / t, l = i / u, f = (p) => (s ? t / 2 - p : p + t / 2) * a, c = (p) => (r ? u / 2 - p : p + u / 2) * l;
|
|
19
|
-
return n ? {
|
|
20
|
-
px: i,
|
|
21
|
-
py: o,
|
|
22
|
-
mirrorX: s,
|
|
23
|
-
portrait: n,
|
|
24
|
-
// canvas columns run along the display's y axis, rows along the (mirrored) x axis
|
|
25
|
-
map: (p, y) => [c(y), f(p)]
|
|
26
|
-
} : {
|
|
27
|
-
px: o,
|
|
28
|
-
py: i,
|
|
29
|
-
mirrorX: s,
|
|
30
|
-
portrait: n,
|
|
31
|
-
map: (p, y) => [f(p), c(y)]
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function k(e, t, u) {
|
|
35
|
-
const o = t.length / 8;
|
|
36
|
-
if (!o) return 0;
|
|
37
|
-
let i = 0;
|
|
38
|
-
e.beginPath();
|
|
39
|
-
let s = NaN, r = NaN;
|
|
40
|
-
for (let n = 0; n < o; n++) {
|
|
41
|
-
const a = t[n * 8], l = t[n * 8 + 1], f = t[n * 8 + 4], c = t[n * 8 + 5];
|
|
42
|
-
(a !== s || l !== r) && (e.moveTo(...u.map(a, l)), i++), e.lineTo(...u.map(f, c)), s = f, r = c;
|
|
43
|
-
}
|
|
44
|
-
return e.fill("evenodd"), i;
|
|
45
|
-
}
|
|
46
|
-
const V = (e) => String(e ?? "");
|
|
47
|
-
function X({ params: e, stats: t, jobName: u, timestamp: o }) {
|
|
48
|
-
const i = String(e.material_print_speed ?? "fast"), s = {
|
|
49
|
-
action: "print",
|
|
50
|
-
jobDir: u,
|
|
51
|
-
expTime: e.exposure_time,
|
|
52
|
-
expTimeFirst: e.initial_exposure_time,
|
|
53
|
-
expUserProfile: i === "slow" ? 1 : i === "fast" ? 0 : 2,
|
|
54
|
-
fileCreationTimestamp: o ?? "",
|
|
55
|
-
hollow: e.hollowing_enable ? 1 : 0,
|
|
56
|
-
layerHeight: e.layer_height,
|
|
57
|
-
materialName: e.sla_material_settings_id ?? "",
|
|
58
|
-
numFade: e.faded_layers,
|
|
59
|
-
numFast: t.layers,
|
|
60
|
-
numSlow: 0,
|
|
61
|
-
printProfile: e.sla_print_settings_id ?? "",
|
|
62
|
-
printTime: Number(t.time_estimate ?? 0).toFixed(6),
|
|
63
|
-
printerModel: e.printer_model ?? "",
|
|
64
|
-
printerProfile: e.printer_settings_id ?? "",
|
|
65
|
-
printerVariant: e.printer_variant ?? "",
|
|
66
|
-
prusaSlicerVersion: "three-slicer",
|
|
67
|
-
usedMaterial: Number(t.resin_ml ?? 0).toFixed(6)
|
|
68
|
-
};
|
|
69
|
-
return Object.keys(s).sort().map((r) => `${r} = ${V(s[r])}`).join(`
|
|
70
|
-
`) + `
|
|
71
|
-
`;
|
|
72
|
-
}
|
|
73
|
-
const L = (e, t) => `${e}${String(t).padStart(5, "0")}.png`, Y = "Metadata/threeslicer_roles.bin", D = "Metadata/threeslicer_scene.bin";
|
|
74
|
-
function j({ modelSTL: e, supportMesh: t, padMesh: u, lift: o = 0 }) {
|
|
75
|
-
const i = e instanceof Uint8Array ? e : new Uint8Array(e ?? 0), s = t instanceof Float32Array ? t : new Float32Array(t ?? 0), r = u instanceof Float32Array ? u : new Float32Array(u ?? 0), n = new Uint8Array(12 + i.length + 4 + s.length * 4 + 4 + r.length * 4), a = new DataView(n.buffer);
|
|
76
|
-
n.set([84, 83, 83, 49], 0), a.setFloat32(4, o, !0);
|
|
77
|
-
let l = 8;
|
|
78
|
-
a.setUint32(l, i.length, !0), l += 4, n.set(i, l), l += i.length;
|
|
79
|
-
for (const f of [s, r]) {
|
|
80
|
-
a.setUint32(l, f.length, !0), l += 4;
|
|
81
|
-
for (let c = 0; c < f.length; c++)
|
|
82
|
-
a.setFloat32(l, f[c], !0), l += 4;
|
|
83
|
-
}
|
|
84
|
-
return n;
|
|
85
|
-
}
|
|
86
|
-
function z(e) {
|
|
87
|
-
const t = e.map(({ paths: r }) => {
|
|
88
|
-
const n = [];
|
|
89
|
-
for (let a = 0; a + 7 < r.length; a += 8) {
|
|
90
|
-
const l = r[a + 3] & 15;
|
|
91
|
-
if (l === 5 || l === 6) for (let f = 0; f < 8; f++) n.push(r[a + f]);
|
|
92
|
-
}
|
|
93
|
-
return n;
|
|
94
|
-
}), u = 8 + t.reduce((r, n) => r + 4 + n.length * 4, 0), o = new Uint8Array(u), i = new DataView(o.buffer);
|
|
95
|
-
o.set([84, 83, 82, 49], 0), i.setUint32(4, t.length, !0);
|
|
96
|
-
let s = 8;
|
|
97
|
-
for (const r of t) {
|
|
98
|
-
i.setUint32(s, r.length, !0), s += 4;
|
|
99
|
-
for (const n of r)
|
|
100
|
-
i.setFloat32(s, n, !0), s += 4;
|
|
101
|
-
}
|
|
102
|
-
return o;
|
|
103
|
-
}
|
|
104
|
-
function H({ layers: e, params: t, makeWorker: u, workerCount: o, onProgress: i }) {
|
|
105
|
-
return new Promise((s, r) => {
|
|
106
|
-
const n = new Array(e.length), a = new Array(o).fill(0);
|
|
107
|
-
let l = 0, f = !1;
|
|
108
|
-
const c = [], p = (y) => {
|
|
109
|
-
f = !0, c.forEach((_) => _.terminate()), r(y);
|
|
110
|
-
};
|
|
111
|
-
for (let y = 0; y < o; y++) {
|
|
112
|
-
const _ = [], m = [];
|
|
113
|
-
for (let g = y; g < e.length; g += o)
|
|
114
|
-
_.push(g), m.push(e[g].paths);
|
|
115
|
-
const w = u();
|
|
116
|
-
c.push(w), w.onerror = (g) => p(new Error("SL1 encode worker: " + ((g == null ? void 0 : g.message) || "failed"))), w.onmessage = ({ data: g }) => {
|
|
117
|
-
if (!f) {
|
|
118
|
-
if (g.progress != null) {
|
|
119
|
-
a[y] = g.progress, i == null || i(a.reduce((b, $) => b + $, 0), e.length);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
g.indices.forEach((b, $) => {
|
|
123
|
-
n[b] = g.pngs[$];
|
|
124
|
-
}), w.terminate(), ++l === o && s(n);
|
|
125
|
-
}
|
|
126
|
-
}, w.postMessage({ indices: _, paths: m, params: t });
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
async function q({ layers: e, params: t, stats: u, jobName: o = "plate", timestamp: i, makeCanvas: s, onProgress: r, scene: n = null, makeWorker: a = null, workerCount: l = 0 }) {
|
|
131
|
-
const f = s ?? (typeof OffscreenCanvas < "u" ? (h, d) => new OffscreenCanvas(h, d) : null), c = O(t), p = {}, y = a && typeof Worker < "u" && e.length > 1 ? {
|
|
132
|
-
makeWorker: a,
|
|
133
|
-
workerCount: Math.max(1, Math.min(l > 0 ? l : 4, e.length))
|
|
134
|
-
} : null;
|
|
135
|
-
if (!y && !f) throw new Error("SL1 export needs a canvas (OffscreenCanvas or an injected factory)");
|
|
136
|
-
const _ = () => performance.now(), m = { canvas: 0, clear: 0, draw: 0, encode: 0, read: 0 }, w = (h, d) => {
|
|
137
|
-
const S = _();
|
|
138
|
-
return m[h] += S - d, S;
|
|
139
|
-
};
|
|
140
|
-
let g = 0, b = 0;
|
|
141
|
-
const $ = async (h) => {
|
|
142
|
-
let d = _();
|
|
143
|
-
const S = f(c.px, c.py), v = S.getContext("2d");
|
|
144
|
-
d = w("canvas", d), v.fillStyle = "#000", v.fillRect(0, 0, c.px, c.py), d = w("clear", d), v.fillStyle = "#fff", b += k(v, e[h].paths, c), d = w("draw", d);
|
|
145
|
-
const B = await S.convertToBlob({ type: "image/png" });
|
|
146
|
-
d = w("encode", d);
|
|
147
|
-
const U = new Uint8Array(await B.arrayBuffer());
|
|
148
|
-
return w("read", d), g += U.length, U;
|
|
149
|
-
}, E = _();
|
|
150
|
-
if (y) {
|
|
151
|
-
const h = await H({ layers: e, params: t, onProgress: r, ...y });
|
|
152
|
-
for (let d = 0; d < e.length; d++)
|
|
153
|
-
p[L(o, d)] = [h[d], { level: 0 }], g += h[d].length;
|
|
154
|
-
} else
|
|
155
|
-
for (let h = 0; h < e.length; h++)
|
|
156
|
-
p[L(o, h)] = [await $(h), { level: 0 }], h & 31 || r == null || r(h, e.length);
|
|
157
|
-
const N = _();
|
|
158
|
-
p["config.ini"] = R(X({ params: t, stats: u, jobName: o, timestamp: i })), p[Y] = [z(e), { level: 6 }], n && (p[D] = [j(n), { level: 6 }]);
|
|
159
|
-
const A = _(), M = T(p), x = (h) => h.toFixed(0);
|
|
160
|
-
return C.info(`[vp-prof] sl1 build: ${e.length} layers ${c.px}x${c.py},` + (y ? ` raster ${x(N - E)}ms (${y.workerCount} workers),` : ` ${b} loops, raster ${x(N - E)}ms (canvas ${x(m.canvas)} + clear ${x(m.clear)} + draw ${x(m.draw)} + encode ${x(m.encode)} + read ${x(m.read)}),`) + ` sidecar ${x(A - N)}ms, zip ${x(_() - A)}ms -> ${(M.byteLength / 1e6).toFixed(1)}MB (png ${(g / 1e6).toFixed(1)}MB)`), M;
|
|
161
|
-
}
|
|
162
|
-
export {
|
|
163
|
-
D as S,
|
|
164
|
-
Y as a,
|
|
165
|
-
Z as b,
|
|
166
|
-
k as d,
|
|
167
|
-
C as l,
|
|
168
|
-
q as m,
|
|
169
|
-
O as s
|
|
170
|
-
};
|