ldr 0.33.14 → 0.34.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
@@ -161,6 +161,18 @@ parts added underneath), preferring front three-quarter views and small turns (t
161
161
  `isolate` is set while a sub-assembly is being built: show it on its own with `setStep(step, isolateMask(instances, view.isolate))`.
162
162
  Visibility is measured on part bounding boxes, so it needs no GPU and also runs in Node.
163
163
 
164
+ **AR Quick Look (USDZ).** `toUSDZ(instances, pack, { maxTriangles?, yUp?, scale? })` → `{ data, triangles, meshes, level }` builds a
165
+ USDZ in the browser (no three.js, no network): one mesh + `UsdPreviewSurface` per colour (LEGO colours in linear RGB, transparent
166
+ colours with `opacity`, chrome / metal as metallic), studs and undersides hidden by neighbours dropped, real size (1 LDU = 0.4 mm,
167
+ Y up, standing on y = 0, centred). It takes the finest pack LOD level (then square studs, then no studs) that fits `maxTriangles`
168
+ (default 200 000). Open it on iOS / iPadOS Safari (feature-detect with `document.createElement("a").relList.supports("ar")`):
169
+
170
+ ```js
171
+ const { data } = toUSDZ(model.instances, model.pack);
172
+ const a = document.createElement("a"); a.rel = "ar"; a.href = URL.createObjectURL(new Blob([data], { type: "model/vnd.usdz+zip" }));
173
+ a.append(document.createElement("img")); a.click(); // Quick Look needs the <img> child
174
+ ```
175
+
164
176
  ### `ldr/node` (Node / Bun only)
165
177
 
166
178
  Everything above, plus:
package/dist/cli.js CHANGED
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // ../../../../../../../tmp/ldr-build-TOtjq4/src/cli.ts
3
+ // ../../../../../../../tmp/ldr-build-UFH0qj/src/cli.ts
4
4
  import fs4 from "node:fs";
5
5
  import zlib from "node:zlib";
6
6
 
7
- // ../../../../../../../tmp/ldr-build-TOtjq4/src/node/build-pack.ts
7
+ // ../../../../../../../tmp/ldr-build-UFH0qj/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-TOtjq4/src/node/resolver.ts
11
+ // ../../../../../../../tmp/ldr-build-UFH0qj/src/node/resolver.ts
12
12
  import fs from "node:fs";
13
13
  import path from "node:path";
14
14
 
15
- // ../../../../../../../tmp/ldr-build-TOtjq4/src/spec.ts
15
+ // ../../../../../../../tmp/ldr-build-UFH0qj/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;
@@ -124,27 +124,54 @@ var b64 = (s) => {
124
124
  out[i] = bin.charCodeAt(i);
125
125
  return out;
126
126
  };
127
- function type1Fast(line) {
127
+ function type1Fast(line, files) {
128
128
  const n = line.length;
129
129
  let i = 1;
130
130
  const ws = (c) => c === 32 || c === 9;
131
- const next = () => {
131
+ const num = () => {
132
132
  while (i < n && ws(line.charCodeAt(i)))
133
133
  i++;
134
134
  const a = i;
135
+ let c = line.charCodeAt(i);
136
+ const neg = c === 45;
137
+ if (neg)
138
+ c = line.charCodeAt(++i);
139
+ let v = 0, d = 0;
140
+ while (c >= 48 && c <= 57) {
141
+ v = v * 10 + (c - 48);
142
+ d++;
143
+ c = line.charCodeAt(++i);
144
+ }
145
+ if (d > 0 && d <= 15 && (i >= n || ws(c)))
146
+ return neg ? -v : v;
135
147
  while (i < n && !ws(line.charCodeAt(i)))
136
148
  i++;
137
- return a < i ? line.slice(a, i) : null;
149
+ return a < i ? +line.slice(a, i) : NaN;
138
150
  };
139
- const ct = next();
140
- if (ct === null)
151
+ while (i < n && ws(line.charCodeAt(i)))
152
+ i++;
153
+ const a0 = i;
154
+ if (i >= n)
141
155
  return null;
156
+ let c = line.charCodeAt(i), neg = c === 45, color = 0, d = 0;
157
+ if (neg)
158
+ c = line.charCodeAt(++i);
159
+ while (c >= 48 && c <= 57) {
160
+ color = color * 10 + (c - 48);
161
+ d++;
162
+ c = line.charCodeAt(++i);
163
+ }
164
+ if (d > 0 && d <= 15 && (i >= n || ws(c))) {
165
+ if (neg)
166
+ color = -color;
167
+ } else {
168
+ while (i < n && !ws(line.charCodeAt(i)))
169
+ i++;
170
+ color = parseColor(line.slice(a0, i));
171
+ }
142
172
  const m = new Array(12);
143
173
  for (let k = 0;k < 12; k++) {
144
- const t = next();
145
- if (t === null)
146
- return null;
147
- const v = +t;
174
+ const v = num();
148
175
  if (!Number.isFinite(v))
149
176
  return null;
150
177
  m[k] = v;
@@ -154,11 +181,14 @@ function type1Fast(line) {
154
181
  if (i >= n)
155
182
  return null;
156
183
  const rest = line.slice(i);
157
- const file = /[ \t]{2,}|\t/.test(rest) ? rest.split(/\s+/).join(" ") : rest;
158
- const color = parseColor(ct);
184
+ let file = files.get(rest);
185
+ if (file === undefined) {
186
+ file = norm(/[ \t]{2,}|\t/.test(rest) ? rest.split(/\s+/).join(" ") : rest);
187
+ files.set(rest, file);
188
+ }
159
189
  if (!Number.isFinite(color))
160
190
  return null;
161
- return { t: 1, color, m, file: norm(file) };
191
+ return { t: 1, color, m, file };
162
192
  }
163
193
  var NUMS = [0, 12, 6, 9, 12, 12];
164
194
  function geomLine(tk) {
@@ -204,6 +234,7 @@ function parse(src, name = "main.ldr", popts = {}) {
204
234
  (data ??= new Map).set(norm(dataCur.name), { name: dataCur.name, bytes, ...png ? { mime: "image/png" } : {} });
205
235
  dataCur = null;
206
236
  };
237
+ const t1Files = new Map;
207
238
  let inHeader = true;
208
239
  const start = (n) => {
209
240
  closeData();
@@ -293,7 +324,7 @@ function parse(src, name = "main.ldr", popts = {}) {
293
324
  }
294
325
  }
295
326
  if (line.charCodeAt(0) === 49 && (line.charCodeAt(1) === 32 || line.charCodeAt(1) === 9) && !dataCur && !skip) {
296
- const g = type1Fast(line);
327
+ const g = type1Fast(line, t1Files);
297
328
  if (g) {
298
329
  if (!cur)
299
330
  start(name);
@@ -817,7 +848,7 @@ function fileStepViews(f) {
817
848
  return out;
818
849
  }
819
850
 
820
- // ../../../../../../../tmp/ldr-build-TOtjq4/src/model.ts
851
+ // ../../../../../../../tmp/ldr-build-UFH0qj/src/model.ts
821
852
  class ModelLimitError extends Error {
822
853
  limit;
823
854
  code = "ldr-model-limit";
@@ -1259,7 +1290,7 @@ function blendedColourHex(code) {
1259
1290
  return "#" + [0, 1, 2].map((k) => (a[k] + b[k] >> 1).toString(16).padStart(2, "0")).join("").toUpperCase();
1260
1291
  }
1261
1292
 
1262
- // ../../../../../../../tmp/ldr-build-TOtjq4/src/node/resolver.ts
1293
+ // ../../../../../../../tmp/ldr-build-UFH0qj/src/node/resolver.ts
1263
1294
  var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
1264
1295
  var UNDER_STUD_RE = /^(stud3|stud3a|stud4.*|stud12|stud16.*|stud18a)\.dat$/i;
1265
1296
  var norm2 = (ref) => ref.trim().replace(/\\/g, "/").toLowerCase();
@@ -1586,11 +1617,11 @@ function collectDeps(lib, refs) {
1586
1617
  return out;
1587
1618
  }
1588
1619
 
1589
- // ../../../../../../../tmp/ldr-build-TOtjq4/src/node/compile.ts
1620
+ // ../../../../../../../tmp/ldr-build-UFH0qj/src/node/compile.ts
1590
1621
  import fs2 from "node:fs";
1591
1622
  import path2 from "node:path";
1592
1623
 
1593
- // ../../../../../../../tmp/ldr-build-TOtjq4/src/node/lod.ts
1624
+ // ../../../../../../../tmp/ldr-build-UFH0qj/src/node/lod.ts
1594
1625
  import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
1595
1626
  await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
1596
1627
  function reorderMesh(P, N, C, I) {
@@ -1896,7 +1927,7 @@ function levelLines(P, I, E, err, always, tol = 0.01) {
1896
1927
  return out;
1897
1928
  }
1898
1929
 
1899
- // ../../../../../../../tmp/ldr-build-TOtjq4/src/node/compile.ts
1930
+ // ../../../../../../../tmp/ldr-build-UFH0qj/src/node/compile.ts
1900
1931
  class BfcState {
1901
1932
  accum;
1902
1933
  ccw = true;
@@ -2840,7 +2871,7 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
2840
2871
  return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
2841
2872
  }
2842
2873
 
2843
- // ../../../../../../../tmp/ldr-build-TOtjq4/src/node/build-pack.ts
2874
+ // ../../../../../../../tmp/ldr-build-UFH0qj/src/node/build-pack.ts
2844
2875
  function packCompilerOpts(o) {
2845
2876
  return { studs: o.studs ?? "low", prims: o.primitives ?? "full", weld: o.weld ?? true, separateStuds: true, cond: !!o.cond, tex: !!o.textures, ...o.partWorkLimit ? { workLimit: o.partWorkLimit } : {} };
2846
2877
  }
@@ -2913,7 +2944,7 @@ function buildPack(o) {
2913
2944
  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 } : {} };
2914
2945
  }
2915
2946
 
2916
- // ../../../../../../../tmp/ldr-build-TOtjq4/src/cli.ts
2947
+ // ../../../../../../../tmp/ldr-build-UFH0qj/src/cli.ts
2917
2948
  var HELP = `ldr pack — build a parts pack for the ldr three.js renderer
2918
2949
 
2919
2950
  Usage:
package/dist/index.d.ts CHANGED
@@ -13,3 +13,4 @@ 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";
15
15
  export { embeddedKeys } from "./embedded.js";
16
+ export { toUSDZ, zipStored, type UsdzOptions, type UsdzResult } from "./usdz.js";