ldr 0.26.0 → 0.27.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/README.md CHANGED
@@ -144,10 +144,12 @@ MPD-embedded parts, such as Studio/OMR unofficial parts or stickers, become part
144
144
  | `lodEdgeMinPx` | `0.15` | LOD: draw only edge segments at least this many pixels long on screen. `0` = every segment. |
145
145
  | `lodUnder` | `true` | LOD: skip undersides that can't be seen (camera behind every bottom face of a cluster's parts, or the body drawn as its closed bounding box). Lossless in the fidelity checks. |
146
146
 
147
- `LdrObject`: `object`, `stats` (`instances`, `drawn`, `missing[]`, `studsHidden/Total`, `undersHidden/Total`, `buildMs`, `condBatches`, `texBatches`, `textures`, `glossmaps`, `clusters`), `stepCount`, `stepViews`, `texturesReady`, `setStep(n | null)`, `setEdges(on)`, `setConditionalLines(on)`, `setCulling(studs, undersides)`, `setSide(side)`, `setLod(on)`, `getBox(target?)`, `dispose()`.
147
+ `LdrObject`: `object`, `stats` (`instances`, `drawn`, `missing[]`, `studsHidden/Total`, `undersHidden/Total`, `buildMs`, `condBatches`, `texBatches`, `textures`, `glossmaps`, `clusters`), `stepCount`, `stepViews`, `texturesReady`, `setStep(n | null)`, `setEdges(on)`, `setConditionalLines(on)`, `setCulling(studs, undersides)`, `setSide(side)`, `setLod(on)`, `setGhost(on, { opacity, color, whiten }?)`, `getBox(target?)`, `dispose()`.
148
148
 
149
149
  `setStep` doesn't rebuild anything: it compacts instance buffers, and culling is step-aware (a stud covered only by a later step's part stays visible). `stats` reflect the shown step.
150
150
 
151
+ `setGhost(true)` draws the steps still to come as a faint, whitened, depth-written ghost (like the LEGO Builder app). It is built once on first use, without edges, with the steps reversed so `setStep` stays a buffer compaction for it too. It honours the booklet isolate mask, and `getBox` ignores it. Off by default. Cost: about the same as drawing the whole model (Titanic, 9.7k bricks: 1.6 ms off, 2.5 ms on, 2.8 ms full model).
152
+
151
153
  **Building instructions.** `parseModel(text, name, { callouts: true })` (or `loadModel(url, { callouts: true })`) sequences a
152
154
  submodel placed N times in one step like a booklet: the first copy is built step by step (its instances get `mult = N`, the "xN"),
153
155
  the other copies appear finished at the end of that step. `planStepViews(instances, pack.header.parts, stepOf, stepCount)` plans a
package/dist/cli.js CHANGED
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // ../../../../../../../tmp/ldr-build-tYthc8/src/cli.ts
3
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/cli.ts
4
4
  import fs4 from "node:fs";
5
5
  import zlib from "node:zlib";
6
6
 
7
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/build-pack.ts
7
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/build-pack.ts
8
8
  import fs3 from "node:fs";
9
9
  import path3 from "node:path";
10
10
 
11
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/resolver.ts
11
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/resolver.ts
12
12
  import fs from "node:fs";
13
13
  import path from "node:path";
14
14
 
15
- // ../../../../../../../tmp/ldr-build-tYthc8/src/spec.ts
15
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/spec.ts
16
16
  var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
17
17
  var COLOUR_ID_RE = /^[A-Za-z][A-Za-z0-9_]*$/;
18
18
  var namedCodes = new Map;
@@ -723,7 +723,7 @@ function fileStepViews(f) {
723
723
  return out;
724
724
  }
725
725
 
726
- // ../../../../../../../tmp/ldr-build-tYthc8/src/model.ts
726
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/model.ts
727
727
  var CALLOUT_END = 999999;
728
728
  var stepKey = (steps) => steps.map((x) => String(x).padStart(6, "0")).join(".") + "~";
729
729
  function flatten(doc, opts = {}) {
@@ -1106,7 +1106,7 @@ function blendedColourHex(code) {
1106
1106
  return "#" + [0, 1, 2].map((k) => (a[k] + b[k] >> 1).toString(16).padStart(2, "0")).join("").toUpperCase();
1107
1107
  }
1108
1108
 
1109
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/resolver.ts
1109
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/resolver.ts
1110
1110
  var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
1111
1111
  var UNDER_STUD_RE = /^(stud3|stud3a|stud4.*|stud12|stud16.*|stud18a)\.dat$/i;
1112
1112
  var norm2 = (ref) => ref.trim().replace(/\\/g, "/").toLowerCase();
@@ -1376,11 +1376,11 @@ function collectDeps(lib, refs) {
1376
1376
  return out;
1377
1377
  }
1378
1378
 
1379
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/compile.ts
1379
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/compile.ts
1380
1380
  import fs2 from "node:fs";
1381
1381
  import path2 from "node:path";
1382
1382
 
1383
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/lod.ts
1383
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/lod.ts
1384
1384
  import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
1385
1385
  await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
1386
1386
  function reorderMesh(P, N, C, I) {
@@ -1572,7 +1572,7 @@ function lodChain(P, C, I) {
1572
1572
  return out;
1573
1573
  }
1574
1574
 
1575
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/compile.ts
1575
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/compile.ts
1576
1576
  function loadColors(root) {
1577
1577
  const map = new Map;
1578
1578
  for (const l of fs2.readFileSync(path2.join(root, "LDConfig.ldr"), "latin1").split(/\r?\n/)) {
@@ -2209,7 +2209,7 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
2209
2209
  return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
2210
2210
  }
2211
2211
 
2212
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/build-pack.ts
2212
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/build-pack.ts
2213
2213
  function buildPack(o) {
2214
2214
  const lib = new Library(o.ldrawRoot);
2215
2215
  const refs = new Map;
@@ -2277,7 +2277,7 @@ function buildPack(o) {
2277
2277
  return { data: encodePack(parts, kinds, comp.opts.weld, extra, { texture, lod: o.lod !== false, reorder: !!o.reorder }), parts: parts.size, studKinds: kinds.size, missing: [...missing], ...warnings.length ? { warnings } : {} };
2278
2278
  }
2279
2279
 
2280
- // ../../../../../../../tmp/ldr-build-tYthc8/src/cli.ts
2280
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/cli.ts
2281
2281
  var HELP = `ldr pack — build a parts pack for the ldr three.js renderer
2282
2282
 
2283
2283
  Usage:
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export { loadPack, decodePack, buildLdrScene, buildLdrSceneAsync, makeMaterial,
8
8
  export { precomputeCull, sceneInstances } from "./cull.js";
9
9
  export type { Pack, LdrParams, Inst, CullResult, BuildLdrSceneAsyncOptions, GlossMap } from "./render.js";
10
10
  export { createLdrObject, createLdrObjectAsync } from "./scene.js";
11
- export type { LdrObject, LdrObjectOptions, LdrStats, ColorSource } from "./scene.js";
11
+ export type { LdrObject, LdrObjectOptions, LdrStats, ColorSource, GhostOptions } from "./scene.js";
12
12
  export { decompressPack, decodeModelText, modelFileName } from "./pack-io.js";
13
13
  export { loadModel, loadParts, loadPartsIndex, mergePacks, prepareModel, bodyTriangles, estimateBudgetFromIndex, BudgetError, DEFAULT_PARTS_CDN } from "./cdn.js";
14
14
  export type { LoadModelOptions, LoadedModel, LoadPartsOptions, PartsCdnIndex, PrepareOptions, PreparedModel } from "./cdn.js";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // ../../../../../../../tmp/ldr-build-tYthc8/src/spec.ts
1
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/spec.ts
2
2
  var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
3
3
  var COLOUR_ID_RE = /^[A-Za-z][A-Za-z0-9_]*$/;
4
4
  var namedCodes = new Map;
@@ -707,7 +707,7 @@ function fileStepViews(f) {
707
707
  viewMemo.set(f, out);
708
708
  return out;
709
709
  }
710
- // ../../../../../../../tmp/ldr-build-tYthc8/src/model.ts
710
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/model.ts
711
711
  var CALLOUT_END = 999999;
712
712
  var stepKey = (steps) => steps.map((x) => String(x).padStart(6, "0")).join(".") + "~";
713
713
  function flatten(doc, opts = {}) {
@@ -1089,7 +1089,7 @@ function blendedColourHex(code) {
1089
1089
  const a = LDRAW_EXE_16[code - 256 >> 4], b = LDRAW_EXE_16[code - 256 & 15];
1090
1090
  return "#" + [0, 1, 2].map((k) => (a[k] + b[k] >> 1).toString(16).padStart(2, "0")).join("").toUpperCase();
1091
1091
  }
1092
- // ../../../../../../../tmp/ldr-build-tYthc8/src/instructions.ts
1092
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/instructions.ts
1093
1093
  var MIN_VIS = 0.5;
1094
1094
  var REORIENT = 0.35;
1095
1095
  var deg = Math.PI / 180;
@@ -1457,10 +1457,10 @@ function planStepViews(insts, parts, stepOf, nSteps, o = {}) {
1457
1457
  }
1458
1458
  };
1459
1459
  }
1460
- // ../../../../../../../tmp/ldr-build-tYthc8/src/render.ts
1460
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/render.ts
1461
1461
  import * as THREE from "three";
1462
1462
 
1463
- // ../../../../../../../tmp/ldr-build-tYthc8/src/pack-io.ts
1463
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/pack-io.ts
1464
1464
  import { decompress } from "fzstd";
1465
1465
  async function decompressPack(data) {
1466
1466
  const u = data instanceof Uint8Array ? data : new Uint8Array(data);
@@ -1483,7 +1483,7 @@ function decodePack(buf) {
1483
1483
  return { header, arr, bytes: buf.byteLength, buffer: buf };
1484
1484
  }
1485
1485
 
1486
- // ../../../../../../../tmp/ldr-build-tYthc8/src/cull.ts
1486
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/cull.ts
1487
1487
  var upright = (m, o = 0) => Math.abs(m[o + 7] - 1) < 0.001 && Math.abs(m[o + 4]) < 0.001 && Math.abs(m[o + 10]) < 0.001;
1488
1488
  var prepCache = new WeakMap;
1489
1489
  function prepPart(H, part) {
@@ -1818,7 +1818,7 @@ function precomputeCull(instances, H, useTex = true) {
1818
1818
  return cullCore(s.all, H, s.nSteps > 1 ? s.stepOf : undefined);
1819
1819
  }
1820
1820
 
1821
- // ../../../../../../../tmp/ldr-build-tYthc8/src/render.ts
1821
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/render.ts
1822
1822
  async function loadPack(url) {
1823
1823
  const res = await fetch(url);
1824
1824
  if (!res.ok)
@@ -1867,6 +1867,10 @@ function flatNormals(pos, idx) {
1867
1867
  return n;
1868
1868
  }
1869
1869
  var geomCache = new WeakMap;
1870
+ var DECODE_CHUNK_VERTS = 65536;
1871
+ function geomCached(b, arr) {
1872
+ return !b || !!geomCache.get(arr)?.has(b);
1873
+ }
1870
1874
  function geom(b, arr) {
1871
1875
  if (!b)
1872
1876
  return null;
@@ -2518,6 +2522,12 @@ class LdrLodRoot extends THREE.LOD {
2518
2522
  }
2519
2523
  }
2520
2524
  }
2525
+ function fillBucketIds(bIds, fill, studBucket, j0, j1) {
2526
+ for (let j = j0;j < j1; j++) {
2527
+ const b = studBucket[j];
2528
+ bIds[b][fill[b]++] = j;
2529
+ }
2530
+ }
2521
2531
  function* buildStudMeshesGen(insts, H, cull, arr, LOD, color, matOf, steps, colorIndex) {
2522
2532
  const bKind = [], bMat = [];
2523
2533
  const bAll = [];
@@ -2595,14 +2605,15 @@ function* buildStudMeshesGen(insts, H, cull, arr, LOD, color, matOf, steps, colo
2595
2605
  sz[j] = a[2] + a[9] * b0 + a[10] * b1 + a[11] * b2;
2596
2606
  }
2597
2607
  }
2608
+ yield;
2598
2609
  const bIds = bAll.map((n) => new Int32Array(n));
2599
- {
2600
- const f = bAll.map(() => 0);
2601
- for (let j = 0;j < cull.nStuds; j++) {
2602
- const b = studBucket[j];
2603
- bIds[b][f[b]++] = j;
2604
- }
2610
+ const bFill = new Int32Array(bAll.length);
2611
+ for (let j0 = 0;j0 < cull.nStuds; j0 += 262144) {
2612
+ if (j0)
2613
+ yield;
2614
+ fillBucketIds(bIds, bFill, studBucket, j0, Math.min(cull.nStuds, j0 + 262144));
2605
2615
  }
2616
+ yield;
2606
2617
  const studCl = new Int32Array(cull.nStuds), studSlot = new Int32Array(cull.nStuds);
2607
2618
  const sMesh = [];
2608
2619
  const allocClusters = (b, kind, g, ids, cs, c0, c1) => {
@@ -2981,7 +2992,10 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
2981
2992
  const bodyB = textured ? p.tbody : p.body;
2982
2993
  const body = geom(bodyB, arr);
2983
2994
  const groups = gridClusters(idsAll.length, (i) => insts[idsAll[i]].m[0], (i) => insts[idsAll[i]].m[2], textured ? Infinity : kFor(tris(p.body) + tris(p.under)));
2995
+ let _coopH = 0;
2984
2996
  for (const g of groups) {
2997
+ if (_coopH++)
2998
+ yield root;
2985
2999
  const ids = Array.from(g, (i) => idsAll[i]);
2986
3000
  let bodyIm = null;
2987
3001
  const lv0 = [];
@@ -3102,6 +3116,19 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3102
3116
  }
3103
3117
  if (maxV === 0)
3104
3118
  continue;
3119
+ let decV = 0;
3120
+ for (const p of partSet.values())
3121
+ if (p.body)
3122
+ for (const b of LOD && p.body.lod ? [p.body, ...p.body.lod] : [p.body]) {
3123
+ if (geomCached(b, arr))
3124
+ continue;
3125
+ geom(b, arr);
3126
+ decV += geomVerts(b);
3127
+ if (decV >= DECODE_CHUNK_VERTS) {
3128
+ decV = 0;
3129
+ yield root;
3130
+ }
3131
+ }
3105
3132
  const bm = new THREE.BatchedMesh(members.length, Math.max(1, maxV), Math.max(1, maxI), mat);
3106
3133
  bm.perObjectFrustumCulled = true;
3107
3134
  bm.sortObjects = false;
@@ -3155,6 +3182,7 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3155
3182
  };
3156
3183
  cl.lv.push({ objs: [bm], err: 0 });
3157
3184
  if (EDGES) {
3185
+ yield root;
3158
3186
  const byPartIds = new Map;
3159
3187
  for (const m of live) {
3160
3188
  const a = byPartIds.get(m.part) || byPartIds.set(m.part, []).get(m.part);
@@ -3203,6 +3231,19 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3203
3231
  }
3204
3232
  if (!uV)
3205
3233
  continue;
3234
+ let uDecV = 0;
3235
+ for (const p of uPartSet.values())
3236
+ if (p.under)
3237
+ for (const b of LOD && p.under.lod ? [p.under, ...p.under.lod] : [p.under]) {
3238
+ if (geomCached(b, arr))
3239
+ continue;
3240
+ geom(b, arr);
3241
+ uDecV += geomVerts(b);
3242
+ if (uDecV >= DECODE_CHUNK_VERTS) {
3243
+ uDecV = 0;
3244
+ yield root;
3245
+ }
3246
+ }
3206
3247
  const ubm = new THREE.BatchedMesh(umembers.length, Math.max(1, uV), Math.max(1, uI), mat);
3207
3248
  ubm.perObjectFrustumCulled = true;
3208
3249
  ubm.sortObjects = false;
@@ -3573,18 +3614,23 @@ function yieldToMain() {
3573
3614
  });
3574
3615
  }
3575
3616
  async function buildLdrSceneAsync(insts, pack, P, color, mark, opts = {}) {
3617
+ const { value, longestSliceMs, yields } = await runSliced(buildLdrSceneGen(insts, pack, P, color, mark), opts);
3618
+ value.stats = { ...value.stats, longestSliceMs: +longestSliceMs.toFixed(2), buildYields: yields };
3619
+ return value;
3620
+ }
3621
+ async function runSliced(g, opts = {}) {
3576
3622
  const sliceMs = opts.sliceMs ?? 8;
3577
3623
  const postPaint = opts.postPaintSliceMs ?? Math.max(sliceMs, 24);
3578
3624
  let painting = typeof opts.onSlice === "function";
3579
3625
  let effective = painting ? sliceMs : postPaint;
3580
- const g = buildLdrSceneGen(insts, pack, P, color, mark);
3581
- let r = g.next();
3582
3626
  let sliceStart = performance.now();
3627
+ let r = g.next();
3583
3628
  let longestSliceMs = 0;
3584
3629
  let yields = 0;
3630
+ let maxStep = 0;
3585
3631
  while (!r.done) {
3586
3632
  const now = performance.now();
3587
- if (now - sliceStart >= effective) {
3633
+ if (now - sliceStart + Math.min(Math.max(maxStep, effective / 3), effective / 2) >= effective) {
3588
3634
  longestSliceMs = Math.max(longestSliceMs, now - sliceStart);
3589
3635
  yields++;
3590
3636
  if (painting && opts.onSlice) {
@@ -3597,12 +3643,12 @@ async function buildLdrSceneAsync(insts, pack, P, color, mark, opts = {}) {
3597
3643
  await yieldToMain();
3598
3644
  sliceStart = performance.now();
3599
3645
  }
3646
+ const t = performance.now();
3600
3647
  r = g.next();
3648
+ maxStep = Math.max(maxStep, performance.now() - t);
3601
3649
  }
3602
3650
  longestSliceMs = Math.max(longestSliceMs, performance.now() - sliceStart);
3603
- const value = r.value;
3604
- value.stats = { ...value.stats, longestSliceMs: +longestSliceMs.toFixed(2), buildYields: yields };
3605
- return value;
3651
+ return { value: r.value, longestSliceMs, yields };
3606
3652
  }
3607
3653
  async function warmPackGeometry(pack, stop = () => false, sliceMs = 8) {
3608
3654
  const { header: H, arr } = pack;
@@ -3626,8 +3672,27 @@ async function warmPackGeometry(pack, stop = () => false, sliceMs = 8) {
3626
3672
  await new Promise((r) => setTimeout(r, 0));
3627
3673
  }
3628
3674
  }
3629
- // ../../../../../../../tmp/ldr-build-tYthc8/src/scene.ts
3675
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/scene.ts
3630
3676
  import * as THREE2 from "three";
3677
+ function ghostMaterial(side, g) {
3678
+ const m = new THREE2.MeshStandardMaterial({ color: 16777215, roughness: 0.85, metalness: 0, side, transparent: false, depthWrite: true, opacity: g.opacity });
3679
+ m.blending = THREE2.CustomBlending;
3680
+ m.blendSrc = THREE2.SrcAlphaFactor;
3681
+ m.blendDst = THREE2.OneMinusSrcAlphaFactor;
3682
+ m.blendSrcAlpha = THREE2.OneFactor;
3683
+ m.blendDstAlpha = THREE2.OneMinusSrcAlphaFactor;
3684
+ const tint = new THREE2.Color(g.color);
3685
+ const u = { ldrGhostTint: { value: tint }, ldrGhostMix: { value: g.whiten } };
3686
+ m.onBeforeCompile = (sh) => {
3687
+ Object.assign(sh.uniforms, u);
3688
+ sh.fragmentShader = `uniform vec3 ldrGhostTint; uniform float ldrGhostMix;
3689
+ ` + sh.fragmentShader.replace("#include <color_fragment>", `#include <color_fragment>
3690
+ diffuseColor.rgb = mix(diffuseColor.rgb, ldrGhostTint, ldrGhostMix);`);
3691
+ };
3692
+ m.customProgramCacheKey = () => "ldrGhost";
3693
+ m.userData.ldrGhost = u;
3694
+ return m;
3695
+ }
3631
3696
  function colorFn(src, pack, fallback) {
3632
3697
  const table = new Map;
3633
3698
  const put = (k, v) => table.set(String(k), new THREE2.Color(typeof v === "string" ? v : v.hex));
@@ -3741,6 +3806,75 @@ function createLdrObjectInner(instances, pack, options, progressive) {
3741
3806
  }
3742
3807
  cur = null;
3743
3808
  };
3809
+ let ghostOn = false, ghost = null, ghostBuild = null, ghostGen = 0;
3810
+ let shownStep = null, shownMask = null;
3811
+ const ghostOpts = { opacity: 0.2, color: 16777215, whiten: 0.75 };
3812
+ const ghostMats = new Map;
3813
+ const syncGhost = () => {
3814
+ if (!ghost)
3815
+ return;
3816
+ const show = ghostOn && shownStep != null && shownStep < uniq.length - 1;
3817
+ ghost.root.visible = show;
3818
+ if (show)
3819
+ ghost.setStep(uniq.length - 2 - shownStep, shownMask);
3820
+ };
3821
+ const disposeGhost = () => {
3822
+ ghostGen++;
3823
+ ghostBuild = null;
3824
+ if (!ghost)
3825
+ return;
3826
+ object.remove(ghost.root);
3827
+ ghost.root.traverse((x) => {
3828
+ if (x.isInstancedMesh)
3829
+ x.dispose();
3830
+ else if (x.isBatchedMesh)
3831
+ x.dispose();
3832
+ });
3833
+ for (const m of ghostMats.values())
3834
+ m.dispose();
3835
+ ghostMats.clear();
3836
+ ghost = null;
3837
+ };
3838
+ const buildGhost = () => ghostBuild ??= (async () => {
3839
+ const my = ghostGen;
3840
+ const n = uniq.length;
3841
+ const rev = new Int32Array(stepOf.length);
3842
+ for (let k = 0;k < rev.length; k++)
3843
+ rev[k] = n - 1 - stepOf[k];
3844
+ const so = { ...sceneOpts(), edges: false, cond: false, tex: false, steps: rev, cull: undefined };
3845
+ so.cull = cullCore(all, pack.header, rev);
3846
+ const g = await buildLdrSceneAsync(all, pack, so, color, () => {}, { postPaintSliceMs: 12 });
3847
+ if (my !== ghostGen) {
3848
+ g.root.traverse((x) => {
3849
+ if (x.isInstancedMesh || x.isBatchedMesh)
3850
+ x.dispose();
3851
+ });
3852
+ return;
3853
+ }
3854
+ const old = new Set;
3855
+ g.root.traverse((x) => {
3856
+ if (!x.isMesh)
3857
+ return;
3858
+ if (x.material)
3859
+ old.add(x.material);
3860
+ let m = ghostMats.get(x.material?.side ?? THREE2.FrontSide);
3861
+ if (!m)
3862
+ ghostMats.set(x.material?.side ?? THREE2.FrontSide, m = ghostMaterial(x.material?.side ?? THREE2.FrontSide, ghostOpts));
3863
+ x.material = m;
3864
+ x.castShadow = x.receiveShadow = false;
3865
+ x.renderOrder = 1;
3866
+ x.userData.ldrGhost = true;
3867
+ });
3868
+ for (const m of old)
3869
+ m.dispose();
3870
+ g.root.name = "ldr-ghost";
3871
+ if (!lodOn)
3872
+ g.setLod(false);
3873
+ g.setCull(cs, cu);
3874
+ ghost = g;
3875
+ object.add(g.root);
3876
+ syncGhost();
3877
+ })();
3744
3878
  const multiStep = uniq.length > 1;
3745
3879
  const drawnAt = (step, mask) => all.filter((i, k) => (step == null || stepOf[k] <= step) && (!mask || mask[k]) && pack.header.parts[i.part]).length;
3746
3880
  const sceneOpts = () => ({ localColours: localColours.size ? localColours : undefined, cullStuds: cs, cullUnder: cu, edges: o.edges, side, cond: o.conditionalLines, condStuds: o.conditionalStudLines !== false, tex: o.textures !== false, lod: o.lod !== false, lodPx: o.lodPx, lodEdgePx: o.lodEdgePx, lodEdgeMinPx: o.lodEdgeMinPx, lodUnder: o.lodUnder, steps: multiStep ? stepOf : undefined, cull: o.precomputedCull });
@@ -3773,7 +3907,12 @@ function createLdrObjectInner(instances, pack, options, progressive) {
3773
3907
  if (!multiStep)
3774
3908
  return;
3775
3909
  const t0 = performance.now();
3910
+ shownStep = step;
3911
+ shownMask = mask;
3776
3912
  Object.assign(stats, cur.setStep(step, mask), { drawn: drawnAt(step, mask), buildMs: performance.now() - t0 });
3913
+ if (ghostOn && step != null && !ghost)
3914
+ buildGhost();
3915
+ syncGhost();
3777
3916
  };
3778
3917
  const api = { texturesReady: Promise.resolve() };
3779
3918
  const finish = () => {
@@ -3802,10 +3941,31 @@ function createLdrObjectInner(instances, pack, options, progressive) {
3802
3941
  applyBuilt(buildLdrScene(all, pack, sceneOpts(), color, () => {}), t0);
3803
3942
  } else
3804
3943
  cur.setCull(a, b);
3944
+ ghost?.setCull(a, b);
3805
3945
  },
3806
3946
  setLod: (v) => {
3807
3947
  lodOn = v;
3808
3948
  cur.setLod(v);
3949
+ ghost?.setLod(v);
3950
+ },
3951
+ setGhost: (on, go = {}) => {
3952
+ ghostOn = on && multiStep;
3953
+ Object.assign(ghostOpts, Object.fromEntries(Object.entries(go).filter(([, v]) => v !== undefined)));
3954
+ for (const m of ghostMats.values()) {
3955
+ m.opacity = ghostOpts.opacity;
3956
+ const u = m.userData.ldrGhost;
3957
+ u.ldrGhostTint.value.set(ghostOpts.color);
3958
+ u.ldrGhostMix.value = ghostOpts.whiten;
3959
+ }
3960
+ if (!ghostOn) {
3961
+ syncGhost();
3962
+ return ghostBuild ?? Promise.resolve();
3963
+ }
3964
+ if (shownStep == null && !ghost)
3965
+ return Promise.resolve();
3966
+ const b = buildGhost();
3967
+ syncGhost();
3968
+ return b;
3809
3969
  },
3810
3970
  setSide: (s) => {
3811
3971
  side = s;
@@ -3819,7 +3979,7 @@ function createLdrObjectInner(instances, pack, options, progressive) {
3819
3979
  object.updateMatrixWorld(true);
3820
3980
  target.makeEmpty();
3821
3981
  object.traverse((x) => {
3822
- if (x.isInstancedMesh && x.count && !x.userData.ldrLod) {
3982
+ if (x.isInstancedMesh && x.count && !x.userData.ldrLod && !x.userData.ldrGhost) {
3823
3983
  x.computeBoundingBox();
3824
3984
  const b = x.boundingBox.clone().applyMatrix4(x.matrixWorld);
3825
3985
  target.union(b);
@@ -3827,7 +3987,10 @@ function createLdrObjectInner(instances, pack, options, progressive) {
3827
3987
  });
3828
3988
  return target;
3829
3989
  },
3830
- dispose: disposeCur
3990
+ dispose: () => {
3991
+ disposeGhost();
3992
+ disposeCur();
3993
+ }
3831
3994
  });
3832
3995
  };
3833
3996
  if (!progressive) {
@@ -3853,10 +4016,10 @@ function createLdrObjectInner(instances, pack, options, progressive) {
3853
4016
  return finish();
3854
4017
  })();
3855
4018
  }
3856
- // ../../../../../../../tmp/ldr-build-tYthc8/src/parts-cdn.ts
4019
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/parts-cdn.ts
3857
4020
  import { decompress as decompress2 } from "fzstd";
3858
4021
 
3859
- // ../../../../../../../tmp/ldr-build-tYthc8/src/embedded.ts
4022
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/embedded.ts
3860
4023
  function splitFiles(text, fallback) {
3861
4024
  const files = new Map;
3862
4025
  let cur = null, saw = false;
@@ -3928,7 +4091,7 @@ function embeddedKeys(text, names, fallback = "main.ldr") {
3928
4091
  return out;
3929
4092
  }
3930
4093
 
3931
- // ../../../../../../../tmp/ldr-build-tYthc8/src/parts-cdn.ts
4094
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/parts-cdn.ts
3932
4095
  var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
3933
4096
  var indexCache = new Map;
3934
4097
  var shardCache = new Map;
@@ -4160,10 +4323,10 @@ async function prepareModel(source, o = {}) {
4160
4323
  return { insts, pack, missing, requests, bytes, cull, timings: { fetchModel: t1 - t0, parse: t2 - t1, parts: t3 - t2, ...cull ? { cull: performance.now() - t3 } : {} } };
4161
4324
  }
4162
4325
 
4163
- // ../../../../../../../tmp/ldr-build-tYthc8/src/load-worker.gen.ts
4326
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/load-worker.gen.ts
4164
4327
  var load_worker_gen_default = 'var vt=ArrayBuffer,Z=Uint8Array,de=Uint16Array,Ct=Int16Array;var be=Int32Array,Le=function(e,t,n){if(Z.prototype.slice)return Z.prototype.slice.call(e,t,n);if(t==null||t<0)t=0;if(n==null||n>e.length)n=e.length;var r=new Z(n-t);return r.set(e.subarray(t,n)),r},ce=function(e,t,n,r){if(Z.prototype.fill)return Z.prototype.fill.call(e,t,n,r);if(n==null||n<0)n=0;if(r==null||r>e.length)r=e.length;for(;n<r;++n)e[n]=t;return e},Tt=function(e,t,n,r){if(Z.prototype.copyWithin)return Z.prototype.copyWithin.call(e,t,n,r);if(n==null||n<0)n=0;if(r==null||r>e.length)r=e.length;while(n<r)e[t++]=e[n++]};var Lt=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],J=function(e,t,n){var r=Error(t||Lt[e]);if(r.code=e,Error.captureStackTrace)Error.captureStackTrace(r,J);if(!n)throw r;return r},Ke=function(e,t,n){var r=0,s=0;for(;r<n;++r)s|=e[t++]<<(r<<3);return s},Et=function(e,t){return(e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24)>>>0},St=function(e,t){var n=e[0]|e[1]<<8|e[2]<<16;if(n==3126568&&e[3]==253){var r=e[4],s=r>>5&1,o=r>>2&1,i=r&3,a=r>>6;if(r&8)J(0);var u=6-s,c=i==3?4:i,f=Ke(e,u,c);u+=c;var l=a?1<<a:s,p=Ke(e,u,l)+(a==1&&256),d=p;if(!s){var w=1<<10+(e[5]>>3);d=w+(w>>3)*(e[5]&7)}if(d>2145386496)J(1);var y=new Z((t==1?p||d:t?0:d)+12);return y[0]=1,y[4]=4,y[8]=8,{b:u+l,y:0,l:0,d:f,w:t&&t!=1?t:y.subarray(12),e:d,o:new be(y.buffer,0,3),u:p,c:o,m:Math.min(131072,d)}}else if((n>>4|e[3]<<20)==25481893)return Et(e,4)+8;J(0)},re=function(e){var t=0;for(;1<<t<=e;++t);return t-1},ue=function(e,t,n){var r=(t<<3)+4,s=(e[t]&15)+5;if(s>n)J(3);var o=1<<s,i=o,a=-1,u=-1,c=-1,f=o,l=new vt(512+(o<<2)),p=new Ct(l,0,256),d=new de(l,0,256),w=new de(l,512,o),y=512+(o<<1),L=new Z(l,y,o),g=new Z(l,y+o);while(a<255&&i>0){var m=re(i+1),b=r>>3,h=(1<<m+1)-1,P=(e[b]|e[b+1]<<8|e[b+2]<<16)>>(r&7)&h,A=(1<<m)-1,E=h-i-1,T=P&A;if(T<E)r+=m,P=T;else if(r+=m+1,P>A)P-=E;if(p[++a]=--P,P==-1)i+=P,L[--f]=a;else i-=P;if(!P)do{var B=r>>3;u=(e[B]|e[B+1]<<8)>>(r&7)&3,r+=2,a+=u}while(u==3)}if(a>255||i)J(0);var v=0,F=(o>>1)+(o>>3)+3,Y=o-1;for(var _=0;_<=a;++_){var C=p[_];if(C<1){d[_]=-C;continue}for(c=0;c<C;++c){L[v]=_;do v=v+F&Y;while(v>=f)}}if(v)J(0);for(c=0;c<o;++c){var M=d[L[c]]++,k=g[c]=s-re(M);w[c]=(M<<k)-o}return[r+7>>3,{b:s,s:L,n:g,t:w}]},Pt=function(e,t){var n=0,r=-1,s=new Z(292),o=e[t],i=s.subarray(0,256),a=s.subarray(256,268),u=new de(s.buffer,268);if(o<128){var c=ue(e,t+1,6),f=c[0],l=c[1];t+=o;var p=f<<3,d=e[t];if(!d)J(0);var w=0,y=0,L=l.b,g=L,m=(++t<<3)-8+re(d);for(;;){if(m-=L,m<p)break;var b=m>>3;if(w+=(e[b]|e[b+1]<<8)>>(m&7)&(1<<L)-1,i[++r]=l.s[w],m-=g,m<p)break;b=m>>3,y+=(e[b]|e[b+1]<<8)>>(m&7)&(1<<g)-1,i[++r]=l.s[y],L=l.n[w],w=l.t[w],g=l.n[y],y=l.t[y]}if(++r>255)J(0)}else{r=o-127;for(;n<r;n+=2){var h=e[++t];i[n]=h>>4,i[n+1]=h&15}++t}var P=0;for(n=0;n<r;++n){var A=i[n];if(A>11)J(0);P+=A&&1<<A-1}var E=re(P)+1,T=1<<E,B=T-P;if(B&B-1)J(0);i[r++]=re(B)+1;for(n=0;n<r;++n){var A=i[n];++a[i[n]=A&&E+1-A]}var v=new Z(T<<1),F=v.subarray(0,T),Y=v.subarray(T);u[E]=0;for(n=E;n>0;--n){var _=u[n];ce(Y,n,_,u[n-1]=_+a[n]*(1<<E-n))}if(u[0]!=T)J(0);for(n=0;n<r;++n){var C=i[n];if(C){var M=u[C];ce(F,n,M,u[C]=M+(1<<E-C))}}return[t,{n:Y,b:E,s:F}]},kt=ue(new Z([81,16,99,140,49,198,24,99,12,33,196,24,99,102,102,134,70,146,4]),0,6)[1],It=ue(new Z([33,20,196,24,99,140,33,132,16,66,8,33,132,16,66,8,33,68,68,68,68,68,68,68,68,36,9]),0,6)[1],Bt=ue(new Z([32,132,16,66,102,70,68,68,68,68,36,73,2]),0,5)[1],We=function(e,t){var n=e.length,r=new be(n);for(var s=0;s<n;++s)r[s]=t,t+=1<<e[s];return r},Ee=new Z(new be([0,0,0,0,16843009,50528770,134678020,202050057,269422093]).buffer,0,36),Ft=We(Ee,0),Se=new Z(new be([0,0,0,0,0,0,0,0,16843009,50528770,117769220,185207048,252579084,16]).buffer,0,53),Rt=We(Se,3),le=function(e,t,n){var r=e.length,s=t.length,o=e[r-1],i=(1<<n.b)-1,a=-n.b;if(!o)J(0);var u=0,c=n.b,f=(r<<3)-8+re(o)-c,l=-1;for(;f>a&&l<s;){var p=f>>3,d=(e[p]|e[p+1]<<8|e[p+2]<<16)>>(f&7);u=(u<<c|d)&i,t[++l]=n.s[u],f-=c=n.n[u]}if(f!=a||l+1!=s)J(0)},Dt=function(e,t,n){var r=6,s=t.length,o=s+3>>2,i=o<<1,a=o+i;le(e.subarray(r,r+=e[0]|e[1]<<8),t.subarray(0,o),n),le(e.subarray(r,r+=e[2]|e[3]<<8),t.subarray(o,i),n),le(e.subarray(r,r+=e[4]|e[5]<<8),t.subarray(i,a),n),le(e.subarray(r),t.subarray(a),n)},Ut=function(e,t,n){var r,s=t.b,o=e[s],i=o>>1&3;t.l=o&1;var a=o>>3|e[s+1]<<5|e[s+2]<<13,u=(s+=3)+a;if(i==1){if(s>=e.length)return;if(t.b=s+1,n)return ce(n,e[s],t.y,t.y+=a),n;return ce(new Z(a),e[s])}if(u>e.length)return;if(i==0){if(t.b=u,n)return n.set(e.subarray(s,u),t.y),t.y+=a,n;return Le(e,s,u)}if(i==2){var c=e[s],f=c&3,l=c>>2&3,p=c>>4,d=0,w=0;if(f<2)if(l&1)p|=e[++s]<<4|(l&2&&e[++s]<<12);else p=c>>3;else if(w=l,l<2)p|=(e[++s]&63)<<4,d=e[s]>>6|e[++s]<<2;else if(l==2)p|=e[++s]<<4|(e[++s]&3)<<12,d=e[s]>>2|e[++s]<<6;else p|=e[++s]<<4|(e[++s]&63)<<12,d=e[s]>>6|e[++s]<<2|e[++s]<<10;++s;var y=n?n.subarray(t.y,t.y+t.m):new Z(t.m),L=y.length-p;if(f==0)y.set(e.subarray(s,s+=p),L);else if(f==1)ce(y,e[s++],L);else{var g=t.h;if(f==2){var m=Pt(e,s);d+=s-(s=m[0]),t.h=g=m[1]}else if(!g)J(0);(w?Dt:le)(e.subarray(s,s+=d),y.subarray(L),g)}var b=e[s++];if(b){if(b==255)b=(e[s++]|e[s++]<<8)+32512;else if(b>127)b=b-128<<8|e[s++];var h=e[s++];if(h&3)J(0);var P=[It,Bt,kt];for(var A=2;A>-1;--A){var E=h>>(A<<1)+2&3;if(E==1){var T=new Z([0,0,e[s++]]);P[A]={s:T.subarray(2,3),n:T.subarray(0,1),t:new de(T.buffer,0,1),b:0}}else if(E==2)r=ue(e,s,9-(A&1)),s=r[0],P[A]=r[1];else if(E==3){if(!t.t)J(0);P[A]=t.t[A]}}var B=t.t=P,v=B[0],F=B[1],Y=B[2],_=e[u-1];if(!_)J(0);var C=(u<<3)-8+re(_)-Y.b,M=C>>3,k=0,G=(e[M]|e[M+1]<<8)>>(C&7)&(1<<Y.b)-1;M=(C-=F.b)>>3;var I=(e[M]|e[M+1]<<8)>>(C&7)&(1<<F.b)-1;M=(C-=v.b)>>3;var N=(e[M]|e[M+1]<<8)>>(C&7)&(1<<v.b)-1;for(++b;--b;){var j=Y.s[G],X=Y.n[G],W=v.s[N],S=v.n[N],x=F.s[I],R=F.n[I];M=(C-=x)>>3;var D=1<<x,U=D+((e[M]|e[M+1]<<8|e[M+2]<<16|e[M+3]<<24)>>>(C&7)&D-1);M=(C-=Se[W])>>3;var H=Rt[W]+((e[M]|e[M+1]<<8|e[M+2]<<16)>>(C&7)&(1<<Se[W])-1);M=(C-=Ee[j])>>3;var z=Ft[j]+((e[M]|e[M+1]<<8|e[M+2]<<16)>>(C&7)&(1<<Ee[j])-1);if(M=(C-=X)>>3,G=Y.t[G]+((e[M]|e[M+1]<<8)>>(C&7)&(1<<X)-1),M=(C-=S)>>3,N=v.t[N]+((e[M]|e[M+1]<<8)>>(C&7)&(1<<S)-1),M=(C-=R)>>3,I=F.t[I]+((e[M]|e[M+1]<<8)>>(C&7)&(1<<R)-1),U>3)t.o[2]=t.o[1],t.o[1]=t.o[0],t.o[0]=U-=3;else{var V=U-(z!=0);if(V){if(U=V==3?t.o[0]-1:t.o[V],V>1)t.o[2]=t.o[1];t.o[1]=t.o[0],t.o[0]=U}else U=t.o[0]}for(var A=0;A<z;++A)y[k+A]=y[L+A];k+=z,L+=z;var O=k-U;if(O<0){var K=-O,q=t.e+O;if(K>H)K=H;for(var A=0;A<K;++A)y[k+A]=t.w[q+A];k+=K,H-=K,O=0}for(var A=0;A<H;++A)y[k+A]=y[O+A];k+=H}if(k!=L)while(L<y.length)y[k++]=y[L++];else k=y.length;if(n)t.y+=k;else y=Le(y,0,k)}else if(n){if(t.y+=p,L)for(var A=0;A<p;++A)y[A]=y[L+A]}else if(L)y=Le(y,L);return t.b=u,y}J(2)},Ot=function(e,t){if(e.length==1)return e[0];var n=new Z(t);for(var r=0,s=0;r<e.length;++r){var o=e[r];n.set(o,s),s+=o.length}return n};function ye(e,t){var n=[],r=+!t,s=0,o=0;for(;e.length;){var i=St(e,r||t);if(typeof i=="object"){if(r){if(t=null,i.w.length==i.u)n.push(t=i.w),o+=i.u}else n.push(t),i.e=0;for(;!i.l;){var a=Ut(e,i,t);if(!a)J(5);if(t)i.e=i.y;else n.push(a),o+=a.length,Tt(i.w,0,a.length),i.w.set(a,i.w.length-a.length)}s=i.b+i.c*4}else s=i;e=e.subarray(s)}return Ot(n,o)}async function Nt(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),n=(r)=>r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);if(t[0]===40&&t[1]===181&&t[2]===47&&t[3]===253)return n(ye(t));if(t[0]===31&&t[1]===139)return new Response(new Blob([t]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();return n(t)}async function Xe(e){return new TextDecoder().decode(await Nt(e))}var Ze=(e)=>decodeURIComponent(e.split(/[?#]/)[0].split("/").pop()||"main.ldr").replace(/\\.(zst|gz)$/i,"")||"main.ldr";function xe(e){let t=new DataView(e).getUint32(0,!0),n=JSON.parse(new TextDecoder().decode(new Uint8Array(e,4,t))),r=4+t;return{header:n,arr:(o)=>o&&(o[2]==="f32"?new Float32Array(e,r+o[0],o[1]):o[2]==="u16"?new Uint16Array(e,r+o[0],o[1]):o[2]==="u8"?new Uint8Array(e,r+o[0],o[1]):new Uint32Array(e,r+o[0],o[1])),bytes:e.byteLength,buffer:e}}var Q=(e)=>e.trim().toLowerCase().replace(/\\\\/g,"/").replace(/\\/+/g,"/"),ke=/^[A-Za-z][A-Za-z0-9_]*$/,Pe=new Map;function Ie(e){let t=e.toLowerCase(),n=2166136261;for(let s=0;s<t.length;s++)n^=t.charCodeAt(s),n=Math.imul(n,16777619);let r=-1-(n>>>0&1073741823);if(!Pe.has(r))Pe.set(r,t);return r}function Be(e){let t=e.charCodeAt(0)|32;if(t>=97&&t<=122&&ke.test(e))return Ie(e);if(/^0x/i.test(e))return parseInt(e,16);return+e}var Ye=/^~?\\s*moved\\s+to\\s+(.+)$/i,zt=new Set(["FILE","NOFILE","!DATA","!:","STEP","BFC","ROTSTEP","BUFEXCHG","!TEXMAP"]),st=new Set(["part","subpart","primitive","8_primitive","48_primitive","shortcut","helper"]),$t=new Set(["model","submodel","configuration"]),jt=/^(?:!?LDRAW_ORG|Unofficial|Official\\s+LCAD)\\s+(\\S+)/i;function Je(e){let t=jt.exec(e);if(!t)return;let n=t[1].toLowerCase().replace(/^unofficial_/,"");return st.has(n)||$t.has(n)?n:void 0}function Vt(e){let t=[],n=0;while(n<e.length){while(e[n]===" "||e[n]==="\\t")n++;if(n>=e.length)break;if(e[n]===\'"\'){let r="";n++;while(n<e.length&&e[n]!==\'"\'){if(e[n]==="\\\\"&&n+1<e.length)n++;r+=e[n++]}n++,t.push(r)}else{let r=n;while(r<e.length&&e[r]!==" "&&e[r]!=="\\t")r++;t.push(e.slice(n,r)),n=r}}return t}function _t(e,t=!1){let n=/^\\s*(\\S+)\\s+(.*)$/.exec(e);if(!n)return null;let r=n[1].toUpperCase(),s=r==="PLANAR"?9:r==="CYLINDRICAL"?10:r==="SPHERICAL"?11:0;if(!s)return null;let o=n[2].trim().split(/\\s+/);if(o.length<s+1)return null;let i=o.slice(0,s).map(Number);if(!i.every(Number.isFinite))return null;let a=n[2].trim();for(let l=0;l<s;l++)a=a.replace(/^\\S+\\s*/,"");let u=Vt(a);if(!u.length)return null;let c={method:r,p1:i.slice(0,3),p2:i.slice(3,6),p3:i.slice(6,9),texture:u[0]};if(s>=10)c.a=i[9];if(s===11)c.b=i[10];let f=u.findIndex((l,p)=>p>0&&l.toUpperCase()==="GLOSSMAP");if(f>0&&u[f+1])c.glossmap=u[f+1];if(t)c.next=!0;return c}var Ht=(e)=>{let t=e.replace(/[^A-Za-z0-9+/]/g,""),n=t+"=".repeat((4-t.length%4)%4),r=atob(n),s=new Uint8Array(r.length);for(let o=0;o<r.length;o++)s[o]=r.charCodeAt(o);return s};function Gt(e){let t=e.length,n=1,r=(c)=>c===32||c===9,s=()=>{while(n<t&&r(e.charCodeAt(n)))n++;let c=n;while(n<t&&!r(e.charCodeAt(n)))n++;return c<n?e.slice(c,n):null},o=s();if(o===null)return null;let i=Array(12);for(let c=0;c<12;c++){let f=s();if(f===null)return null;i[c]=+f}while(n<t&&r(e.charCodeAt(n)))n++;if(n>=t)return null;let a=e.slice(n),u=/[ \\t]{2,}|\\t/.test(a)?a.split(/\\s+/).join(" "):a;return{t:1,color:Be(o),m:i,file:Q(u)}}function qe(e){let t=+e[0];if(!(t>=1&&t<=5)||e.length<2)return null;let n=Be(e[1]),r=e.slice(2).map(Number);if(t===1)return{t:1,color:n,m:r.slice(0,12),file:Q(e.slice(14).join(" "))};if(t===2)return{t:2,color:n,p:r.slice(0,6)};if(t===3)return{t:3,color:n,p:r.slice(0,9)};if(t===4)return{t:4,color:n,p:r.slice(0,12)};return{t:5,color:n,p:r.slice(0,12)}}function ot(e,t="main.ldr",n={}){let r=!!n.geometryText,s=new Map,o=null,i="",a,u=null,c=[],f=null,l=()=>{if(!u)return;let m=Ht(u.chunks.join("")),b=m[0]===137&&m[1]===80&&m[2]===78&&m[3]===71;(a??=new Map).set(Q(u.name),{name:u.name,bytes:m,...b?{mime:"image/png"}:{}}),u=null},p=!0,d=(m)=>{if(l(),o={name:Q(m),cmds:[]},s.set(o.name,o),!i)i=o.name;c=[],f=null,p=!0},w=!1,y=!1,L=()=>{if(y)return;y=!0,s.clear(),o=null,i=""},g=(m,b)=>{if(f){m.tex=f,f=null;return}let h=c[c.length-1];if(!h)return;if(h.fallback){if(!b)m.fallback=!0}else m.tex=h.map};for(let m of e.split(`\n`)){let b=m.trim();if(!b)continue;if(r&&b.charCodeAt(0)>=50&&b.charCodeAt(0)<=53&&(b.charCodeAt(1)===32||b.charCodeAt(1)===9)){if(u||w)continue;if(!o)d(t);let E=b.slice(2).trimStart(),T=E.search(/\\s/),B={t:b.charCodeAt(0)-48,color:Be(T<0?E:E.slice(0,T)),p:[],src:b};g(B,!1),o.cmds.push(B),p=!1;continue}if(b.charCodeAt(0)===48&&(b.charCodeAt(1)===32||b.charCodeAt(1)===9)){let E=2;while(b.charCodeAt(E)===32||b.charCodeAt(E)===9)E++;let T=E;while(T<b.length&&b.charCodeAt(T)!==32&&b.charCodeAt(T)!==9)T++;let B=b.slice(E,T);if(!zt.has(B)){if(w||u)continue;if(!o)d(t);let v=b.slice(E),F={t:0,text:v};if(B.charCodeAt(0)===33)F.meta=B;if(f=null,p&&!o.org){let _=Je(v);if(_)o.org=_}let Y=v.match(Ye);if(Y&&!o.movedTo){let _=Y[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(_))_+=".dat";o.movedTo=Q(_)}o.cmds.push(F);continue}}if(b.charCodeAt(0)===49&&(b.charCodeAt(1)===32||b.charCodeAt(1)===9)&&!u&&!w){let E=Gt(b);if(E){if(!o)d(t);g(E,!1),o.cmds.push(E),p=!1;continue}}let h=b.split(/\\s+/);if(+h[0]===0){let E=b.slice(1).trim();if(h[1]==="FILE"){L(),w=!1,d(E.slice(5));continue}if(h[1]==="NOFILE"){l(),o=null,w=!0;continue}if(h[1]==="!DATA"){L(),l(),o=null,w=!1,u={name:E.slice(5).trim(),chunks:[]};continue}if(w)continue;if(u){if(h[1]==="!:")u.chunks.push(h.slice(2).join(""));continue}if(!o)d(t);let T={t:0,text:E};if(h[1]==="STEP")T.step=!0,c=[],f=null;else if(h[1]==="BFC")T.bfc=h.slice(2).join(" ");else if(h[1]==="ROTSTEP")if(T.meta="ROTSTEP",T.step=!0,c=[],f=null,(h[2]??"").toUpperCase()==="END")T.rotstep={x:0,y:0,z:0,mode:"END"};else{let v=(h[5]??"REL").toUpperCase();T.rotstep={x:+h[2]||0,y:+h[3]||0,z:+h[4]||0,mode:["REL","ABS","ADD"].includes(v)?v:"REL"}}else if(h[1]==="BUFEXCHG"){T.meta="BUFEXCHG";let v=(h[2]??"").toUpperCase();T.bufexchg={op:v==="RETRIEVE"?"RETRIEVE":"STORE",buf:h[3]??"A"}}else if(h[1]?.startsWith("!"))T.meta=h[1];if(p&&!o.org){let v=Je(E);if(v)o.org=v}if(h[1]==="!TEXMAP"){let v=(h[2]??"").toUpperCase();if(f=null,v==="START"||v==="NEXT"){let F=_t(E.replace(/^!TEXMAP\\s+\\S+/i,""),v==="NEXT");if(T.texmap={op:v,...F?{map:F}:{}},F)if((o.texmaps??=[]).push(F),v==="START")c.push({map:F,fallback:!1});else f=F}else if(v==="FALLBACK"){T.texmap={op:v};let F=c[c.length-1];if(F)F.fallback=!0}else if(v==="END")T.texmap={op:v},c.pop()}else if(h[1]==="!:"){f=null;let v=qe(h.slice(2));if(v)g(v,!0),T.geom=v}else f=null;let B=E.match(Ye);if(B&&!o.movedTo){let v=B[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(v))v+=".dat";o.movedTo=Q(v)}o.cmds.push(T);continue}if(u||w)continue;if(!o)d(t);let A=qe(h);if(!A)continue;g(A,!1),o.cmds.push(A),p=!1}return l(),a?{main:i,files:s,data:a}:{main:i,files:s}}var yn=Math.PI/180;function it(e,t){let n=(r)=>[t[3]*r[0]+t[4]*r[1]+t[5]*r[2]+t[0],t[6]*r[0]+t[7]*r[1]+t[8]*r[2]+t[1],t[9]*r[0]+t[10]*r[1]+t[11]*r[2]+t[2]];return{...e,p1:n(e.p1),p2:n(e.p2),p3:n(e.p3)}}function at(e,t){let[n,r,s,o,i,a,u,c,f,l,p,d]=e,[w,y,L,g,m,b,h,P,A,E,T,B]=t;return[o*w+i*y+a*L+n,u*w+c*y+f*L+r,l*w+p*y+d*L+s,o*g+i*h+a*E,o*m+i*P+a*T,o*b+i*A+a*B,u*g+c*h+f*E,u*m+c*P+f*T,u*b+c*A+f*B,l*g+p*h+d*E,l*m+p*P+d*T,l*b+p*A+d*B]}var Fe=[0,0,0,1,0,0,0,1,0,0,0,1];var Qe=new WeakMap,Kt=/^(s|8|48)\\//;function Re(e,t){let n=e.files.get(Q(t));if(!n)return"part";let r=Qe.get(n);if(r)return r;if(n.org)r=st.has(n.org)?"part":"model";else if(n.name===e.main)r="model";else r=n.cmds.some((s)=>s.t>=2||s.t===0&&!!s.geom||s.t===1&&Kt.test(s.file))?"part":"model";return Qe.set(n,r),r}var et=new WeakMap;function lt(e){let t=et.get(e);if(t)return t;t=[];let n=0;for(let r of e.cmds){if(r.t===0&&r.step){n++;continue}if((r.t>=2||r.t===0&&r.geom&&r.geom.t>=2)&&t[t.length-1]!==n)t.push(n)}return et.set(e,t),t}var tt=(e)=>e>16777215?"0x"+e.toString(16).toUpperCase():e<0?Pe.get(e)??String(e):String(e),Wt=(e)=>e.t===0?"0 "+e.text:e.t===1?`1 ${tt(e.color)} ${e.m.join(" ")} ${e.file}`:e.src?e.src:`${e.t} ${tt(e.color)} ${e.p.join(" ")}`,De=(e,t)=>`${Q(e)}#${t}`;function Xt(e,t){let n=[],r=0,s=(o)=>!!o&&o.t===0&&o.texmap?.op==="NEXT";for(let o of e.cmds){if(o.t===0){if(o.step){r++;continue}if(o.bfc!==void 0){n.push(o);continue}if(r!==t)continue;if(o.texmap)n.push(o);else if(o.geom){if(o.geom.t>=2)n.push(o);else if(s(n[n.length-1]))n.pop()}continue}if(r!==t)continue;if(o.t===1){if(s(n[n.length-1]))n.pop();continue}n.push(o)}return{name:De(e.name,t),cmds:n}}function ct(e,t){return[`0 ldr: own geometry of ${e.name}, step ${t}`,...Xt(e,t).cmds.map(Wt)].join(`\n`)+`\n`}function Zt(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")}function ut(e){let[t,n,r,s,o,i,a,u,c,f,l,p]=e,d=u*p-c*l,w=-(a*p-c*f),y=a*l-u*f,L=s*d+o*w+i*y;if(!Number.isFinite(L)||Math.abs(L)<0.000000000001)return null;let g=1/L,m=[d*g,-(o*p-i*l)*g,(o*c-i*u)*g,w*g,(s*p-i*f)*g,-(s*c-i*a)*g,y*g,-(s*l-o*f)*g,(s*u-o*a)*g];return[-(m[0]*t+m[1]*n+m[2]*r),-(m[3]*t+m[4]*n+m[5]*r),-(m[6]*t+m[7]*n+m[8]*r),...m]}var Yt=(e)=>String(+e.toFixed(6)||0),nt=(e)=>\'"\'+e.replace(/\\\\/g,"\\\\\\\\").replace(/"/g,"\\\\\\"")+\'"\';function ft(e,t){let n=[...t.p1,...t.p2,...t.p3,...t.method!=="PLANAR"?[t.a??360]:[],...t.method==="SPHERICAL"?[t.b??180]:[]].map(Yt).join(" "),r=`0 ldr: ${e} with a model-level !TEXMAP\n0 BFC CERTIFY CCW\n0 !TEXMAP START ${t.method} ${n} ${nt(t.texture)}${t.glossmap?" GLOSSMAP "+nt(t.glossmap):""}\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 ${Q(e)}\n0 !TEXMAP END\n`;return{name:`${Q(e)}#tex-${Zt(r)}`,source:r}}var Jt=(e,t)=>{let n=[,,,,,,,,,];for(let r=0;r<3;r++)for(let s=0;s<3;s++)n[r*3+s]=e[r*3]*t[s]+e[r*3+1]*t[3+s]+e[r*3+2]*t[6+s];return n};function qt(e,t,n){let r=Math.PI/180,s=Math.sin(e*r),o=Math.cos(e*r),i=Math.sin(t*r),a=Math.cos(t*r),u=Math.sin(n*r),c=Math.cos(n*r);return[a*c,-a*u,i,o*u+s*i*c,o*c-s*i*u,-s*a,s*u-o*i*c,s*c+o*i*u,o*a]}var rt=new WeakMap;function pt(e){let t=rt.get(e);if(t)return t;let n=[],r=null;for(let s of e.cmds){if(s.t!==0||!s.step)continue;let o=s.rotstep;if(o)if(o.mode==="END")r=null;else{let i=qt(o.x,o.y,o.z);r=o.mode==="ABS"?{abs:!0,m:i,rotstep:o}:o.mode==="ADD"&&r?{abs:r.abs,m:Jt(r.m,i),rotstep:o}:{abs:!1,m:i,rotstep:o}}n.push(r)}return n.push(r),rt.set(e,n),n}var mt=999999,gt=(e)=>e.map((t)=>String(t).padStart(6,"0")).join(".")+"~";function Qt(e,t={}){let n=[],r=t.maxDepth??64,s=t.looseGeometry!==!1,o=!!t.textures,i=!!t.callouts,a=new Map,u=0,c=(l,p)=>{let d=l.name+"#"+p,w=a.get(d);if(!w){let y;w=Object.assign(()=>y??=ct(l,p),{file:l,step:p}),a.set(d,w)}return w},f=(l,p,d,w,y,L,g,m,b=null,h=[],P=[],A=void 0,E=null)=>{let T=l.files.get(p);if(!T||g>r)return;let B=E,v=0,F=g>0?++u:0,Y=i&&F?[...h,F]:h,_=i&&F?[...P,d]:P,C=i&&!b?new Map:null,M=-1,k=0,G=(S,x,R,D,U,H,z)=>{if(M!==v)M=v,k=0;let V=C?.get(v+"|"+x);if(V)return V.n++,f(S,S===l?x:S.main,R,D,y+"/"+x,[...U,mt],g+1,H,[...U,mt],Y,_,z,B);let O=[...U,k++],K=n.length;f(S,S===l?x:S.main,R,D,y+"/"+x,O,g+1,H,b,Y,_,z,B),C?.set(v+"|"+x,{n:1,from:K,to:n.length})},I=pt(T),N=s?lt(T):[],j=0,X=(S,x,R,D,U,H,z,V)=>{if(b)D=b;let O={part:S,color:x,m:R,step:D[0],steps:D,localStep:U,path:y};if(V)O.colour=V;if(F){if(O.sub=F,i)O.subPath=Y,O.subMats=_}if(H)O.embedded=!0;if(z){let q=ft(S,z);O.texPart=q.name,O.texSource=q.source}let K=I[U];if(K)O.view=K;return n.push(O),O},W=(S)=>{while(j<N.length&&N[j]<=S){let x=N[j++];X(De(T.name,x),w,d,[...L,x],x,!1,null,A).source=c(T,x)}};for(let S of T.cmds){if(S.t===0&&S.step){v++;continue}let x=S;if(x.t>=2||x.t===0&&x.geom&&x.geom.t>=2){W(v);continue}if(x.t===0){if(x.meta==="!COLOUR"){let q=tn(x.text);if(q&&q.code!==16&&q.code!==24)(B=new Map(B??[])).set(q.code,q);continue}if(o&&x.geom?.t===1)x=x.geom;else continue}if(x.t!==1)continue;if(o&&x.fallback)continue;let R=x.color===16?w:x.color,D=x.color===16?A:B?.get(x.color),U=at(d,x.m),H=[...L,v],z=o?x.tex??m:null,V=z?ut(x.m):null,O=z&&V?it(z,V):null;if(l.files.has(x.file)){if(Re(l,x.file)==="model"){G(l,x.file,U,R,H,O,D);continue}X(x.file,R,U,H,v,!0,O,D);continue}let K=t.resolveModel?.(x.file);if(K){G(K,x.file,U,R,H,O,D);continue}X(x.file,R,U,H,v,!1,O,D)}if(W(1/0),C){for(let S of C.values())if(S.n>1)for(let x=S.from;x<S.to;x++)n[x].mult??=S.n}};if(Re(e,e.main)==="part"){if(e.files.get(e.main))n.push({part:e.main,color:16,m:[...Fe],step:0,steps:[0],localStep:0,path:e.main,embedded:!0});return n}return f(e,e.main,Fe,16,e.main,[],0,null),n}function dt(e,t="main.ldr",n){return Qt(ot(e,t,{geometryText:!0}),n)}var en=new Set(["CHROME","PEARLESCENT","RUBBER","MATTE_METALLIC","METAL","MATERIAL"]);function Ue(e){if(!e)return null;if(e.startsWith("#")&&/^#[0-9A-Fa-f]{6}$/.test(e))return e.toUpperCase();if(/^0x[0-9A-Fa-f]{6}$/i.test(e))return("#"+e.slice(2)).toUpperCase();return null}function ht(e,t){let n={value:"#FFFFFF",fraction:0.5};while(t<e.length){let r=e[t].toUpperCase(),s=e[t+1];if(r==="VALUE"){let o=Ue(s);if(o)n.value=o;t+=2}else if(r==="ALPHA")n.alpha=+s,t+=2;else if(r==="LUMINANCE")n.luminance=+s,t+=2;else if(r==="FRACTION")n.fraction=+s,t+=2;else if(r==="VFRACTION")n.vfraction=+s,t+=2;else if(r==="SIZE")n.size=+s,t+=2;else if(r==="MINSIZE")n.minsize=+s,t+=2;else if(r==="MAXSIZE")n.maxsize=+s,t+=2;else break}return{grain:n,next:t}}function tn(e){let t=e.indexOf("!COLOUR");if(t<0)return null;let n=e.slice(t+7).trim().split(/\\s+/).filter(Boolean);if(n.length<2)return null;let r=n[0],s=NaN,o="#FF00FF",i="#333333",a=255,u=0,c={type:"default"},f=1;while(f<n.length){let l=n[f].toUpperCase(),p=n[f+1];if(l==="CODE")s=p!==void 0&&ke.test(p)?Ie(p):p!==void 0&&/^\\d+$/.test(p)?+p:NaN,f+=2;else if(l==="VALUE"){let d=Ue(p);if(d)o=d;f+=2}else if(l==="EDGE")i=Ue(p)??p,f+=2;else if(l==="ALPHA")a=+p,f+=2;else if(l==="LUMINANCE")u=+p,f+=2;else if(l==="CHROME")c={type:"chrome"},f+=1;else if(l==="PEARLESCENT")c={type:"pearlescent"},f+=1;else if(l==="RUBBER")c={type:"rubber"},f+=1;else if(l==="MATTE_METALLIC")c={type:"matte_metallic"},f+=1;else if(l==="METAL")c={type:"metal"},f+=1;else if(l==="MATERIAL"){let d=(n[f+1]||"").toUpperCase();if(d==="GLITTER"){let{grain:w,next:y}=ht(n,f+2);c={type:"glitter",material:w},f=y}else if(d==="SPECKLE"){let{grain:w,next:y}=ht(n,f+2);c={type:"speckle",material:w},f=y}else if(d==="FABRIC"){let w=(n[f+2]||"").toUpperCase(),y=["VELVET","CANVAS","STRING","FUR"].includes(w)?w.toLowerCase():void 0;c={type:"fabric",kind:y},f+=y?3:2}else f=n.length}else if(en.has(l))f+=1;else f+=1}if(Number.isNaN(s)||!o)return null;return{code:s,name:r,hex:o,edge:i,alpha:Number.isFinite(a)?a:255,luminance:Number.isFinite(u)?u:0,finish:c}}function nn(e){let t=Math.max(0,Math.min(1,(e.alpha??255)/255)),n=t<1,r=Math.max(0,Math.min(1,(e.luminance??0)/255)),s={opacity:t,transparent:n,depthWrite:!n,emissive:r,clearcoat:0,clearcoatRoughness:0,sheen:0,sheenRoughness:0};switch(e.finish?.type??"default"){case"chrome":return{...s,metalness:1,roughness:0,finish:"chrome"};case"pearlescent":return{...s,metalness:0.25,roughness:0.3,clearcoat:0.5,clearcoatRoughness:0.25,sheen:0.4,sheenRoughness:0.35,finish:"pearlescent"};case"rubber":return{...s,metalness:0,roughness:0.9,finish:"rubber"};case"matte_metallic":return{...s,metalness:0.4,roughness:0.8,finish:"matte_metallic"};case"metal":return{...s,metalness:0.85,roughness:0.2,finish:"metal"};case"glitter":{let i=e.finish.material,a=i.size??(i.minsize!=null&&i.maxsize!=null?(i.minsize+i.maxsize)/2:1);return{...s,metalness:0.35,roughness:0.25,clearcoat:1,clearcoatRoughness:0.08,particleHex:i.value,particleFraction:i.fraction,particleSize:a,finish:"glitter"}}case"speckle":{let i=e.finish.material,a=i.size??(i.minsize!=null&&i.maxsize!=null?(i.minsize+i.maxsize)/2:1);return{...s,metalness:0.2,roughness:0.55,particleHex:i.value,particleFraction:i.fraction,particleSize:a,finish:"speckle"}}case"fabric":return{...s,metalness:0,roughness:0.85,sheen:0.65,sheenRoughness:0.75,finish:"fabric"};default:return{...s,metalness:0,roughness:0.45,finish:"default"}}}function Oe(e){let t=nn(e),n=!t.transparent?"op":t.opacity>=0.75?"a200":t.opacity>=0.4?"a128":`a${Math.round(t.opacity*255)}`,r=t.emissive>0?`L${Math.round(t.emissive*16)}`:"",s=`${t.finish}:${n}${r}`;if(t.particleHex)s+=`:${t.particleHex}:${(t.particleFraction??0).toFixed(2)}`;return s}function rn(e,t){let n=new Map,r=null,s=!1;for(let o of e.split(/\\r?\\n/)){let i=/^\\s*0\\s+FILE\\s+(.+)$/i.exec(o);if(i){if(!s)n.clear();s=!0,r=[],n.set(Q(i[1]),r);continue}if(/^\\s*0\\s+(NOFILE|!DATA)(\\s|$)/i.test(o)){if(!s)n.clear();s=!0,r=null;continue}if(!r){if(s)continue;r=[],n.set(Q(t),r)}let a=o.trim().replace(/\\s+/g," ");if(a)r.push(a)}return n}var sn=(e)=>{if(!e.startsWith("1 "))return null;let t=e.split(" ");return t.length>=15?Q(t.slice(14).join(" ")):null};function on(e){let t=2166136261,n=1523705862;for(let r=0;r<e.length;r++){let s=e.charCodeAt(r);t=Math.imul(t^s,16777619),n=Math.imul(n^s,16777629)^n>>>15}return(t>>>0).toString(16).padStart(8,"0")+(n>>>0).toString(16).padStart(8,"0")}function bt(e,t,n="main.ldr"){let r=rn(e,n),s=new Map;for(let o of t){let i=Q(o);if(!r.has(i)||s.has(i))continue;let a=new Set([i]),u=[i];while(u.length)for(let f of r.get(u.pop())){let l=sn(f);if(l&&r.has(l)&&!a.has(l))a.add(l),u.push(l)}let c=[i,...[...a].filter((f)=>f!==i).sort()].map((f)=>"0 FILE "+(f===i?"":f)+`\n`+r.get(f).join(`\n`)).join(`\n`);s.set(i,`emb/${on(c)}.dat`)}return s}var yt=(e,t=0)=>Math.abs(e[t+7]-1)<0.001&&Math.abs(e[t+4])<0.001&&Math.abs(e[t+10])<0.001,xt=new WeakMap;function Ne(e,t){let n=xt.get(e);if(!n)xt.set(e,n=new Map);let r=n.get(t);if(r!==void 0)return r;let s=e.parts[t];if(!s)return n.set(t,null),null;let o=s.studs.length,i=new Float64Array(o*12),a=[],u=[];s.studs.forEach((p,d)=>{a.push(p[0]),u.push(p[1]);for(let w=0;w<12;w++)i[d*12+w]=p[2+w]});let c=null,f=0,l=0;if(s.mask){f=s.mask[0],l=s.mask[1];let p=s.mask[2];c=new Uint8Array(p.length);for(let d=0;d<p.length;d++)c[d]=p.charCodeAt(d)===49?1:0}return n.set(t,r={nStuds:o,studM:i,kind:a,color:u,mask:c,nx:f,nz:l}),r}var ie=1073741824;class ze{a;b;c;vals;used;mask;size=0;constructor(e=1024){let t=1024;while(t<e*2)t*=2;this.a=new Int32Array(t),this.b=new Int32Array(t),this.c=new Int32Array(t),this.vals=new Int32Array(t),this.used=new Uint8Array(t),this.mask=t-1}slot(e,t,n){let r=Math.imul(e,2654435761)^Math.imul(t,2246822507)^Math.imul(n,3266489909);return r^=r>>>15,r=Math.imul(r,739982445),r^=r>>>12,r&this.mask}get(e,t,n){let r=this.slot(e,t,n),s=this.used,o=this.a,i=this.b,a=this.c;for(;;){if(!s[r])return-1;if(o[r]===e&&i[r]===t&&a[r]===n)return this.vals[r];r=r+1&this.mask}}put(e,t,n,r){if((this.size+1)*2>this.used.length)this.grow();let s=this.slot(e,t,n),o=this.used,i=this.a,a=this.b,u=this.c;for(;;){if(!o[s])return o[s]=1,i[s]=e,a[s]=t,u[s]=n,this.vals[s]=r,this.size++,-1;if(i[s]===e&&a[s]===t&&u[s]===n){let c=this.vals[s];return this.vals[s]=r,c}s=s+1&this.mask}}grow(){let{a:e,b:t,c:n,vals:r,used:s}=this,o=s.length*2;this.a=new Int32Array(o),this.b=new Int32Array(o),this.c=new Int32Array(o),this.vals=new Int32Array(o),this.used=new Uint8Array(o),this.mask=o-1,this.size=0;for(let i=0;i<s.length;i++)if(s[i])this.put(e[i],t[i],n[i],r[i])}}var we=(e,t,n)=>e>-ie&&e<ie&&t>-ie&&t<ie&&n>-ie&&n<ie,fe=2147483647;function an(e,t,n){let s=[],o=[],i=[],a=[],u=[],c=[],f=[],l=[],p=new ze(e.length*2),d=[],w=[];for(let C=0;C<e.length;C++){let M=e[C],k=M.m,G=t.parts[M.part];if(!G||!G.mask||!yt(k))continue;let I=G.bbox,N=1/0,j=-1/0,X=1/0,W=-1/0;for(let R=0;R<2;R++)for(let D=0;D<2;D++){let U=R?I[3]:I[0],H=D?I[5]:I[2],z=k[0]+k[3]*U+k[5]*H,V=k[2]+k[9]*U+k[11]*H;if(z<N)N=z;if(z>j)j=z;if(V<X)X=V;if(V>W)W=V}let S=u.length;s.push(N),o.push(j),i.push(X),a.push(W),u.push(C),c.push(Ne(t,M.part)),f.push(I[0]),l.push(I[2]);let x=Math.round((k[1]+I[4])*2);for(let R=Math.floor(N/40);R<=Math.floor(j/40);R++)for(let D=Math.floor(X/40);D<=Math.floor(W/40);D++){if(!we(x,R,D))continue;let U=w.length;w.push(S),d.push(p.put(x,R,D,U))}}let y=[0,5,-5,5,-5],L=[0,5,5,-5,-5],g=NaN,m=NaN,b=NaN,h=-1,P=(C,M,k,G)=>{let I=Math.round(M*2),N=Math.floor(C/40),j=Math.floor(k/40);if(!we(I,N,j))return fe;let X=fe;if(I!==g||N!==m||j!==b)g=I,m=N,b=j,h=p.get(I,N,j);for(let W=h;W>=0;W=d[W]){let S=w[W];if(u[S]===G||!(C-6>=s[S]-0.5&&C+6<=o[S]+0.5&&k-6>=i[S]-0.5&&k+6<=a[S]+0.5))continue;let x=e[u[S]].m,R=c[S],D=f[S],U=l[S],H=C-x[0],z=M-x[1],V=k-x[2],O=x[3]*H+x[6]*z+x[9]*V,K=x[5]*H+x[8]*z+x[11]*V,{nx:q,nz:se,mask:ae}=R,oe=!0;for(let ee=0;ee<5;ee++){let te=Math.floor((O+y[ee]-D)/20),ne=Math.floor((K+L[ee]-U)/20);if(te<0||ne<0||te>=q||ne>=se||ae[te*se+ne]!==1){oe=!1;break}}if(oe){if(!n)return 0;let ee=n[u[S]];if(ee<X)X=ee}}return X},A=0;for(let C of e){let M=Ne(t,C.part);if(M)A+=M.nStuds}let E=new Uint8Array(A),T=new Uint8Array(A),B=new ze(A),v=0,F=n?new Int32Array(A).fill(fe):void 0;for(let C=0,M=0;C<e.length;C++){let k=e[C],G=Ne(t,k.part);if(!G)continue;let I=k.m,N=G.studM,j=I[0],X=I[1],W=I[2],S=I[3],x=I[4],R=I[5],D=I[6],U=I[7],H=I[8],z=I[9],V=I[10],O=I[11];for(let K=0;K<G.nStuds;K++,M++){let q=K*12,se=N[q+4],ae=N[q+7],oe=N[q+10];if(!(Math.abs(D*se+U*ae+H*oe-1)<0.001&&Math.abs(S*se+x*ae+R*oe)<0.001&&Math.abs(z*se+V*ae+O*oe)<0.001))continue;T[M]=1;let ee=N[q],te=N[q+1],ne=N[q+2],$e=j+S*ee+x*te+R*ne,je=X+D*ee+U*te+H*ne,Ve=W+z*ee+V*te+O*ne,_e=P($e,je,Ve,C);if(_e!==fe){if(E[M]=1,v++,F)F[M]=_e}let me=Math.round($e),he=Math.round(je),ge=Math.round(Ve);if(!we(me,he,ge))continue;if(!n){B.put(me,he,ge,1);continue}let He=n[C],Ge=B.get(me,he,ge);if(Ge<0||He<Ge)B.put(me,he,ge,He)}}let Y=new Uint8Array(e.length),_=n?new Int32Array(e.length).fill(fe):void 0;for(let C=0;C<e.length;C++){let M=e[C],k=t.parts[M.part];if(!k||!k.under||!yt(M.m))continue;let G=k.bbox,I=Math.round((G[3]-G[0])/20),N=Math.round((G[5]-G[2])/20);if(!I||!N||I*N>4096)continue;let j=M.m,X=!0,W=0;for(let S=0;S<I&&X;S++)for(let x=0;x<N;x++){let R=G[0]+10+20*S,D=G[2]+10+20*x,U=j[0]+j[3]*R+j[5]*D,H=j[2]+j[9]*R+j[11]*D,z=Math.round(U),V=Math.round(j[1]+G[4]),O=Math.round(H),K=we(z,V,O)?B.get(z,V,O):-1;if(K<0){X=!1;break}if(K>W)W=K}if(X){if(Y[C]=1,_)_[C]=W}}return{nStuds:A,studHidden:E,studUp:T,underHidden:Y,studsHidden:v,studHideStep:F,underHideStep:_}}function ln(e,t,n){let r=(l)=>n&&l.texPart&&t.parts[l.texPart]?l.texPart:l.part,s=new Map,o=new Map,i=(l)=>{let p=l.colour;if(!p)return String(l.color);let d=o.get(p);if(d!==void 0)return d;let w=t.colorTable?.[l.color],y=w?.hex??t.colors?.[l.color],L=w?Oe({alpha:w.alpha??255,luminance:w.luminance??0,finish:w.finish??{type:"default"}}):"default:op",g=Oe(p);if(d=y&&y.toUpperCase()===p.hex.toUpperCase()&&L===g?String(l.color):p.hex.toUpperCase()+"/"+g,d!==String(l.color))s.set(d,p);return o.set(p,d),d},a=e.map((l)=>({part:r(l),color:i(l),m:l.m,steps:l.steps})),u=a.map((l)=>gt(l.steps)),c=[...new Set(u)].sort(),f=new Map(c.map((l,p)=>[l,p]));return{all:a,stepOf:u.map((l)=>f.get(l)),nSteps:c.length,localColours:s}}function Ae(e,t,n=!0){let r=ln(e,t,n);return an(r.all,t,r.nSteps>1?r.stepOf:void 0)}var Te="https://ldr-demo.vercel.app/cdn/v1/",ve=new Map,Me=new Map;function At(e=Te,t=fetch){let n=ve.get(e);if(!n)n=t(e+"parts.json").then((r)=>{if(!r.ok)throw Error(`ldr: parts CDN index ${r.status} (${e}parts.json)`);return r.json()}),n.catch(()=>ve.delete(e)),ve.set(e,n);return n}var cn=(e)=>Array.isArray(e)&&e.length===3&&typeof e[0]==="number"&&typeof e[1]==="number"&&(e[2]==="f32"||e[2]==="u16"||e[2]==="u8"||e[2]==="u32"),Ce=(e,t)=>cn(e)?[e[0]+t,e[1],e[2]]:Array.isArray(e)?e.map((n)=>Ce(n,t)):e&&typeof e==="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,Ce(r,t)])):e;function un(e,t={}){let n=[],r=0,s={},o={};for(let p of e){let d=p.buffer;if(!d)throw Error("ldr: mergePacks needs packs from decodePack/loadPack");let w=new DataView(d).getUint32(0,!0),y=new Uint8Array(d,4+w),L=r;n.push(y),r+=y.byteLength;let g=(4-r%4)%4;if(g)n.push(new Uint8Array(g)),r+=g;for(let[m,b]of Object.entries(p.header.parts??{}))if(!(m in s))s[m]=Ce(b,L);for(let[m,b]of Object.entries(p.header.studKinds??{}))if(!(m in o))o[m]=Ce(b,L)}let i=e[0]?.header??{version:1,weld:!0},a=new TextEncoder().encode(JSON.stringify({...i,parts:s,studKinds:o,...t})),u=(4-(4+a.length)%4)%4,c=4+a.length+u,f=new Uint8Array(c+r);new DataView(f.buffer).setUint32(0,a.length+u,!0),f.set(a,4),f.fill(32,4+a.length,c);let l=c;for(let p of n)f.set(p,l),l+=p.byteLength;return xe(f.buffer)}async function fn(e,t={}){e=[...e];try{return await wt(e,t)}catch(n){let r=t.cdn??Te,s=t.fetch??fetch;ve.delete(r);let o=(i,a)=>s(i,{...a,cache:"reload"});try{return await wt(e,{...t,fetch:o})}catch{throw n}}}async function wt(e,t){let n=t.cdn??Te,r=t.fetch??fetch,s=t.gap??16384,o=await At(n,r),i=[...new Set([...e].map(Q))],a=[],u=[];for(let g of i){if(Me.has(n+g))continue;let m=o.parts[g];if(m)u.push({name:g,off:m[0],len:m[1],file:m[2]??0});else a.push(g)}u.sort((g,m)=>g.file-m.file||g.off-m.off);let c=[];for(let g of u){let m=c[c.length-1];if(m&&m.file===g.file&&g.off-m.end<=s)m.end=Math.max(m.end,g.off+g.len),m.items.push(g);else c.push({file:g.file,start:g.off,end:g.off+g.len,items:[g]})}let f=0,l=0,p=0,d=new Map,w=async()=>{while(p<c.length){let g=c[p++],m=d.get(g.file);if(m)m=m.subarray(g.start,g.end);else{let b=await r(new URL(o.archives[g.file],n).href,{headers:{Range:`bytes=${g.start}-${g.end-1}`,"Accept-Encoding":"identity"}});if(!b.ok)throw Error(`ldr: parts CDN ${b.status}`);if(l++,m=new Uint8Array(await b.arrayBuffer()),f+=m.byteLength,b.status===200)d.set(g.file,m),m=m.subarray(g.start,g.end)}for(let b of g.items){let h=ye(m.subarray(b.off-g.start,b.off-g.start+b.len)),P=h.buffer.slice(h.byteOffset,h.byteOffset+h.byteLength);Me.set(n+b.name,xe(P))}}};await Promise.all(Array.from({length:Math.min(t.concurrency??24,c.length)},w));let y=i.filter((g)=>Me.has(n+g)).map((g)=>Me.get(n+g));return{pack:y.length?un(y,{colors:o.colors}):xe(pn(o.colors)),missing:a,requests:l,bytes:f}}function pn(e){let t=new TextEncoder().encode(JSON.stringify({version:1,weld:!0,parts:{},studKinds:{},colors:e})),n=(4-(4+t.length)%4)%4,r=new Uint8Array(4+t.length+n).fill(32);return new DataView(r.buffer).setUint32(0,t.length+n,!0),r.set(t,4),r.buffer}function mn(e,t){let n=t.header.parts;if(!n)return 0;let r=0;for(let s of e){let o=n[s.part]?.body?.tris;if(o)r+=o}return r}function hn(e,t,n){let r=0,s=0,o=!1,i=new Set;for(let a of e){let u=a.embedded?t.get(a.part):Q(a.part),c=u?n.parts[u]:void 0;if(!c)continue;if(c[3]!=null)o=!0,r+=c[3];if(!i.has(u))i.add(u),s+=c[1]}return{bodyTris:r,packBytes:s,known:o}}class pe extends Error{code="ldr-budget";bodyTris;packBytes;maxBodyTris;maxPackBytes;constructor(e){let t=[e.maxBodyTris!=null&&e.bodyTris>e.maxBodyTris?`${e.bodyTris} triangles (limit ${e.maxBodyTris})`:"",e.maxPackBytes!=null&&e.packBytes>e.maxPackBytes?`${(e.packBytes/1e6).toFixed(1)} MB parts pack (limit ${(e.maxPackBytes/1e6).toFixed(0)} MB)`:""].filter(Boolean).join(", ");super(`ldr: model exceeds device budget: ${t}`);this.name="BudgetError",this.bodyTris=e.bodyTris,this.packBytes=e.packBytes,this.maxBodyTris=e.maxBodyTris,this.maxPackBytes=e.maxPackBytes}}async function Mt(e,t={}){let n=performance.now(),r=t.fetch??fetch,s=At(t.cdn??Te,r);s.catch(()=>{});let o=t.text?e:await r(e).then(async(h)=>{if(!h.ok)throw Error(`ldr: ${h.status} fetching ${e}`);return Xe(await h.arrayBuffer())}),i=performance.now(),a=t.name??(t.text?"main.ldr":Ze(e)),u=dt(o,a,{looseGeometry:!1,callouts:t.callouts}),c=performance.now();t.onParsed?.(u),await s;let f=bt(o,new Set(u.filter((h)=>h.embedded).map((h)=>h.part)),a),l=(h,P)=>t.maxBodyTris!=null&&h>t.maxBodyTris||t.maxPackBytes!=null&&P>t.maxPackBytes;if(t.maxBodyTris!=null||t.maxPackBytes!=null){let h=hn(u,f,await s);if(l(h.known?h.bodyTris:0,h.packBytes))throw new pe({bodyTris:h.bodyTris,packBytes:h.packBytes,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes})}let{pack:p,missing:d,requests:w,bytes:y}=await fn([...u.filter((h)=>!h.embedded).map((h)=>h.part),...f.values()],t),L=new Map([...f].map(([h,P])=>[P,h])),g=d.map((h)=>L.get(h)??h);for(let[h,P]of f){let A=p.header.parts[P];if(A)p.header.parts[h]=A}let m=performance.now();if(t.maxBodyTris!=null||t.maxPackBytes!=null){let h=p.buffer?.byteLength??p.bytes??0,P=mn(u,p);if(l(P,h))throw new pe({bodyTris:P,packBytes:h,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes})}let b=t.cull?Ae(u,p.header,t.textures!==!1):void 0;return{insts:u,pack:p,missing:g,requests:w,bytes:y,cull:b,timings:{fetchModel:i-n,parse:c-i,parts:m-c,...b?{cull:performance.now()-m}:{}}}}self.onmessage=async(e)=>{let{id:t,source:n,opts:r}=e.data;try{let s=await Mt(n,{...r,cull:!1,onParsed:(f)=>self.postMessage({id:t,insts:f})}),o=s.pack.buffer;if(self.postMessage({id:t,buffer:o,missing:s.missing,requests:s.requests,bytes:s.bytes,timings:s.timings},[o]),!r.cull)return;let i=performance.now(),a=Ae(s.insts,s.pack.header,r.textures!==!1),u=performance.now()-i,c=[];for(let f of[a.studHidden,a.studUp,a.underHidden,a.studHideStep,a.underHideStep])if(f)c.push(f.buffer);self.postMessage({id:t,cull:a,ms:u},c)}catch(s){if(s instanceof pe||s?.code==="ldr-budget")self.postMessage({id:t,phase:"error",error:String(s?.message??s),budget:{bodyTris:s.bodyTris,packBytes:s.packBytes,maxBodyTris:s.maxBodyTris,maxPackBytes:s.maxPackBytes}});else self.postMessage({id:t,phase:"error",error:String(s?.message??s)})}};\n';
4165
4328
 
4166
- // ../../../../../../../tmp/ldr-build-tYthc8/src/cdn.ts
4329
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/cdn.ts
4167
4330
  var worker;
4168
4331
  var seq = 0;
4169
4332
  var pending = new Map;
@@ -1,4 +1,4 @@
1
- // ../../../../../../../tmp/ldr-build-tYthc8/src/spec.ts
1
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/spec.ts
2
2
  var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
3
3
  var COLOUR_ID_RE = /^[A-Za-z][A-Za-z0-9_]*$/;
4
4
  var namedCodes = new Map;
@@ -708,7 +708,7 @@ function fileStepViews(f) {
708
708
  viewMemo.set(f, out);
709
709
  return out;
710
710
  }
711
- // ../../../../../../../tmp/ldr-build-tYthc8/src/model.ts
711
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/model.ts
712
712
  var CALLOUT_END = 999999;
713
713
  var stepKey = (steps) => steps.map((x) => String(x).padStart(6, "0")).join(".") + "~";
714
714
  function flatten(doc, opts = {}) {
@@ -1090,7 +1090,7 @@ function blendedColourHex(code) {
1090
1090
  const a = LDRAW_EXE_16[code - 256 >> 4], b = LDRAW_EXE_16[code - 256 & 15];
1091
1091
  return "#" + [0, 1, 2].map((k) => (a[k] + b[k] >> 1).toString(16).padStart(2, "0")).join("").toUpperCase();
1092
1092
  }
1093
- // ../../../../../../../tmp/ldr-build-tYthc8/src/instructions.ts
1093
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/instructions.ts
1094
1094
  var MIN_VIS = 0.5;
1095
1095
  var REORIENT = 0.35;
1096
1096
  var deg = Math.PI / 180;
@@ -1458,10 +1458,10 @@ function planStepViews(insts, parts, stepOf, nSteps, o = {}) {
1458
1458
  }
1459
1459
  };
1460
1460
  }
1461
- // ../../../../../../../tmp/ldr-build-tYthc8/src/render.ts
1461
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/render.ts
1462
1462
  import * as THREE from "three";
1463
1463
 
1464
- // ../../../../../../../tmp/ldr-build-tYthc8/src/pack-io.ts
1464
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/pack-io.ts
1465
1465
  import { decompress } from "fzstd";
1466
1466
  async function decompressPack(data) {
1467
1467
  const u = data instanceof Uint8Array ? data : new Uint8Array(data);
@@ -1484,7 +1484,7 @@ function decodePack(buf) {
1484
1484
  return { header, arr, bytes: buf.byteLength, buffer: buf };
1485
1485
  }
1486
1486
 
1487
- // ../../../../../../../tmp/ldr-build-tYthc8/src/cull.ts
1487
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/cull.ts
1488
1488
  var upright = (m, o = 0) => Math.abs(m[o + 7] - 1) < 0.001 && Math.abs(m[o + 4]) < 0.001 && Math.abs(m[o + 10]) < 0.001;
1489
1489
  var prepCache = new WeakMap;
1490
1490
  function prepPart(H, part) {
@@ -1819,7 +1819,7 @@ function precomputeCull(instances, H, useTex = true) {
1819
1819
  return cullCore(s.all, H, s.nSteps > 1 ? s.stepOf : undefined);
1820
1820
  }
1821
1821
 
1822
- // ../../../../../../../tmp/ldr-build-tYthc8/src/render.ts
1822
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/render.ts
1823
1823
  async function loadPack(url) {
1824
1824
  const res = await fetch(url);
1825
1825
  if (!res.ok)
@@ -1868,6 +1868,10 @@ function flatNormals(pos, idx) {
1868
1868
  return n;
1869
1869
  }
1870
1870
  var geomCache = new WeakMap;
1871
+ var DECODE_CHUNK_VERTS = 65536;
1872
+ function geomCached(b, arr) {
1873
+ return !b || !!geomCache.get(arr)?.has(b);
1874
+ }
1871
1875
  function geom(b, arr) {
1872
1876
  if (!b)
1873
1877
  return null;
@@ -2519,6 +2523,12 @@ class LdrLodRoot extends THREE.LOD {
2519
2523
  }
2520
2524
  }
2521
2525
  }
2526
+ function fillBucketIds(bIds, fill, studBucket, j0, j1) {
2527
+ for (let j = j0;j < j1; j++) {
2528
+ const b = studBucket[j];
2529
+ bIds[b][fill[b]++] = j;
2530
+ }
2531
+ }
2522
2532
  function* buildStudMeshesGen(insts, H, cull, arr, LOD, color, matOf, steps, colorIndex) {
2523
2533
  const bKind = [], bMat = [];
2524
2534
  const bAll = [];
@@ -2596,14 +2606,15 @@ function* buildStudMeshesGen(insts, H, cull, arr, LOD, color, matOf, steps, colo
2596
2606
  sz[j] = a[2] + a[9] * b0 + a[10] * b1 + a[11] * b2;
2597
2607
  }
2598
2608
  }
2609
+ yield;
2599
2610
  const bIds = bAll.map((n) => new Int32Array(n));
2600
- {
2601
- const f = bAll.map(() => 0);
2602
- for (let j = 0;j < cull.nStuds; j++) {
2603
- const b = studBucket[j];
2604
- bIds[b][f[b]++] = j;
2605
- }
2611
+ const bFill = new Int32Array(bAll.length);
2612
+ for (let j0 = 0;j0 < cull.nStuds; j0 += 262144) {
2613
+ if (j0)
2614
+ yield;
2615
+ fillBucketIds(bIds, bFill, studBucket, j0, Math.min(cull.nStuds, j0 + 262144));
2606
2616
  }
2617
+ yield;
2607
2618
  const studCl = new Int32Array(cull.nStuds), studSlot = new Int32Array(cull.nStuds);
2608
2619
  const sMesh = [];
2609
2620
  const allocClusters = (b, kind, g, ids, cs, c0, c1) => {
@@ -2982,7 +2993,10 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
2982
2993
  const bodyB = textured ? p.tbody : p.body;
2983
2994
  const body = geom(bodyB, arr);
2984
2995
  const groups = gridClusters(idsAll.length, (i) => insts[idsAll[i]].m[0], (i) => insts[idsAll[i]].m[2], textured ? Infinity : kFor(tris(p.body) + tris(p.under)));
2996
+ let _coopH = 0;
2985
2997
  for (const g of groups) {
2998
+ if (_coopH++)
2999
+ yield root;
2986
3000
  const ids = Array.from(g, (i) => idsAll[i]);
2987
3001
  let bodyIm = null;
2988
3002
  const lv0 = [];
@@ -3103,6 +3117,19 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3103
3117
  }
3104
3118
  if (maxV === 0)
3105
3119
  continue;
3120
+ let decV = 0;
3121
+ for (const p of partSet.values())
3122
+ if (p.body)
3123
+ for (const b of LOD && p.body.lod ? [p.body, ...p.body.lod] : [p.body]) {
3124
+ if (geomCached(b, arr))
3125
+ continue;
3126
+ geom(b, arr);
3127
+ decV += geomVerts(b);
3128
+ if (decV >= DECODE_CHUNK_VERTS) {
3129
+ decV = 0;
3130
+ yield root;
3131
+ }
3132
+ }
3106
3133
  const bm = new THREE.BatchedMesh(members.length, Math.max(1, maxV), Math.max(1, maxI), mat);
3107
3134
  bm.perObjectFrustumCulled = true;
3108
3135
  bm.sortObjects = false;
@@ -3156,6 +3183,7 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3156
3183
  };
3157
3184
  cl.lv.push({ objs: [bm], err: 0 });
3158
3185
  if (EDGES) {
3186
+ yield root;
3159
3187
  const byPartIds = new Map;
3160
3188
  for (const m of live) {
3161
3189
  const a = byPartIds.get(m.part) || byPartIds.set(m.part, []).get(m.part);
@@ -3204,6 +3232,19 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3204
3232
  }
3205
3233
  if (!uV)
3206
3234
  continue;
3235
+ let uDecV = 0;
3236
+ for (const p of uPartSet.values())
3237
+ if (p.under)
3238
+ for (const b of LOD && p.under.lod ? [p.under, ...p.under.lod] : [p.under]) {
3239
+ if (geomCached(b, arr))
3240
+ continue;
3241
+ geom(b, arr);
3242
+ uDecV += geomVerts(b);
3243
+ if (uDecV >= DECODE_CHUNK_VERTS) {
3244
+ uDecV = 0;
3245
+ yield root;
3246
+ }
3247
+ }
3207
3248
  const ubm = new THREE.BatchedMesh(umembers.length, Math.max(1, uV), Math.max(1, uI), mat);
3208
3249
  ubm.perObjectFrustumCulled = true;
3209
3250
  ubm.sortObjects = false;
@@ -3574,18 +3615,23 @@ function yieldToMain() {
3574
3615
  });
3575
3616
  }
3576
3617
  async function buildLdrSceneAsync(insts, pack, P, color, mark, opts = {}) {
3618
+ const { value, longestSliceMs, yields } = await runSliced(buildLdrSceneGen(insts, pack, P, color, mark), opts);
3619
+ value.stats = { ...value.stats, longestSliceMs: +longestSliceMs.toFixed(2), buildYields: yields };
3620
+ return value;
3621
+ }
3622
+ async function runSliced(g, opts = {}) {
3577
3623
  const sliceMs = opts.sliceMs ?? 8;
3578
3624
  const postPaint = opts.postPaintSliceMs ?? Math.max(sliceMs, 24);
3579
3625
  let painting = typeof opts.onSlice === "function";
3580
3626
  let effective = painting ? sliceMs : postPaint;
3581
- const g = buildLdrSceneGen(insts, pack, P, color, mark);
3582
- let r = g.next();
3583
3627
  let sliceStart = performance.now();
3628
+ let r = g.next();
3584
3629
  let longestSliceMs = 0;
3585
3630
  let yields = 0;
3631
+ let maxStep = 0;
3586
3632
  while (!r.done) {
3587
3633
  const now = performance.now();
3588
- if (now - sliceStart >= effective) {
3634
+ if (now - sliceStart + Math.min(Math.max(maxStep, effective / 3), effective / 2) >= effective) {
3589
3635
  longestSliceMs = Math.max(longestSliceMs, now - sliceStart);
3590
3636
  yields++;
3591
3637
  if (painting && opts.onSlice) {
@@ -3598,12 +3644,12 @@ async function buildLdrSceneAsync(insts, pack, P, color, mark, opts = {}) {
3598
3644
  await yieldToMain();
3599
3645
  sliceStart = performance.now();
3600
3646
  }
3647
+ const t = performance.now();
3601
3648
  r = g.next();
3649
+ maxStep = Math.max(maxStep, performance.now() - t);
3602
3650
  }
3603
3651
  longestSliceMs = Math.max(longestSliceMs, performance.now() - sliceStart);
3604
- const value = r.value;
3605
- value.stats = { ...value.stats, longestSliceMs: +longestSliceMs.toFixed(2), buildYields: yields };
3606
- return value;
3652
+ return { value: r.value, longestSliceMs, yields };
3607
3653
  }
3608
3654
  async function warmPackGeometry(pack, stop = () => false, sliceMs = 8) {
3609
3655
  const { header: H, arr } = pack;
@@ -3627,8 +3673,27 @@ async function warmPackGeometry(pack, stop = () => false, sliceMs = 8) {
3627
3673
  await new Promise((r) => setTimeout(r, 0));
3628
3674
  }
3629
3675
  }
3630
- // ../../../../../../../tmp/ldr-build-tYthc8/src/scene.ts
3676
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/scene.ts
3631
3677
  import * as THREE2 from "three";
3678
+ function ghostMaterial(side, g) {
3679
+ const m = new THREE2.MeshStandardMaterial({ color: 16777215, roughness: 0.85, metalness: 0, side, transparent: false, depthWrite: true, opacity: g.opacity });
3680
+ m.blending = THREE2.CustomBlending;
3681
+ m.blendSrc = THREE2.SrcAlphaFactor;
3682
+ m.blendDst = THREE2.OneMinusSrcAlphaFactor;
3683
+ m.blendSrcAlpha = THREE2.OneFactor;
3684
+ m.blendDstAlpha = THREE2.OneMinusSrcAlphaFactor;
3685
+ const tint = new THREE2.Color(g.color);
3686
+ const u = { ldrGhostTint: { value: tint }, ldrGhostMix: { value: g.whiten } };
3687
+ m.onBeforeCompile = (sh) => {
3688
+ Object.assign(sh.uniforms, u);
3689
+ sh.fragmentShader = `uniform vec3 ldrGhostTint; uniform float ldrGhostMix;
3690
+ ` + sh.fragmentShader.replace("#include <color_fragment>", `#include <color_fragment>
3691
+ diffuseColor.rgb = mix(diffuseColor.rgb, ldrGhostTint, ldrGhostMix);`);
3692
+ };
3693
+ m.customProgramCacheKey = () => "ldrGhost";
3694
+ m.userData.ldrGhost = u;
3695
+ return m;
3696
+ }
3632
3697
  function colorFn(src, pack, fallback) {
3633
3698
  const table = new Map;
3634
3699
  const put = (k, v) => table.set(String(k), new THREE2.Color(typeof v === "string" ? v : v.hex));
@@ -3742,6 +3807,75 @@ function createLdrObjectInner(instances, pack, options, progressive) {
3742
3807
  }
3743
3808
  cur = null;
3744
3809
  };
3810
+ let ghostOn = false, ghost = null, ghostBuild = null, ghostGen = 0;
3811
+ let shownStep = null, shownMask = null;
3812
+ const ghostOpts = { opacity: 0.2, color: 16777215, whiten: 0.75 };
3813
+ const ghostMats = new Map;
3814
+ const syncGhost = () => {
3815
+ if (!ghost)
3816
+ return;
3817
+ const show = ghostOn && shownStep != null && shownStep < uniq.length - 1;
3818
+ ghost.root.visible = show;
3819
+ if (show)
3820
+ ghost.setStep(uniq.length - 2 - shownStep, shownMask);
3821
+ };
3822
+ const disposeGhost = () => {
3823
+ ghostGen++;
3824
+ ghostBuild = null;
3825
+ if (!ghost)
3826
+ return;
3827
+ object.remove(ghost.root);
3828
+ ghost.root.traverse((x) => {
3829
+ if (x.isInstancedMesh)
3830
+ x.dispose();
3831
+ else if (x.isBatchedMesh)
3832
+ x.dispose();
3833
+ });
3834
+ for (const m of ghostMats.values())
3835
+ m.dispose();
3836
+ ghostMats.clear();
3837
+ ghost = null;
3838
+ };
3839
+ const buildGhost = () => ghostBuild ??= (async () => {
3840
+ const my = ghostGen;
3841
+ const n = uniq.length;
3842
+ const rev = new Int32Array(stepOf.length);
3843
+ for (let k = 0;k < rev.length; k++)
3844
+ rev[k] = n - 1 - stepOf[k];
3845
+ const so = { ...sceneOpts(), edges: false, cond: false, tex: false, steps: rev, cull: undefined };
3846
+ so.cull = cullCore(all, pack.header, rev);
3847
+ const g = await buildLdrSceneAsync(all, pack, so, color, () => {}, { postPaintSliceMs: 12 });
3848
+ if (my !== ghostGen) {
3849
+ g.root.traverse((x) => {
3850
+ if (x.isInstancedMesh || x.isBatchedMesh)
3851
+ x.dispose();
3852
+ });
3853
+ return;
3854
+ }
3855
+ const old = new Set;
3856
+ g.root.traverse((x) => {
3857
+ if (!x.isMesh)
3858
+ return;
3859
+ if (x.material)
3860
+ old.add(x.material);
3861
+ let m = ghostMats.get(x.material?.side ?? THREE2.FrontSide);
3862
+ if (!m)
3863
+ ghostMats.set(x.material?.side ?? THREE2.FrontSide, m = ghostMaterial(x.material?.side ?? THREE2.FrontSide, ghostOpts));
3864
+ x.material = m;
3865
+ x.castShadow = x.receiveShadow = false;
3866
+ x.renderOrder = 1;
3867
+ x.userData.ldrGhost = true;
3868
+ });
3869
+ for (const m of old)
3870
+ m.dispose();
3871
+ g.root.name = "ldr-ghost";
3872
+ if (!lodOn)
3873
+ g.setLod(false);
3874
+ g.setCull(cs, cu);
3875
+ ghost = g;
3876
+ object.add(g.root);
3877
+ syncGhost();
3878
+ })();
3745
3879
  const multiStep = uniq.length > 1;
3746
3880
  const drawnAt = (step, mask) => all.filter((i, k) => (step == null || stepOf[k] <= step) && (!mask || mask[k]) && pack.header.parts[i.part]).length;
3747
3881
  const sceneOpts = () => ({ localColours: localColours.size ? localColours : undefined, cullStuds: cs, cullUnder: cu, edges: o.edges, side, cond: o.conditionalLines, condStuds: o.conditionalStudLines !== false, tex: o.textures !== false, lod: o.lod !== false, lodPx: o.lodPx, lodEdgePx: o.lodEdgePx, lodEdgeMinPx: o.lodEdgeMinPx, lodUnder: o.lodUnder, steps: multiStep ? stepOf : undefined, cull: o.precomputedCull });
@@ -3774,7 +3908,12 @@ function createLdrObjectInner(instances, pack, options, progressive) {
3774
3908
  if (!multiStep)
3775
3909
  return;
3776
3910
  const t0 = performance.now();
3911
+ shownStep = step;
3912
+ shownMask = mask;
3777
3913
  Object.assign(stats, cur.setStep(step, mask), { drawn: drawnAt(step, mask), buildMs: performance.now() - t0 });
3914
+ if (ghostOn && step != null && !ghost)
3915
+ buildGhost();
3916
+ syncGhost();
3778
3917
  };
3779
3918
  const api = { texturesReady: Promise.resolve() };
3780
3919
  const finish = () => {
@@ -3803,10 +3942,31 @@ function createLdrObjectInner(instances, pack, options, progressive) {
3803
3942
  applyBuilt(buildLdrScene(all, pack, sceneOpts(), color, () => {}), t0);
3804
3943
  } else
3805
3944
  cur.setCull(a, b);
3945
+ ghost?.setCull(a, b);
3806
3946
  },
3807
3947
  setLod: (v) => {
3808
3948
  lodOn = v;
3809
3949
  cur.setLod(v);
3950
+ ghost?.setLod(v);
3951
+ },
3952
+ setGhost: (on, go = {}) => {
3953
+ ghostOn = on && multiStep;
3954
+ Object.assign(ghostOpts, Object.fromEntries(Object.entries(go).filter(([, v]) => v !== undefined)));
3955
+ for (const m of ghostMats.values()) {
3956
+ m.opacity = ghostOpts.opacity;
3957
+ const u = m.userData.ldrGhost;
3958
+ u.ldrGhostTint.value.set(ghostOpts.color);
3959
+ u.ldrGhostMix.value = ghostOpts.whiten;
3960
+ }
3961
+ if (!ghostOn) {
3962
+ syncGhost();
3963
+ return ghostBuild ?? Promise.resolve();
3964
+ }
3965
+ if (shownStep == null && !ghost)
3966
+ return Promise.resolve();
3967
+ const b = buildGhost();
3968
+ syncGhost();
3969
+ return b;
3810
3970
  },
3811
3971
  setSide: (s) => {
3812
3972
  side = s;
@@ -3820,7 +3980,7 @@ function createLdrObjectInner(instances, pack, options, progressive) {
3820
3980
  object.updateMatrixWorld(true);
3821
3981
  target.makeEmpty();
3822
3982
  object.traverse((x) => {
3823
- if (x.isInstancedMesh && x.count && !x.userData.ldrLod) {
3983
+ if (x.isInstancedMesh && x.count && !x.userData.ldrLod && !x.userData.ldrGhost) {
3824
3984
  x.computeBoundingBox();
3825
3985
  const b = x.boundingBox.clone().applyMatrix4(x.matrixWorld);
3826
3986
  target.union(b);
@@ -3828,7 +3988,10 @@ function createLdrObjectInner(instances, pack, options, progressive) {
3828
3988
  });
3829
3989
  return target;
3830
3990
  },
3831
- dispose: disposeCur
3991
+ dispose: () => {
3992
+ disposeGhost();
3993
+ disposeCur();
3994
+ }
3832
3995
  });
3833
3996
  };
3834
3997
  if (!progressive) {
@@ -3854,10 +4017,10 @@ function createLdrObjectInner(instances, pack, options, progressive) {
3854
4017
  return finish();
3855
4018
  })();
3856
4019
  }
3857
- // ../../../../../../../tmp/ldr-build-tYthc8/src/parts-cdn.ts
4020
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/parts-cdn.ts
3858
4021
  import { decompress as decompress2 } from "fzstd";
3859
4022
 
3860
- // ../../../../../../../tmp/ldr-build-tYthc8/src/embedded.ts
4023
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/embedded.ts
3861
4024
  function splitFiles(text, fallback) {
3862
4025
  const files = new Map;
3863
4026
  let cur = null, saw = false;
@@ -3929,7 +4092,7 @@ function embeddedKeys(text, names, fallback = "main.ldr") {
3929
4092
  return out;
3930
4093
  }
3931
4094
 
3932
- // ../../../../../../../tmp/ldr-build-tYthc8/src/parts-cdn.ts
4095
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/parts-cdn.ts
3933
4096
  var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
3934
4097
  var indexCache = new Map;
3935
4098
  var shardCache = new Map;
@@ -4161,10 +4324,10 @@ async function prepareModel(source, o = {}) {
4161
4324
  return { insts, pack, missing, requests, bytes, cull, timings: { fetchModel: t1 - t0, parse: t2 - t1, parts: t3 - t2, ...cull ? { cull: performance.now() - t3 } : {} } };
4162
4325
  }
4163
4326
 
4164
- // ../../../../../../../tmp/ldr-build-tYthc8/src/load-worker.gen.ts
4327
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/load-worker.gen.ts
4165
4328
  var load_worker_gen_default = 'var vt=ArrayBuffer,Z=Uint8Array,de=Uint16Array,Ct=Int16Array;var be=Int32Array,Le=function(e,t,n){if(Z.prototype.slice)return Z.prototype.slice.call(e,t,n);if(t==null||t<0)t=0;if(n==null||n>e.length)n=e.length;var r=new Z(n-t);return r.set(e.subarray(t,n)),r},ce=function(e,t,n,r){if(Z.prototype.fill)return Z.prototype.fill.call(e,t,n,r);if(n==null||n<0)n=0;if(r==null||r>e.length)r=e.length;for(;n<r;++n)e[n]=t;return e},Tt=function(e,t,n,r){if(Z.prototype.copyWithin)return Z.prototype.copyWithin.call(e,t,n,r);if(n==null||n<0)n=0;if(r==null||r>e.length)r=e.length;while(n<r)e[t++]=e[n++]};var Lt=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],J=function(e,t,n){var r=Error(t||Lt[e]);if(r.code=e,Error.captureStackTrace)Error.captureStackTrace(r,J);if(!n)throw r;return r},Ke=function(e,t,n){var r=0,s=0;for(;r<n;++r)s|=e[t++]<<(r<<3);return s},Et=function(e,t){return(e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24)>>>0},St=function(e,t){var n=e[0]|e[1]<<8|e[2]<<16;if(n==3126568&&e[3]==253){var r=e[4],s=r>>5&1,o=r>>2&1,i=r&3,a=r>>6;if(r&8)J(0);var u=6-s,c=i==3?4:i,f=Ke(e,u,c);u+=c;var l=a?1<<a:s,p=Ke(e,u,l)+(a==1&&256),d=p;if(!s){var w=1<<10+(e[5]>>3);d=w+(w>>3)*(e[5]&7)}if(d>2145386496)J(1);var y=new Z((t==1?p||d:t?0:d)+12);return y[0]=1,y[4]=4,y[8]=8,{b:u+l,y:0,l:0,d:f,w:t&&t!=1?t:y.subarray(12),e:d,o:new be(y.buffer,0,3),u:p,c:o,m:Math.min(131072,d)}}else if((n>>4|e[3]<<20)==25481893)return Et(e,4)+8;J(0)},re=function(e){var t=0;for(;1<<t<=e;++t);return t-1},ue=function(e,t,n){var r=(t<<3)+4,s=(e[t]&15)+5;if(s>n)J(3);var o=1<<s,i=o,a=-1,u=-1,c=-1,f=o,l=new vt(512+(o<<2)),p=new Ct(l,0,256),d=new de(l,0,256),w=new de(l,512,o),y=512+(o<<1),L=new Z(l,y,o),g=new Z(l,y+o);while(a<255&&i>0){var m=re(i+1),b=r>>3,h=(1<<m+1)-1,P=(e[b]|e[b+1]<<8|e[b+2]<<16)>>(r&7)&h,A=(1<<m)-1,E=h-i-1,T=P&A;if(T<E)r+=m,P=T;else if(r+=m+1,P>A)P-=E;if(p[++a]=--P,P==-1)i+=P,L[--f]=a;else i-=P;if(!P)do{var B=r>>3;u=(e[B]|e[B+1]<<8)>>(r&7)&3,r+=2,a+=u}while(u==3)}if(a>255||i)J(0);var v=0,F=(o>>1)+(o>>3)+3,Y=o-1;for(var _=0;_<=a;++_){var C=p[_];if(C<1){d[_]=-C;continue}for(c=0;c<C;++c){L[v]=_;do v=v+F&Y;while(v>=f)}}if(v)J(0);for(c=0;c<o;++c){var M=d[L[c]]++,k=g[c]=s-re(M);w[c]=(M<<k)-o}return[r+7>>3,{b:s,s:L,n:g,t:w}]},Pt=function(e,t){var n=0,r=-1,s=new Z(292),o=e[t],i=s.subarray(0,256),a=s.subarray(256,268),u=new de(s.buffer,268);if(o<128){var c=ue(e,t+1,6),f=c[0],l=c[1];t+=o;var p=f<<3,d=e[t];if(!d)J(0);var w=0,y=0,L=l.b,g=L,m=(++t<<3)-8+re(d);for(;;){if(m-=L,m<p)break;var b=m>>3;if(w+=(e[b]|e[b+1]<<8)>>(m&7)&(1<<L)-1,i[++r]=l.s[w],m-=g,m<p)break;b=m>>3,y+=(e[b]|e[b+1]<<8)>>(m&7)&(1<<g)-1,i[++r]=l.s[y],L=l.n[w],w=l.t[w],g=l.n[y],y=l.t[y]}if(++r>255)J(0)}else{r=o-127;for(;n<r;n+=2){var h=e[++t];i[n]=h>>4,i[n+1]=h&15}++t}var P=0;for(n=0;n<r;++n){var A=i[n];if(A>11)J(0);P+=A&&1<<A-1}var E=re(P)+1,T=1<<E,B=T-P;if(B&B-1)J(0);i[r++]=re(B)+1;for(n=0;n<r;++n){var A=i[n];++a[i[n]=A&&E+1-A]}var v=new Z(T<<1),F=v.subarray(0,T),Y=v.subarray(T);u[E]=0;for(n=E;n>0;--n){var _=u[n];ce(Y,n,_,u[n-1]=_+a[n]*(1<<E-n))}if(u[0]!=T)J(0);for(n=0;n<r;++n){var C=i[n];if(C){var M=u[C];ce(F,n,M,u[C]=M+(1<<E-C))}}return[t,{n:Y,b:E,s:F}]},kt=ue(new Z([81,16,99,140,49,198,24,99,12,33,196,24,99,102,102,134,70,146,4]),0,6)[1],It=ue(new Z([33,20,196,24,99,140,33,132,16,66,8,33,132,16,66,8,33,68,68,68,68,68,68,68,68,36,9]),0,6)[1],Bt=ue(new Z([32,132,16,66,102,70,68,68,68,68,36,73,2]),0,5)[1],We=function(e,t){var n=e.length,r=new be(n);for(var s=0;s<n;++s)r[s]=t,t+=1<<e[s];return r},Ee=new Z(new be([0,0,0,0,16843009,50528770,134678020,202050057,269422093]).buffer,0,36),Ft=We(Ee,0),Se=new Z(new be([0,0,0,0,0,0,0,0,16843009,50528770,117769220,185207048,252579084,16]).buffer,0,53),Rt=We(Se,3),le=function(e,t,n){var r=e.length,s=t.length,o=e[r-1],i=(1<<n.b)-1,a=-n.b;if(!o)J(0);var u=0,c=n.b,f=(r<<3)-8+re(o)-c,l=-1;for(;f>a&&l<s;){var p=f>>3,d=(e[p]|e[p+1]<<8|e[p+2]<<16)>>(f&7);u=(u<<c|d)&i,t[++l]=n.s[u],f-=c=n.n[u]}if(f!=a||l+1!=s)J(0)},Dt=function(e,t,n){var r=6,s=t.length,o=s+3>>2,i=o<<1,a=o+i;le(e.subarray(r,r+=e[0]|e[1]<<8),t.subarray(0,o),n),le(e.subarray(r,r+=e[2]|e[3]<<8),t.subarray(o,i),n),le(e.subarray(r,r+=e[4]|e[5]<<8),t.subarray(i,a),n),le(e.subarray(r),t.subarray(a),n)},Ut=function(e,t,n){var r,s=t.b,o=e[s],i=o>>1&3;t.l=o&1;var a=o>>3|e[s+1]<<5|e[s+2]<<13,u=(s+=3)+a;if(i==1){if(s>=e.length)return;if(t.b=s+1,n)return ce(n,e[s],t.y,t.y+=a),n;return ce(new Z(a),e[s])}if(u>e.length)return;if(i==0){if(t.b=u,n)return n.set(e.subarray(s,u),t.y),t.y+=a,n;return Le(e,s,u)}if(i==2){var c=e[s],f=c&3,l=c>>2&3,p=c>>4,d=0,w=0;if(f<2)if(l&1)p|=e[++s]<<4|(l&2&&e[++s]<<12);else p=c>>3;else if(w=l,l<2)p|=(e[++s]&63)<<4,d=e[s]>>6|e[++s]<<2;else if(l==2)p|=e[++s]<<4|(e[++s]&3)<<12,d=e[s]>>2|e[++s]<<6;else p|=e[++s]<<4|(e[++s]&63)<<12,d=e[s]>>6|e[++s]<<2|e[++s]<<10;++s;var y=n?n.subarray(t.y,t.y+t.m):new Z(t.m),L=y.length-p;if(f==0)y.set(e.subarray(s,s+=p),L);else if(f==1)ce(y,e[s++],L);else{var g=t.h;if(f==2){var m=Pt(e,s);d+=s-(s=m[0]),t.h=g=m[1]}else if(!g)J(0);(w?Dt:le)(e.subarray(s,s+=d),y.subarray(L),g)}var b=e[s++];if(b){if(b==255)b=(e[s++]|e[s++]<<8)+32512;else if(b>127)b=b-128<<8|e[s++];var h=e[s++];if(h&3)J(0);var P=[It,Bt,kt];for(var A=2;A>-1;--A){var E=h>>(A<<1)+2&3;if(E==1){var T=new Z([0,0,e[s++]]);P[A]={s:T.subarray(2,3),n:T.subarray(0,1),t:new de(T.buffer,0,1),b:0}}else if(E==2)r=ue(e,s,9-(A&1)),s=r[0],P[A]=r[1];else if(E==3){if(!t.t)J(0);P[A]=t.t[A]}}var B=t.t=P,v=B[0],F=B[1],Y=B[2],_=e[u-1];if(!_)J(0);var C=(u<<3)-8+re(_)-Y.b,M=C>>3,k=0,G=(e[M]|e[M+1]<<8)>>(C&7)&(1<<Y.b)-1;M=(C-=F.b)>>3;var I=(e[M]|e[M+1]<<8)>>(C&7)&(1<<F.b)-1;M=(C-=v.b)>>3;var N=(e[M]|e[M+1]<<8)>>(C&7)&(1<<v.b)-1;for(++b;--b;){var j=Y.s[G],X=Y.n[G],W=v.s[N],S=v.n[N],x=F.s[I],R=F.n[I];M=(C-=x)>>3;var D=1<<x,U=D+((e[M]|e[M+1]<<8|e[M+2]<<16|e[M+3]<<24)>>>(C&7)&D-1);M=(C-=Se[W])>>3;var H=Rt[W]+((e[M]|e[M+1]<<8|e[M+2]<<16)>>(C&7)&(1<<Se[W])-1);M=(C-=Ee[j])>>3;var z=Ft[j]+((e[M]|e[M+1]<<8|e[M+2]<<16)>>(C&7)&(1<<Ee[j])-1);if(M=(C-=X)>>3,G=Y.t[G]+((e[M]|e[M+1]<<8)>>(C&7)&(1<<X)-1),M=(C-=S)>>3,N=v.t[N]+((e[M]|e[M+1]<<8)>>(C&7)&(1<<S)-1),M=(C-=R)>>3,I=F.t[I]+((e[M]|e[M+1]<<8)>>(C&7)&(1<<R)-1),U>3)t.o[2]=t.o[1],t.o[1]=t.o[0],t.o[0]=U-=3;else{var V=U-(z!=0);if(V){if(U=V==3?t.o[0]-1:t.o[V],V>1)t.o[2]=t.o[1];t.o[1]=t.o[0],t.o[0]=U}else U=t.o[0]}for(var A=0;A<z;++A)y[k+A]=y[L+A];k+=z,L+=z;var O=k-U;if(O<0){var K=-O,q=t.e+O;if(K>H)K=H;for(var A=0;A<K;++A)y[k+A]=t.w[q+A];k+=K,H-=K,O=0}for(var A=0;A<H;++A)y[k+A]=y[O+A];k+=H}if(k!=L)while(L<y.length)y[k++]=y[L++];else k=y.length;if(n)t.y+=k;else y=Le(y,0,k)}else if(n){if(t.y+=p,L)for(var A=0;A<p;++A)y[A]=y[L+A]}else if(L)y=Le(y,L);return t.b=u,y}J(2)},Ot=function(e,t){if(e.length==1)return e[0];var n=new Z(t);for(var r=0,s=0;r<e.length;++r){var o=e[r];n.set(o,s),s+=o.length}return n};function ye(e,t){var n=[],r=+!t,s=0,o=0;for(;e.length;){var i=St(e,r||t);if(typeof i=="object"){if(r){if(t=null,i.w.length==i.u)n.push(t=i.w),o+=i.u}else n.push(t),i.e=0;for(;!i.l;){var a=Ut(e,i,t);if(!a)J(5);if(t)i.e=i.y;else n.push(a),o+=a.length,Tt(i.w,0,a.length),i.w.set(a,i.w.length-a.length)}s=i.b+i.c*4}else s=i;e=e.subarray(s)}return Ot(n,o)}async function Nt(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),n=(r)=>r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);if(t[0]===40&&t[1]===181&&t[2]===47&&t[3]===253)return n(ye(t));if(t[0]===31&&t[1]===139)return new Response(new Blob([t]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();return n(t)}async function Xe(e){return new TextDecoder().decode(await Nt(e))}var Ze=(e)=>decodeURIComponent(e.split(/[?#]/)[0].split("/").pop()||"main.ldr").replace(/\\.(zst|gz)$/i,"")||"main.ldr";function xe(e){let t=new DataView(e).getUint32(0,!0),n=JSON.parse(new TextDecoder().decode(new Uint8Array(e,4,t))),r=4+t;return{header:n,arr:(o)=>o&&(o[2]==="f32"?new Float32Array(e,r+o[0],o[1]):o[2]==="u16"?new Uint16Array(e,r+o[0],o[1]):o[2]==="u8"?new Uint8Array(e,r+o[0],o[1]):new Uint32Array(e,r+o[0],o[1])),bytes:e.byteLength,buffer:e}}var Q=(e)=>e.trim().toLowerCase().replace(/\\\\/g,"/").replace(/\\/+/g,"/"),ke=/^[A-Za-z][A-Za-z0-9_]*$/,Pe=new Map;function Ie(e){let t=e.toLowerCase(),n=2166136261;for(let s=0;s<t.length;s++)n^=t.charCodeAt(s),n=Math.imul(n,16777619);let r=-1-(n>>>0&1073741823);if(!Pe.has(r))Pe.set(r,t);return r}function Be(e){let t=e.charCodeAt(0)|32;if(t>=97&&t<=122&&ke.test(e))return Ie(e);if(/^0x/i.test(e))return parseInt(e,16);return+e}var Ye=/^~?\\s*moved\\s+to\\s+(.+)$/i,zt=new Set(["FILE","NOFILE","!DATA","!:","STEP","BFC","ROTSTEP","BUFEXCHG","!TEXMAP"]),st=new Set(["part","subpart","primitive","8_primitive","48_primitive","shortcut","helper"]),$t=new Set(["model","submodel","configuration"]),jt=/^(?:!?LDRAW_ORG|Unofficial|Official\\s+LCAD)\\s+(\\S+)/i;function Je(e){let t=jt.exec(e);if(!t)return;let n=t[1].toLowerCase().replace(/^unofficial_/,"");return st.has(n)||$t.has(n)?n:void 0}function Vt(e){let t=[],n=0;while(n<e.length){while(e[n]===" "||e[n]==="\\t")n++;if(n>=e.length)break;if(e[n]===\'"\'){let r="";n++;while(n<e.length&&e[n]!==\'"\'){if(e[n]==="\\\\"&&n+1<e.length)n++;r+=e[n++]}n++,t.push(r)}else{let r=n;while(r<e.length&&e[r]!==" "&&e[r]!=="\\t")r++;t.push(e.slice(n,r)),n=r}}return t}function _t(e,t=!1){let n=/^\\s*(\\S+)\\s+(.*)$/.exec(e);if(!n)return null;let r=n[1].toUpperCase(),s=r==="PLANAR"?9:r==="CYLINDRICAL"?10:r==="SPHERICAL"?11:0;if(!s)return null;let o=n[2].trim().split(/\\s+/);if(o.length<s+1)return null;let i=o.slice(0,s).map(Number);if(!i.every(Number.isFinite))return null;let a=n[2].trim();for(let l=0;l<s;l++)a=a.replace(/^\\S+\\s*/,"");let u=Vt(a);if(!u.length)return null;let c={method:r,p1:i.slice(0,3),p2:i.slice(3,6),p3:i.slice(6,9),texture:u[0]};if(s>=10)c.a=i[9];if(s===11)c.b=i[10];let f=u.findIndex((l,p)=>p>0&&l.toUpperCase()==="GLOSSMAP");if(f>0&&u[f+1])c.glossmap=u[f+1];if(t)c.next=!0;return c}var Ht=(e)=>{let t=e.replace(/[^A-Za-z0-9+/]/g,""),n=t+"=".repeat((4-t.length%4)%4),r=atob(n),s=new Uint8Array(r.length);for(let o=0;o<r.length;o++)s[o]=r.charCodeAt(o);return s};function Gt(e){let t=e.length,n=1,r=(c)=>c===32||c===9,s=()=>{while(n<t&&r(e.charCodeAt(n)))n++;let c=n;while(n<t&&!r(e.charCodeAt(n)))n++;return c<n?e.slice(c,n):null},o=s();if(o===null)return null;let i=Array(12);for(let c=0;c<12;c++){let f=s();if(f===null)return null;i[c]=+f}while(n<t&&r(e.charCodeAt(n)))n++;if(n>=t)return null;let a=e.slice(n),u=/[ \\t]{2,}|\\t/.test(a)?a.split(/\\s+/).join(" "):a;return{t:1,color:Be(o),m:i,file:Q(u)}}function qe(e){let t=+e[0];if(!(t>=1&&t<=5)||e.length<2)return null;let n=Be(e[1]),r=e.slice(2).map(Number);if(t===1)return{t:1,color:n,m:r.slice(0,12),file:Q(e.slice(14).join(" "))};if(t===2)return{t:2,color:n,p:r.slice(0,6)};if(t===3)return{t:3,color:n,p:r.slice(0,9)};if(t===4)return{t:4,color:n,p:r.slice(0,12)};return{t:5,color:n,p:r.slice(0,12)}}function ot(e,t="main.ldr",n={}){let r=!!n.geometryText,s=new Map,o=null,i="",a,u=null,c=[],f=null,l=()=>{if(!u)return;let m=Ht(u.chunks.join("")),b=m[0]===137&&m[1]===80&&m[2]===78&&m[3]===71;(a??=new Map).set(Q(u.name),{name:u.name,bytes:m,...b?{mime:"image/png"}:{}}),u=null},p=!0,d=(m)=>{if(l(),o={name:Q(m),cmds:[]},s.set(o.name,o),!i)i=o.name;c=[],f=null,p=!0},w=!1,y=!1,L=()=>{if(y)return;y=!0,s.clear(),o=null,i=""},g=(m,b)=>{if(f){m.tex=f,f=null;return}let h=c[c.length-1];if(!h)return;if(h.fallback){if(!b)m.fallback=!0}else m.tex=h.map};for(let m of e.split(`\n`)){let b=m.trim();if(!b)continue;if(r&&b.charCodeAt(0)>=50&&b.charCodeAt(0)<=53&&(b.charCodeAt(1)===32||b.charCodeAt(1)===9)){if(u||w)continue;if(!o)d(t);let E=b.slice(2).trimStart(),T=E.search(/\\s/),B={t:b.charCodeAt(0)-48,color:Be(T<0?E:E.slice(0,T)),p:[],src:b};g(B,!1),o.cmds.push(B),p=!1;continue}if(b.charCodeAt(0)===48&&(b.charCodeAt(1)===32||b.charCodeAt(1)===9)){let E=2;while(b.charCodeAt(E)===32||b.charCodeAt(E)===9)E++;let T=E;while(T<b.length&&b.charCodeAt(T)!==32&&b.charCodeAt(T)!==9)T++;let B=b.slice(E,T);if(!zt.has(B)){if(w||u)continue;if(!o)d(t);let v=b.slice(E),F={t:0,text:v};if(B.charCodeAt(0)===33)F.meta=B;if(f=null,p&&!o.org){let _=Je(v);if(_)o.org=_}let Y=v.match(Ye);if(Y&&!o.movedTo){let _=Y[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(_))_+=".dat";o.movedTo=Q(_)}o.cmds.push(F);continue}}if(b.charCodeAt(0)===49&&(b.charCodeAt(1)===32||b.charCodeAt(1)===9)&&!u&&!w){let E=Gt(b);if(E){if(!o)d(t);g(E,!1),o.cmds.push(E),p=!1;continue}}let h=b.split(/\\s+/);if(+h[0]===0){let E=b.slice(1).trim();if(h[1]==="FILE"){L(),w=!1,d(E.slice(5));continue}if(h[1]==="NOFILE"){l(),o=null,w=!0;continue}if(h[1]==="!DATA"){L(),l(),o=null,w=!1,u={name:E.slice(5).trim(),chunks:[]};continue}if(w)continue;if(u){if(h[1]==="!:")u.chunks.push(h.slice(2).join(""));continue}if(!o)d(t);let T={t:0,text:E};if(h[1]==="STEP")T.step=!0,c=[],f=null;else if(h[1]==="BFC")T.bfc=h.slice(2).join(" ");else if(h[1]==="ROTSTEP")if(T.meta="ROTSTEP",T.step=!0,c=[],f=null,(h[2]??"").toUpperCase()==="END")T.rotstep={x:0,y:0,z:0,mode:"END"};else{let v=(h[5]??"REL").toUpperCase();T.rotstep={x:+h[2]||0,y:+h[3]||0,z:+h[4]||0,mode:["REL","ABS","ADD"].includes(v)?v:"REL"}}else if(h[1]==="BUFEXCHG"){T.meta="BUFEXCHG";let v=(h[2]??"").toUpperCase();T.bufexchg={op:v==="RETRIEVE"?"RETRIEVE":"STORE",buf:h[3]??"A"}}else if(h[1]?.startsWith("!"))T.meta=h[1];if(p&&!o.org){let v=Je(E);if(v)o.org=v}if(h[1]==="!TEXMAP"){let v=(h[2]??"").toUpperCase();if(f=null,v==="START"||v==="NEXT"){let F=_t(E.replace(/^!TEXMAP\\s+\\S+/i,""),v==="NEXT");if(T.texmap={op:v,...F?{map:F}:{}},F)if((o.texmaps??=[]).push(F),v==="START")c.push({map:F,fallback:!1});else f=F}else if(v==="FALLBACK"){T.texmap={op:v};let F=c[c.length-1];if(F)F.fallback=!0}else if(v==="END")T.texmap={op:v},c.pop()}else if(h[1]==="!:"){f=null;let v=qe(h.slice(2));if(v)g(v,!0),T.geom=v}else f=null;let B=E.match(Ye);if(B&&!o.movedTo){let v=B[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(v))v+=".dat";o.movedTo=Q(v)}o.cmds.push(T);continue}if(u||w)continue;if(!o)d(t);let A=qe(h);if(!A)continue;g(A,!1),o.cmds.push(A),p=!1}return l(),a?{main:i,files:s,data:a}:{main:i,files:s}}var yn=Math.PI/180;function it(e,t){let n=(r)=>[t[3]*r[0]+t[4]*r[1]+t[5]*r[2]+t[0],t[6]*r[0]+t[7]*r[1]+t[8]*r[2]+t[1],t[9]*r[0]+t[10]*r[1]+t[11]*r[2]+t[2]];return{...e,p1:n(e.p1),p2:n(e.p2),p3:n(e.p3)}}function at(e,t){let[n,r,s,o,i,a,u,c,f,l,p,d]=e,[w,y,L,g,m,b,h,P,A,E,T,B]=t;return[o*w+i*y+a*L+n,u*w+c*y+f*L+r,l*w+p*y+d*L+s,o*g+i*h+a*E,o*m+i*P+a*T,o*b+i*A+a*B,u*g+c*h+f*E,u*m+c*P+f*T,u*b+c*A+f*B,l*g+p*h+d*E,l*m+p*P+d*T,l*b+p*A+d*B]}var Fe=[0,0,0,1,0,0,0,1,0,0,0,1];var Qe=new WeakMap,Kt=/^(s|8|48)\\//;function Re(e,t){let n=e.files.get(Q(t));if(!n)return"part";let r=Qe.get(n);if(r)return r;if(n.org)r=st.has(n.org)?"part":"model";else if(n.name===e.main)r="model";else r=n.cmds.some((s)=>s.t>=2||s.t===0&&!!s.geom||s.t===1&&Kt.test(s.file))?"part":"model";return Qe.set(n,r),r}var et=new WeakMap;function lt(e){let t=et.get(e);if(t)return t;t=[];let n=0;for(let r of e.cmds){if(r.t===0&&r.step){n++;continue}if((r.t>=2||r.t===0&&r.geom&&r.geom.t>=2)&&t[t.length-1]!==n)t.push(n)}return et.set(e,t),t}var tt=(e)=>e>16777215?"0x"+e.toString(16).toUpperCase():e<0?Pe.get(e)??String(e):String(e),Wt=(e)=>e.t===0?"0 "+e.text:e.t===1?`1 ${tt(e.color)} ${e.m.join(" ")} ${e.file}`:e.src?e.src:`${e.t} ${tt(e.color)} ${e.p.join(" ")}`,De=(e,t)=>`${Q(e)}#${t}`;function Xt(e,t){let n=[],r=0,s=(o)=>!!o&&o.t===0&&o.texmap?.op==="NEXT";for(let o of e.cmds){if(o.t===0){if(o.step){r++;continue}if(o.bfc!==void 0){n.push(o);continue}if(r!==t)continue;if(o.texmap)n.push(o);else if(o.geom){if(o.geom.t>=2)n.push(o);else if(s(n[n.length-1]))n.pop()}continue}if(r!==t)continue;if(o.t===1){if(s(n[n.length-1]))n.pop();continue}n.push(o)}return{name:De(e.name,t),cmds:n}}function ct(e,t){return[`0 ldr: own geometry of ${e.name}, step ${t}`,...Xt(e,t).cmds.map(Wt)].join(`\n`)+`\n`}function Zt(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")}function ut(e){let[t,n,r,s,o,i,a,u,c,f,l,p]=e,d=u*p-c*l,w=-(a*p-c*f),y=a*l-u*f,L=s*d+o*w+i*y;if(!Number.isFinite(L)||Math.abs(L)<0.000000000001)return null;let g=1/L,m=[d*g,-(o*p-i*l)*g,(o*c-i*u)*g,w*g,(s*p-i*f)*g,-(s*c-i*a)*g,y*g,-(s*l-o*f)*g,(s*u-o*a)*g];return[-(m[0]*t+m[1]*n+m[2]*r),-(m[3]*t+m[4]*n+m[5]*r),-(m[6]*t+m[7]*n+m[8]*r),...m]}var Yt=(e)=>String(+e.toFixed(6)||0),nt=(e)=>\'"\'+e.replace(/\\\\/g,"\\\\\\\\").replace(/"/g,"\\\\\\"")+\'"\';function ft(e,t){let n=[...t.p1,...t.p2,...t.p3,...t.method!=="PLANAR"?[t.a??360]:[],...t.method==="SPHERICAL"?[t.b??180]:[]].map(Yt).join(" "),r=`0 ldr: ${e} with a model-level !TEXMAP\n0 BFC CERTIFY CCW\n0 !TEXMAP START ${t.method} ${n} ${nt(t.texture)}${t.glossmap?" GLOSSMAP "+nt(t.glossmap):""}\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 ${Q(e)}\n0 !TEXMAP END\n`;return{name:`${Q(e)}#tex-${Zt(r)}`,source:r}}var Jt=(e,t)=>{let n=[,,,,,,,,,];for(let r=0;r<3;r++)for(let s=0;s<3;s++)n[r*3+s]=e[r*3]*t[s]+e[r*3+1]*t[3+s]+e[r*3+2]*t[6+s];return n};function qt(e,t,n){let r=Math.PI/180,s=Math.sin(e*r),o=Math.cos(e*r),i=Math.sin(t*r),a=Math.cos(t*r),u=Math.sin(n*r),c=Math.cos(n*r);return[a*c,-a*u,i,o*u+s*i*c,o*c-s*i*u,-s*a,s*u-o*i*c,s*c+o*i*u,o*a]}var rt=new WeakMap;function pt(e){let t=rt.get(e);if(t)return t;let n=[],r=null;for(let s of e.cmds){if(s.t!==0||!s.step)continue;let o=s.rotstep;if(o)if(o.mode==="END")r=null;else{let i=qt(o.x,o.y,o.z);r=o.mode==="ABS"?{abs:!0,m:i,rotstep:o}:o.mode==="ADD"&&r?{abs:r.abs,m:Jt(r.m,i),rotstep:o}:{abs:!1,m:i,rotstep:o}}n.push(r)}return n.push(r),rt.set(e,n),n}var mt=999999,gt=(e)=>e.map((t)=>String(t).padStart(6,"0")).join(".")+"~";function Qt(e,t={}){let n=[],r=t.maxDepth??64,s=t.looseGeometry!==!1,o=!!t.textures,i=!!t.callouts,a=new Map,u=0,c=(l,p)=>{let d=l.name+"#"+p,w=a.get(d);if(!w){let y;w=Object.assign(()=>y??=ct(l,p),{file:l,step:p}),a.set(d,w)}return w},f=(l,p,d,w,y,L,g,m,b=null,h=[],P=[],A=void 0,E=null)=>{let T=l.files.get(p);if(!T||g>r)return;let B=E,v=0,F=g>0?++u:0,Y=i&&F?[...h,F]:h,_=i&&F?[...P,d]:P,C=i&&!b?new Map:null,M=-1,k=0,G=(S,x,R,D,U,H,z)=>{if(M!==v)M=v,k=0;let V=C?.get(v+"|"+x);if(V)return V.n++,f(S,S===l?x:S.main,R,D,y+"/"+x,[...U,mt],g+1,H,[...U,mt],Y,_,z,B);let O=[...U,k++],K=n.length;f(S,S===l?x:S.main,R,D,y+"/"+x,O,g+1,H,b,Y,_,z,B),C?.set(v+"|"+x,{n:1,from:K,to:n.length})},I=pt(T),N=s?lt(T):[],j=0,X=(S,x,R,D,U,H,z,V)=>{if(b)D=b;let O={part:S,color:x,m:R,step:D[0],steps:D,localStep:U,path:y};if(V)O.colour=V;if(F){if(O.sub=F,i)O.subPath=Y,O.subMats=_}if(H)O.embedded=!0;if(z){let q=ft(S,z);O.texPart=q.name,O.texSource=q.source}let K=I[U];if(K)O.view=K;return n.push(O),O},W=(S)=>{while(j<N.length&&N[j]<=S){let x=N[j++];X(De(T.name,x),w,d,[...L,x],x,!1,null,A).source=c(T,x)}};for(let S of T.cmds){if(S.t===0&&S.step){v++;continue}let x=S;if(x.t>=2||x.t===0&&x.geom&&x.geom.t>=2){W(v);continue}if(x.t===0){if(x.meta==="!COLOUR"){let q=tn(x.text);if(q&&q.code!==16&&q.code!==24)(B=new Map(B??[])).set(q.code,q);continue}if(o&&x.geom?.t===1)x=x.geom;else continue}if(x.t!==1)continue;if(o&&x.fallback)continue;let R=x.color===16?w:x.color,D=x.color===16?A:B?.get(x.color),U=at(d,x.m),H=[...L,v],z=o?x.tex??m:null,V=z?ut(x.m):null,O=z&&V?it(z,V):null;if(l.files.has(x.file)){if(Re(l,x.file)==="model"){G(l,x.file,U,R,H,O,D);continue}X(x.file,R,U,H,v,!0,O,D);continue}let K=t.resolveModel?.(x.file);if(K){G(K,x.file,U,R,H,O,D);continue}X(x.file,R,U,H,v,!1,O,D)}if(W(1/0),C){for(let S of C.values())if(S.n>1)for(let x=S.from;x<S.to;x++)n[x].mult??=S.n}};if(Re(e,e.main)==="part"){if(e.files.get(e.main))n.push({part:e.main,color:16,m:[...Fe],step:0,steps:[0],localStep:0,path:e.main,embedded:!0});return n}return f(e,e.main,Fe,16,e.main,[],0,null),n}function dt(e,t="main.ldr",n){return Qt(ot(e,t,{geometryText:!0}),n)}var en=new Set(["CHROME","PEARLESCENT","RUBBER","MATTE_METALLIC","METAL","MATERIAL"]);function Ue(e){if(!e)return null;if(e.startsWith("#")&&/^#[0-9A-Fa-f]{6}$/.test(e))return e.toUpperCase();if(/^0x[0-9A-Fa-f]{6}$/i.test(e))return("#"+e.slice(2)).toUpperCase();return null}function ht(e,t){let n={value:"#FFFFFF",fraction:0.5};while(t<e.length){let r=e[t].toUpperCase(),s=e[t+1];if(r==="VALUE"){let o=Ue(s);if(o)n.value=o;t+=2}else if(r==="ALPHA")n.alpha=+s,t+=2;else if(r==="LUMINANCE")n.luminance=+s,t+=2;else if(r==="FRACTION")n.fraction=+s,t+=2;else if(r==="VFRACTION")n.vfraction=+s,t+=2;else if(r==="SIZE")n.size=+s,t+=2;else if(r==="MINSIZE")n.minsize=+s,t+=2;else if(r==="MAXSIZE")n.maxsize=+s,t+=2;else break}return{grain:n,next:t}}function tn(e){let t=e.indexOf("!COLOUR");if(t<0)return null;let n=e.slice(t+7).trim().split(/\\s+/).filter(Boolean);if(n.length<2)return null;let r=n[0],s=NaN,o="#FF00FF",i="#333333",a=255,u=0,c={type:"default"},f=1;while(f<n.length){let l=n[f].toUpperCase(),p=n[f+1];if(l==="CODE")s=p!==void 0&&ke.test(p)?Ie(p):p!==void 0&&/^\\d+$/.test(p)?+p:NaN,f+=2;else if(l==="VALUE"){let d=Ue(p);if(d)o=d;f+=2}else if(l==="EDGE")i=Ue(p)??p,f+=2;else if(l==="ALPHA")a=+p,f+=2;else if(l==="LUMINANCE")u=+p,f+=2;else if(l==="CHROME")c={type:"chrome"},f+=1;else if(l==="PEARLESCENT")c={type:"pearlescent"},f+=1;else if(l==="RUBBER")c={type:"rubber"},f+=1;else if(l==="MATTE_METALLIC")c={type:"matte_metallic"},f+=1;else if(l==="METAL")c={type:"metal"},f+=1;else if(l==="MATERIAL"){let d=(n[f+1]||"").toUpperCase();if(d==="GLITTER"){let{grain:w,next:y}=ht(n,f+2);c={type:"glitter",material:w},f=y}else if(d==="SPECKLE"){let{grain:w,next:y}=ht(n,f+2);c={type:"speckle",material:w},f=y}else if(d==="FABRIC"){let w=(n[f+2]||"").toUpperCase(),y=["VELVET","CANVAS","STRING","FUR"].includes(w)?w.toLowerCase():void 0;c={type:"fabric",kind:y},f+=y?3:2}else f=n.length}else if(en.has(l))f+=1;else f+=1}if(Number.isNaN(s)||!o)return null;return{code:s,name:r,hex:o,edge:i,alpha:Number.isFinite(a)?a:255,luminance:Number.isFinite(u)?u:0,finish:c}}function nn(e){let t=Math.max(0,Math.min(1,(e.alpha??255)/255)),n=t<1,r=Math.max(0,Math.min(1,(e.luminance??0)/255)),s={opacity:t,transparent:n,depthWrite:!n,emissive:r,clearcoat:0,clearcoatRoughness:0,sheen:0,sheenRoughness:0};switch(e.finish?.type??"default"){case"chrome":return{...s,metalness:1,roughness:0,finish:"chrome"};case"pearlescent":return{...s,metalness:0.25,roughness:0.3,clearcoat:0.5,clearcoatRoughness:0.25,sheen:0.4,sheenRoughness:0.35,finish:"pearlescent"};case"rubber":return{...s,metalness:0,roughness:0.9,finish:"rubber"};case"matte_metallic":return{...s,metalness:0.4,roughness:0.8,finish:"matte_metallic"};case"metal":return{...s,metalness:0.85,roughness:0.2,finish:"metal"};case"glitter":{let i=e.finish.material,a=i.size??(i.minsize!=null&&i.maxsize!=null?(i.minsize+i.maxsize)/2:1);return{...s,metalness:0.35,roughness:0.25,clearcoat:1,clearcoatRoughness:0.08,particleHex:i.value,particleFraction:i.fraction,particleSize:a,finish:"glitter"}}case"speckle":{let i=e.finish.material,a=i.size??(i.minsize!=null&&i.maxsize!=null?(i.minsize+i.maxsize)/2:1);return{...s,metalness:0.2,roughness:0.55,particleHex:i.value,particleFraction:i.fraction,particleSize:a,finish:"speckle"}}case"fabric":return{...s,metalness:0,roughness:0.85,sheen:0.65,sheenRoughness:0.75,finish:"fabric"};default:return{...s,metalness:0,roughness:0.45,finish:"default"}}}function Oe(e){let t=nn(e),n=!t.transparent?"op":t.opacity>=0.75?"a200":t.opacity>=0.4?"a128":`a${Math.round(t.opacity*255)}`,r=t.emissive>0?`L${Math.round(t.emissive*16)}`:"",s=`${t.finish}:${n}${r}`;if(t.particleHex)s+=`:${t.particleHex}:${(t.particleFraction??0).toFixed(2)}`;return s}function rn(e,t){let n=new Map,r=null,s=!1;for(let o of e.split(/\\r?\\n/)){let i=/^\\s*0\\s+FILE\\s+(.+)$/i.exec(o);if(i){if(!s)n.clear();s=!0,r=[],n.set(Q(i[1]),r);continue}if(/^\\s*0\\s+(NOFILE|!DATA)(\\s|$)/i.test(o)){if(!s)n.clear();s=!0,r=null;continue}if(!r){if(s)continue;r=[],n.set(Q(t),r)}let a=o.trim().replace(/\\s+/g," ");if(a)r.push(a)}return n}var sn=(e)=>{if(!e.startsWith("1 "))return null;let t=e.split(" ");return t.length>=15?Q(t.slice(14).join(" ")):null};function on(e){let t=2166136261,n=1523705862;for(let r=0;r<e.length;r++){let s=e.charCodeAt(r);t=Math.imul(t^s,16777619),n=Math.imul(n^s,16777629)^n>>>15}return(t>>>0).toString(16).padStart(8,"0")+(n>>>0).toString(16).padStart(8,"0")}function bt(e,t,n="main.ldr"){let r=rn(e,n),s=new Map;for(let o of t){let i=Q(o);if(!r.has(i)||s.has(i))continue;let a=new Set([i]),u=[i];while(u.length)for(let f of r.get(u.pop())){let l=sn(f);if(l&&r.has(l)&&!a.has(l))a.add(l),u.push(l)}let c=[i,...[...a].filter((f)=>f!==i).sort()].map((f)=>"0 FILE "+(f===i?"":f)+`\n`+r.get(f).join(`\n`)).join(`\n`);s.set(i,`emb/${on(c)}.dat`)}return s}var yt=(e,t=0)=>Math.abs(e[t+7]-1)<0.001&&Math.abs(e[t+4])<0.001&&Math.abs(e[t+10])<0.001,xt=new WeakMap;function Ne(e,t){let n=xt.get(e);if(!n)xt.set(e,n=new Map);let r=n.get(t);if(r!==void 0)return r;let s=e.parts[t];if(!s)return n.set(t,null),null;let o=s.studs.length,i=new Float64Array(o*12),a=[],u=[];s.studs.forEach((p,d)=>{a.push(p[0]),u.push(p[1]);for(let w=0;w<12;w++)i[d*12+w]=p[2+w]});let c=null,f=0,l=0;if(s.mask){f=s.mask[0],l=s.mask[1];let p=s.mask[2];c=new Uint8Array(p.length);for(let d=0;d<p.length;d++)c[d]=p.charCodeAt(d)===49?1:0}return n.set(t,r={nStuds:o,studM:i,kind:a,color:u,mask:c,nx:f,nz:l}),r}var ie=1073741824;class ze{a;b;c;vals;used;mask;size=0;constructor(e=1024){let t=1024;while(t<e*2)t*=2;this.a=new Int32Array(t),this.b=new Int32Array(t),this.c=new Int32Array(t),this.vals=new Int32Array(t),this.used=new Uint8Array(t),this.mask=t-1}slot(e,t,n){let r=Math.imul(e,2654435761)^Math.imul(t,2246822507)^Math.imul(n,3266489909);return r^=r>>>15,r=Math.imul(r,739982445),r^=r>>>12,r&this.mask}get(e,t,n){let r=this.slot(e,t,n),s=this.used,o=this.a,i=this.b,a=this.c;for(;;){if(!s[r])return-1;if(o[r]===e&&i[r]===t&&a[r]===n)return this.vals[r];r=r+1&this.mask}}put(e,t,n,r){if((this.size+1)*2>this.used.length)this.grow();let s=this.slot(e,t,n),o=this.used,i=this.a,a=this.b,u=this.c;for(;;){if(!o[s])return o[s]=1,i[s]=e,a[s]=t,u[s]=n,this.vals[s]=r,this.size++,-1;if(i[s]===e&&a[s]===t&&u[s]===n){let c=this.vals[s];return this.vals[s]=r,c}s=s+1&this.mask}}grow(){let{a:e,b:t,c:n,vals:r,used:s}=this,o=s.length*2;this.a=new Int32Array(o),this.b=new Int32Array(o),this.c=new Int32Array(o),this.vals=new Int32Array(o),this.used=new Uint8Array(o),this.mask=o-1,this.size=0;for(let i=0;i<s.length;i++)if(s[i])this.put(e[i],t[i],n[i],r[i])}}var we=(e,t,n)=>e>-ie&&e<ie&&t>-ie&&t<ie&&n>-ie&&n<ie,fe=2147483647;function an(e,t,n){let s=[],o=[],i=[],a=[],u=[],c=[],f=[],l=[],p=new ze(e.length*2),d=[],w=[];for(let C=0;C<e.length;C++){let M=e[C],k=M.m,G=t.parts[M.part];if(!G||!G.mask||!yt(k))continue;let I=G.bbox,N=1/0,j=-1/0,X=1/0,W=-1/0;for(let R=0;R<2;R++)for(let D=0;D<2;D++){let U=R?I[3]:I[0],H=D?I[5]:I[2],z=k[0]+k[3]*U+k[5]*H,V=k[2]+k[9]*U+k[11]*H;if(z<N)N=z;if(z>j)j=z;if(V<X)X=V;if(V>W)W=V}let S=u.length;s.push(N),o.push(j),i.push(X),a.push(W),u.push(C),c.push(Ne(t,M.part)),f.push(I[0]),l.push(I[2]);let x=Math.round((k[1]+I[4])*2);for(let R=Math.floor(N/40);R<=Math.floor(j/40);R++)for(let D=Math.floor(X/40);D<=Math.floor(W/40);D++){if(!we(x,R,D))continue;let U=w.length;w.push(S),d.push(p.put(x,R,D,U))}}let y=[0,5,-5,5,-5],L=[0,5,5,-5,-5],g=NaN,m=NaN,b=NaN,h=-1,P=(C,M,k,G)=>{let I=Math.round(M*2),N=Math.floor(C/40),j=Math.floor(k/40);if(!we(I,N,j))return fe;let X=fe;if(I!==g||N!==m||j!==b)g=I,m=N,b=j,h=p.get(I,N,j);for(let W=h;W>=0;W=d[W]){let S=w[W];if(u[S]===G||!(C-6>=s[S]-0.5&&C+6<=o[S]+0.5&&k-6>=i[S]-0.5&&k+6<=a[S]+0.5))continue;let x=e[u[S]].m,R=c[S],D=f[S],U=l[S],H=C-x[0],z=M-x[1],V=k-x[2],O=x[3]*H+x[6]*z+x[9]*V,K=x[5]*H+x[8]*z+x[11]*V,{nx:q,nz:se,mask:ae}=R,oe=!0;for(let ee=0;ee<5;ee++){let te=Math.floor((O+y[ee]-D)/20),ne=Math.floor((K+L[ee]-U)/20);if(te<0||ne<0||te>=q||ne>=se||ae[te*se+ne]!==1){oe=!1;break}}if(oe){if(!n)return 0;let ee=n[u[S]];if(ee<X)X=ee}}return X},A=0;for(let C of e){let M=Ne(t,C.part);if(M)A+=M.nStuds}let E=new Uint8Array(A),T=new Uint8Array(A),B=new ze(A),v=0,F=n?new Int32Array(A).fill(fe):void 0;for(let C=0,M=0;C<e.length;C++){let k=e[C],G=Ne(t,k.part);if(!G)continue;let I=k.m,N=G.studM,j=I[0],X=I[1],W=I[2],S=I[3],x=I[4],R=I[5],D=I[6],U=I[7],H=I[8],z=I[9],V=I[10],O=I[11];for(let K=0;K<G.nStuds;K++,M++){let q=K*12,se=N[q+4],ae=N[q+7],oe=N[q+10];if(!(Math.abs(D*se+U*ae+H*oe-1)<0.001&&Math.abs(S*se+x*ae+R*oe)<0.001&&Math.abs(z*se+V*ae+O*oe)<0.001))continue;T[M]=1;let ee=N[q],te=N[q+1],ne=N[q+2],$e=j+S*ee+x*te+R*ne,je=X+D*ee+U*te+H*ne,Ve=W+z*ee+V*te+O*ne,_e=P($e,je,Ve,C);if(_e!==fe){if(E[M]=1,v++,F)F[M]=_e}let me=Math.round($e),he=Math.round(je),ge=Math.round(Ve);if(!we(me,he,ge))continue;if(!n){B.put(me,he,ge,1);continue}let He=n[C],Ge=B.get(me,he,ge);if(Ge<0||He<Ge)B.put(me,he,ge,He)}}let Y=new Uint8Array(e.length),_=n?new Int32Array(e.length).fill(fe):void 0;for(let C=0;C<e.length;C++){let M=e[C],k=t.parts[M.part];if(!k||!k.under||!yt(M.m))continue;let G=k.bbox,I=Math.round((G[3]-G[0])/20),N=Math.round((G[5]-G[2])/20);if(!I||!N||I*N>4096)continue;let j=M.m,X=!0,W=0;for(let S=0;S<I&&X;S++)for(let x=0;x<N;x++){let R=G[0]+10+20*S,D=G[2]+10+20*x,U=j[0]+j[3]*R+j[5]*D,H=j[2]+j[9]*R+j[11]*D,z=Math.round(U),V=Math.round(j[1]+G[4]),O=Math.round(H),K=we(z,V,O)?B.get(z,V,O):-1;if(K<0){X=!1;break}if(K>W)W=K}if(X){if(Y[C]=1,_)_[C]=W}}return{nStuds:A,studHidden:E,studUp:T,underHidden:Y,studsHidden:v,studHideStep:F,underHideStep:_}}function ln(e,t,n){let r=(l)=>n&&l.texPart&&t.parts[l.texPart]?l.texPart:l.part,s=new Map,o=new Map,i=(l)=>{let p=l.colour;if(!p)return String(l.color);let d=o.get(p);if(d!==void 0)return d;let w=t.colorTable?.[l.color],y=w?.hex??t.colors?.[l.color],L=w?Oe({alpha:w.alpha??255,luminance:w.luminance??0,finish:w.finish??{type:"default"}}):"default:op",g=Oe(p);if(d=y&&y.toUpperCase()===p.hex.toUpperCase()&&L===g?String(l.color):p.hex.toUpperCase()+"/"+g,d!==String(l.color))s.set(d,p);return o.set(p,d),d},a=e.map((l)=>({part:r(l),color:i(l),m:l.m,steps:l.steps})),u=a.map((l)=>gt(l.steps)),c=[...new Set(u)].sort(),f=new Map(c.map((l,p)=>[l,p]));return{all:a,stepOf:u.map((l)=>f.get(l)),nSteps:c.length,localColours:s}}function Ae(e,t,n=!0){let r=ln(e,t,n);return an(r.all,t,r.nSteps>1?r.stepOf:void 0)}var Te="https://ldr-demo.vercel.app/cdn/v1/",ve=new Map,Me=new Map;function At(e=Te,t=fetch){let n=ve.get(e);if(!n)n=t(e+"parts.json").then((r)=>{if(!r.ok)throw Error(`ldr: parts CDN index ${r.status} (${e}parts.json)`);return r.json()}),n.catch(()=>ve.delete(e)),ve.set(e,n);return n}var cn=(e)=>Array.isArray(e)&&e.length===3&&typeof e[0]==="number"&&typeof e[1]==="number"&&(e[2]==="f32"||e[2]==="u16"||e[2]==="u8"||e[2]==="u32"),Ce=(e,t)=>cn(e)?[e[0]+t,e[1],e[2]]:Array.isArray(e)?e.map((n)=>Ce(n,t)):e&&typeof e==="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,Ce(r,t)])):e;function un(e,t={}){let n=[],r=0,s={},o={};for(let p of e){let d=p.buffer;if(!d)throw Error("ldr: mergePacks needs packs from decodePack/loadPack");let w=new DataView(d).getUint32(0,!0),y=new Uint8Array(d,4+w),L=r;n.push(y),r+=y.byteLength;let g=(4-r%4)%4;if(g)n.push(new Uint8Array(g)),r+=g;for(let[m,b]of Object.entries(p.header.parts??{}))if(!(m in s))s[m]=Ce(b,L);for(let[m,b]of Object.entries(p.header.studKinds??{}))if(!(m in o))o[m]=Ce(b,L)}let i=e[0]?.header??{version:1,weld:!0},a=new TextEncoder().encode(JSON.stringify({...i,parts:s,studKinds:o,...t})),u=(4-(4+a.length)%4)%4,c=4+a.length+u,f=new Uint8Array(c+r);new DataView(f.buffer).setUint32(0,a.length+u,!0),f.set(a,4),f.fill(32,4+a.length,c);let l=c;for(let p of n)f.set(p,l),l+=p.byteLength;return xe(f.buffer)}async function fn(e,t={}){e=[...e];try{return await wt(e,t)}catch(n){let r=t.cdn??Te,s=t.fetch??fetch;ve.delete(r);let o=(i,a)=>s(i,{...a,cache:"reload"});try{return await wt(e,{...t,fetch:o})}catch{throw n}}}async function wt(e,t){let n=t.cdn??Te,r=t.fetch??fetch,s=t.gap??16384,o=await At(n,r),i=[...new Set([...e].map(Q))],a=[],u=[];for(let g of i){if(Me.has(n+g))continue;let m=o.parts[g];if(m)u.push({name:g,off:m[0],len:m[1],file:m[2]??0});else a.push(g)}u.sort((g,m)=>g.file-m.file||g.off-m.off);let c=[];for(let g of u){let m=c[c.length-1];if(m&&m.file===g.file&&g.off-m.end<=s)m.end=Math.max(m.end,g.off+g.len),m.items.push(g);else c.push({file:g.file,start:g.off,end:g.off+g.len,items:[g]})}let f=0,l=0,p=0,d=new Map,w=async()=>{while(p<c.length){let g=c[p++],m=d.get(g.file);if(m)m=m.subarray(g.start,g.end);else{let b=await r(new URL(o.archives[g.file],n).href,{headers:{Range:`bytes=${g.start}-${g.end-1}`,"Accept-Encoding":"identity"}});if(!b.ok)throw Error(`ldr: parts CDN ${b.status}`);if(l++,m=new Uint8Array(await b.arrayBuffer()),f+=m.byteLength,b.status===200)d.set(g.file,m),m=m.subarray(g.start,g.end)}for(let b of g.items){let h=ye(m.subarray(b.off-g.start,b.off-g.start+b.len)),P=h.buffer.slice(h.byteOffset,h.byteOffset+h.byteLength);Me.set(n+b.name,xe(P))}}};await Promise.all(Array.from({length:Math.min(t.concurrency??24,c.length)},w));let y=i.filter((g)=>Me.has(n+g)).map((g)=>Me.get(n+g));return{pack:y.length?un(y,{colors:o.colors}):xe(pn(o.colors)),missing:a,requests:l,bytes:f}}function pn(e){let t=new TextEncoder().encode(JSON.stringify({version:1,weld:!0,parts:{},studKinds:{},colors:e})),n=(4-(4+t.length)%4)%4,r=new Uint8Array(4+t.length+n).fill(32);return new DataView(r.buffer).setUint32(0,t.length+n,!0),r.set(t,4),r.buffer}function mn(e,t){let n=t.header.parts;if(!n)return 0;let r=0;for(let s of e){let o=n[s.part]?.body?.tris;if(o)r+=o}return r}function hn(e,t,n){let r=0,s=0,o=!1,i=new Set;for(let a of e){let u=a.embedded?t.get(a.part):Q(a.part),c=u?n.parts[u]:void 0;if(!c)continue;if(c[3]!=null)o=!0,r+=c[3];if(!i.has(u))i.add(u),s+=c[1]}return{bodyTris:r,packBytes:s,known:o}}class pe extends Error{code="ldr-budget";bodyTris;packBytes;maxBodyTris;maxPackBytes;constructor(e){let t=[e.maxBodyTris!=null&&e.bodyTris>e.maxBodyTris?`${e.bodyTris} triangles (limit ${e.maxBodyTris})`:"",e.maxPackBytes!=null&&e.packBytes>e.maxPackBytes?`${(e.packBytes/1e6).toFixed(1)} MB parts pack (limit ${(e.maxPackBytes/1e6).toFixed(0)} MB)`:""].filter(Boolean).join(", ");super(`ldr: model exceeds device budget: ${t}`);this.name="BudgetError",this.bodyTris=e.bodyTris,this.packBytes=e.packBytes,this.maxBodyTris=e.maxBodyTris,this.maxPackBytes=e.maxPackBytes}}async function Mt(e,t={}){let n=performance.now(),r=t.fetch??fetch,s=At(t.cdn??Te,r);s.catch(()=>{});let o=t.text?e:await r(e).then(async(h)=>{if(!h.ok)throw Error(`ldr: ${h.status} fetching ${e}`);return Xe(await h.arrayBuffer())}),i=performance.now(),a=t.name??(t.text?"main.ldr":Ze(e)),u=dt(o,a,{looseGeometry:!1,callouts:t.callouts}),c=performance.now();t.onParsed?.(u),await s;let f=bt(o,new Set(u.filter((h)=>h.embedded).map((h)=>h.part)),a),l=(h,P)=>t.maxBodyTris!=null&&h>t.maxBodyTris||t.maxPackBytes!=null&&P>t.maxPackBytes;if(t.maxBodyTris!=null||t.maxPackBytes!=null){let h=hn(u,f,await s);if(l(h.known?h.bodyTris:0,h.packBytes))throw new pe({bodyTris:h.bodyTris,packBytes:h.packBytes,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes})}let{pack:p,missing:d,requests:w,bytes:y}=await fn([...u.filter((h)=>!h.embedded).map((h)=>h.part),...f.values()],t),L=new Map([...f].map(([h,P])=>[P,h])),g=d.map((h)=>L.get(h)??h);for(let[h,P]of f){let A=p.header.parts[P];if(A)p.header.parts[h]=A}let m=performance.now();if(t.maxBodyTris!=null||t.maxPackBytes!=null){let h=p.buffer?.byteLength??p.bytes??0,P=mn(u,p);if(l(P,h))throw new pe({bodyTris:P,packBytes:h,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes})}let b=t.cull?Ae(u,p.header,t.textures!==!1):void 0;return{insts:u,pack:p,missing:g,requests:w,bytes:y,cull:b,timings:{fetchModel:i-n,parse:c-i,parts:m-c,...b?{cull:performance.now()-m}:{}}}}self.onmessage=async(e)=>{let{id:t,source:n,opts:r}=e.data;try{let s=await Mt(n,{...r,cull:!1,onParsed:(f)=>self.postMessage({id:t,insts:f})}),o=s.pack.buffer;if(self.postMessage({id:t,buffer:o,missing:s.missing,requests:s.requests,bytes:s.bytes,timings:s.timings},[o]),!r.cull)return;let i=performance.now(),a=Ae(s.insts,s.pack.header,r.textures!==!1),u=performance.now()-i,c=[];for(let f of[a.studHidden,a.studUp,a.underHidden,a.studHideStep,a.underHideStep])if(f)c.push(f.buffer);self.postMessage({id:t,cull:a,ms:u},c)}catch(s){if(s instanceof pe||s?.code==="ldr-budget")self.postMessage({id:t,phase:"error",error:String(s?.message??s),budget:{bodyTris:s.bodyTris,packBytes:s.packBytes,maxBodyTris:s.maxBodyTris,maxPackBytes:s.maxPackBytes}});else self.postMessage({id:t,phase:"error",error:String(s?.message??s)})}};\n';
4166
4329
 
4167
- // ../../../../../../../tmp/ldr-build-tYthc8/src/cdn.ts
4330
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/cdn.ts
4168
4331
  var worker;
4169
4332
  var seq = 0;
4170
4333
  var pending = new Map;
@@ -4277,7 +4440,7 @@ async function loadModel(source, o = {}) {
4277
4440
  timings: { ...prep.timings, parts: t3 - t0 - prep.timings.fetchModel - prep.timings.parse, build: t4 - t3, total: t4 - t0 }
4278
4441
  });
4279
4442
  }
4280
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/library.ts
4443
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/library.ts
4281
4444
  import { existsSync, readFileSync } from "fs";
4282
4445
  import { join } from "path";
4283
4446
  var xf = (m, x, y, z) => [m[3] * x + m[4] * y + m[5] * z + m[0], m[6] * x + m[7] * y + m[8] * z + m[1], m[9] * x + m[10] * y + m[11] * z + m[2]];
@@ -4531,11 +4694,11 @@ class Library {
4531
4694
  return insts;
4532
4695
  }
4533
4696
  }
4534
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/build-pack.ts
4697
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/build-pack.ts
4535
4698
  import fs3 from "node:fs";
4536
4699
  import path3 from "node:path";
4537
4700
 
4538
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/resolver.ts
4701
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/resolver.ts
4539
4702
  import fs from "node:fs";
4540
4703
  import path from "node:path";
4541
4704
  var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
@@ -4807,11 +4970,11 @@ function collectDeps(lib, refs) {
4807
4970
  return out;
4808
4971
  }
4809
4972
 
4810
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/compile.ts
4973
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/compile.ts
4811
4974
  import fs2 from "node:fs";
4812
4975
  import path2 from "node:path";
4813
4976
 
4814
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/lod.ts
4977
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/lod.ts
4815
4978
  import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
4816
4979
  await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
4817
4980
  function reorderMesh(P, N, C, I) {
@@ -5003,7 +5166,7 @@ function lodChain(P, C, I) {
5003
5166
  return out;
5004
5167
  }
5005
5168
 
5006
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/compile.ts
5169
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/compile.ts
5007
5170
  function loadColors(root) {
5008
5171
  const map = new Map;
5009
5172
  for (const l of fs2.readFileSync(path2.join(root, "LDConfig.ldr"), "latin1").split(/\r?\n/)) {
@@ -5640,7 +5803,7 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
5640
5803
  return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
5641
5804
  }
5642
5805
 
5643
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/build-pack.ts
5806
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/build-pack.ts
5644
5807
  function buildPack(o) {
5645
5808
  const lib = new Library2(o.ldrawRoot);
5646
5809
  const refs = new Map;
@@ -5707,7 +5870,7 @@ function buildPack(o) {
5707
5870
  const warnings = [...lib.conflicts].map((n) => `${n}: defined differently by two models; the first definition is used`);
5708
5871
  return { data: encodePack(parts, kinds, comp.opts.weld, extra, { texture, lod: o.lod !== false, reorder: !!o.reorder }), parts: parts.size, studKinds: kinds.size, missing: [...missing], ...warnings.length ? { warnings } : {} };
5709
5872
  }
5710
- // ../../../../../../../tmp/ldr-build-tYthc8/src/node/promote.ts
5873
+ // ../../../../../../../tmp/ldr-build-95sBCS/src/node/promote.ts
5711
5874
  var GEOM = /^\s*[2-5]\s/;
5712
5875
  var REF = /^\s*1\s/;
5713
5876
  var FILE = /^\s*0\s+FILE\s+(.+?)\s*$/i;
package/dist/render.d.ts CHANGED
@@ -89,10 +89,11 @@ export declare function computeCulling(insts: Inst[], H: any): {
89
89
  /** Drive buildLdrSceneGen to completion without yielding (same as pre-Round-33 sync build). */
90
90
  export declare function buildLdrScene(insts: Inst[], pack: Pack, P: LdrParams, color: (c: string) => THREE.Color, mark: (k: string) => void): any;
91
91
  export type BuildLdrSceneAsyncOptions = {
92
- /** Soft cap on contiguous main-thread work between yields while mid-build paints are active (ms). Default 8. */
92
+ /** Cap on contiguous main-thread work between yields while mid-build paints are active (ms). Default 8. The build yields before a
93
+ * step that would likely overrun it (reserve: the longest step so far, between a third and half of the cap). */
93
94
  sliceMs?: number;
94
95
  /**
95
- * Soft cap after mid-build paints stop (onSlice returned false, or no onSlice). Default max(sliceMs, 24).
96
+ * Cap after mid-build paints stop (onSlice returned false, or no onSlice). Default max(sliceMs, 24). Same predictive yield as sliceMs.
96
97
  * Larger slices cut yield/timer overhead on the remaining build without changing the sync path.
97
98
  */
98
99
  postPaintSliceMs?: number;
@@ -108,4 +109,10 @@ export type BuildLdrSceneAsyncOptions = {
108
109
  * After onSlice returns false (TTFP done), slices coarsen to postPaintSliceMs and paints stop — cuts total loadMs.
109
110
  */
110
111
  export declare function buildLdrSceneAsync(insts: Inst[], pack: Pack, P: LdrParams, color: (c: string) => THREE.Color, mark: (k: string) => void, opts?: BuildLdrSceneAsyncOptions): Promise<any>;
112
+ /** Drives a build generator in main-thread slices (see BuildLdrSceneAsyncOptions); internal, exported for tests. */
113
+ export declare function runSliced<R>(g: Generator<THREE.Object3D, R, void>, opts?: BuildLdrSceneAsyncOptions): Promise<{
114
+ value: R;
115
+ longestSliceMs: number;
116
+ yields: number;
117
+ }>;
111
118
  export declare function warmPackGeometry(pack: Pack, stop?: () => boolean, sliceMs?: number): Promise<void>;
package/dist/scene.d.ts CHANGED
@@ -51,9 +51,9 @@ export interface LdrObjectOptions {
51
51
  /** LOD: skip undersides that can't be seen: while the camera is behind every bottom face of a cluster's (same-orientation) parts and
52
52
  * studs are under 4 px, or where the body is drawn as its closed bounding box. Default true. */
53
53
  lodUnder?: boolean;
54
- /** Progressive build (createLdrObjectAsync / loadModel): soft cap while mid-build paints are active, ms. Default 8. */
54
+ /** Progressive build (createLdrObjectAsync / loadModel): cap on each main-thread slice while mid-build paints are active, ms (the build yields before a step that would likely overrun it). Default 8. */
55
55
  sliceMs?: number;
56
- /** Progressive build: soft cap after paints stop (onSlice returned false / no onSlice). Default max(sliceMs, 24). */
56
+ /** Progressive build: slice cap after paints stop (onSlice returned false / no onSlice). Default max(sliceMs, 24). */
57
57
  postPaintSliceMs?: number;
58
58
  /**
59
59
  * Progressive build: called after each yield while paints are enabled; live object holds finished batches — render for TTFP.
@@ -108,10 +108,23 @@ export interface LdrObject {
108
108
  setSide(side: "front" | "double"): void;
109
109
  /** Turn distance LOD on/off (off = full detail and edges everywhere). Only has an effect if the object was built with `lod` (default). */
110
110
  setLod(on: boolean): void;
111
+ /** Ghost overlay of the upcoming steps (like the LEGO Builder app): while a step is shown with `setStep`, the parts of later steps
112
+ * are drawn as a faint, whitish, depth-tested ghost of the finished model; built parts draw as usual. Built lazily (a second,
113
+ * edge-free copy of the scene with the steps reversed, so its step-aware culling matches the ghosted set) the first time it is
114
+ * needed, with yields like the progressive build; resolves when it is ready. No effect on single-step models. */
115
+ setGhost(on: boolean, options?: GhostOptions): Promise<void>;
111
116
  /** Bounding box in the object's parent space. */
112
117
  getBox(target?: THREE.Box3): THREE.Box3;
113
118
  dispose(): void;
114
119
  }
120
+ export interface GhostOptions {
121
+ /** Ghost opacity, 0-1. Default 0.2. */
122
+ opacity?: number;
123
+ /** Ghost tint (mixed with each part's own colour by `whiten`). Default white. */
124
+ color?: THREE.ColorRepresentation;
125
+ /** How far each part's colour is pushed towards `color`, 0-1. Default 0.75. */
126
+ whiten?: number;
127
+ }
115
128
  /**
116
129
  * Build a three.js object for a flattened model using a parts pack.
117
130
  * Instances whose part is not in the pack are skipped and listed in `stats.missing`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ldr",
3
- "version": "0.26.0",
3
+ "version": "0.27.0",
4
4
  "description": "High-performance LEGO (LDraw) rendering for three.js: instanced parts packs, hidden stud/tube culling, low-detail studs, indexed edges, build steps.",
5
5
  "license": "MIT",
6
6
  "author": "Evan Bacon",