three-usd-robot 0.2.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.
@@ -0,0 +1,2685 @@
1
+ import { unzipSync } from 'fflate';
2
+
3
+ // src/version.ts
4
+ var PACKAGE_NAME = "three-usd-robot";
5
+ var VERSION = "0.0.0";
6
+
7
+ // src/parser/ast.ts
8
+ var Quat = class _Quat {
9
+ constructor(real, imaginary) {
10
+ this.real = real;
11
+ this.imaginary = imaginary;
12
+ }
13
+ real;
14
+ imaginary;
15
+ /** Components in Three.js order `[x, y, z, w]`. */
16
+ toXYZW() {
17
+ return [this.imaginary[0], this.imaginary[1], this.imaginary[2], this.real];
18
+ }
19
+ static identity() {
20
+ return new _Quat(1, [0, 0, 0]);
21
+ }
22
+ };
23
+ var UsdMatrix = class _UsdMatrix {
24
+ constructor(values, dim) {
25
+ this.values = values;
26
+ this.dim = dim;
27
+ }
28
+ values;
29
+ dim;
30
+ static identity4() {
31
+ return new _UsdMatrix([
32
+ 1,
33
+ 0,
34
+ 0,
35
+ 0,
36
+ 0,
37
+ 1,
38
+ 0,
39
+ 0,
40
+ 0,
41
+ 0,
42
+ 1,
43
+ 0,
44
+ 0,
45
+ 0,
46
+ 0,
47
+ 1
48
+ ], 4);
49
+ }
50
+ };
51
+ var AssetPath = class {
52
+ constructor(path) {
53
+ this.path = path;
54
+ }
55
+ path;
56
+ };
57
+
58
+ // src/parser/reader.ts
59
+ var ParseError = class extends Error {
60
+ constructor(message, line, col) {
61
+ super(`USDA parse error (line ${line}:${col}): ${message}`);
62
+ this.line = line;
63
+ this.col = col;
64
+ this.name = "ParseError";
65
+ }
66
+ line;
67
+ col;
68
+ };
69
+ var TokenReader = class {
70
+ constructor(tokens) {
71
+ this.tokens = tokens;
72
+ }
73
+ tokens;
74
+ pos = 0;
75
+ peek(ahead = 0) {
76
+ return this.tokens[Math.min(this.pos + ahead, this.tokens.length - 1)];
77
+ }
78
+ next() {
79
+ const t = this.tokens[this.pos];
80
+ if (this.pos < this.tokens.length - 1) this.pos++;
81
+ return t;
82
+ }
83
+ atEnd() {
84
+ return this.peek().type === "eof";
85
+ }
86
+ is(type, ahead = 0) {
87
+ return this.peek(ahead).type === type;
88
+ }
89
+ /** True when the lookahead token is an identifier with the given text. */
90
+ isIdent(value, ahead = 0) {
91
+ const t = this.peek(ahead);
92
+ return t.type === "ident" && t.value === value;
93
+ }
94
+ expect(type) {
95
+ const t = this.peek();
96
+ if (t.type !== type) {
97
+ throw new ParseError(
98
+ `expected ${type} but found ${t.type} ${JSON.stringify(t.value)}`,
99
+ t.line,
100
+ t.col
101
+ );
102
+ }
103
+ return this.next();
104
+ }
105
+ /** Consume an identifier token (any value) and return its text. */
106
+ expectIdent() {
107
+ return this.expect("ident").value;
108
+ }
109
+ /** Consume the given token type if present; return whether it was consumed. */
110
+ accept(type) {
111
+ if (this.is(type)) {
112
+ this.next();
113
+ return true;
114
+ }
115
+ return false;
116
+ }
117
+ /** Consume an identifier with the exact text if present. */
118
+ acceptIdent(value) {
119
+ if (this.isIdent(value)) {
120
+ this.next();
121
+ return true;
122
+ }
123
+ return false;
124
+ }
125
+ error(message) {
126
+ const t = this.peek();
127
+ return new ParseError(message, t.line, t.col);
128
+ }
129
+ };
130
+
131
+ // src/parser/tokenize.ts
132
+ var TokenizeError = class extends Error {
133
+ constructor(message, line, col) {
134
+ super(`USDA tokenize error (line ${line}:${col}): ${message}`);
135
+ this.line = line;
136
+ this.col = col;
137
+ this.name = "TokenizeError";
138
+ }
139
+ line;
140
+ col;
141
+ };
142
+ var IDENT_START = /[A-Za-z_]/;
143
+ var IDENT_CONT = /[A-Za-z0-9_:]/;
144
+ var NUMBER_RE = /^[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/;
145
+ var INF_NAN_RE = /^[-+]?(?:inf|nan)\b/i;
146
+ function tokenize(src) {
147
+ const tokens = [];
148
+ let i = 0;
149
+ let line = 1;
150
+ let lineStart = 0;
151
+ const n = src.length;
152
+ const col = () => i - lineStart + 1;
153
+ const push = (type, value, startCol, num) => {
154
+ tokens.push(
155
+ num === void 0 ? { type, value, line, col: startCol } : { type, value, num, line, col: startCol }
156
+ );
157
+ };
158
+ while (i < n) {
159
+ const c = src[i];
160
+ if (c === "\n") {
161
+ i++;
162
+ line++;
163
+ lineStart = i;
164
+ continue;
165
+ }
166
+ if (c === " " || c === " " || c === "\r" || c === "\f" || c === "\v") {
167
+ i++;
168
+ continue;
169
+ }
170
+ if (c === "#") {
171
+ while (i < n && src[i] !== "\n") i++;
172
+ continue;
173
+ }
174
+ const startCol = col();
175
+ const punct = PUNCT[c];
176
+ if (punct) {
177
+ push(punct, c, startCol);
178
+ i++;
179
+ continue;
180
+ }
181
+ if (c === '"' && src[i + 1] === '"' && src[i + 2] === '"') {
182
+ const { value, advanced } = readTripleString(src, i, line, startCol);
183
+ push("string", value, startCol);
184
+ i = advanced;
185
+ continue;
186
+ }
187
+ if (c === '"' || c === "'") {
188
+ const { value, advanced } = readString(src, i, c, line, startCol);
189
+ push("string", value, startCol);
190
+ i = advanced;
191
+ continue;
192
+ }
193
+ if (c === "@") {
194
+ const triple = src[i + 1] === "@" && src[i + 2] === "@";
195
+ const { value, advanced } = readAsset(src, i, triple, line, startCol);
196
+ push("asset", value, startCol);
197
+ i = advanced;
198
+ continue;
199
+ }
200
+ if (c === "<") {
201
+ const { value, advanced } = readPath(src, i, line, startCol);
202
+ push("path", value, startCol);
203
+ i = advanced;
204
+ continue;
205
+ }
206
+ const infMatch = INF_NAN_RE.exec(src.slice(i));
207
+ if (infMatch) {
208
+ const text = infMatch[0];
209
+ const lower = text.toLowerCase();
210
+ const num = lower.includes("nan") ? Number.NaN : lower.startsWith("-") ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;
211
+ push("number", text, startCol, num);
212
+ i += text.length;
213
+ continue;
214
+ }
215
+ if (/[0-9]/.test(c) || (c === "-" || c === "+" || c === ".") && /[0-9.]/.test(src[i + 1] ?? "")) {
216
+ const m = NUMBER_RE.exec(src.slice(i));
217
+ if (m) {
218
+ const text = m[0];
219
+ push("number", text, startCol, Number(text));
220
+ i += text.length;
221
+ continue;
222
+ }
223
+ }
224
+ if (c === ".") {
225
+ push("dot", ".", startCol);
226
+ i++;
227
+ continue;
228
+ }
229
+ if (IDENT_START.test(c)) {
230
+ const start = i;
231
+ i++;
232
+ while (i < n && IDENT_CONT.test(src[i])) i++;
233
+ push("ident", src.slice(start, i), startCol);
234
+ continue;
235
+ }
236
+ throw new TokenizeError(`unexpected character ${JSON.stringify(c)}`, line, startCol);
237
+ }
238
+ tokens.push({ type: "eof", value: "", line, col: col() });
239
+ return tokens;
240
+ }
241
+ var PUNCT = {
242
+ "{": "lbrace",
243
+ "}": "rbrace",
244
+ "(": "lparen",
245
+ ")": "rparen",
246
+ "[": "lbracket",
247
+ "]": "rbracket",
248
+ "=": "equals",
249
+ ",": "comma",
250
+ ":": "colon"
251
+ };
252
+ function readString(src, start, quote, line, startCol) {
253
+ let i = start + 1;
254
+ let out = "";
255
+ while (i < src.length) {
256
+ const ch = src[i];
257
+ if (ch === "\\") {
258
+ const next = src[i + 1];
259
+ out += ESCAPES[next ?? ""] ?? next ?? "";
260
+ i += 2;
261
+ continue;
262
+ }
263
+ if (ch === quote) {
264
+ return { value: out, advanced: i + 1 };
265
+ }
266
+ if (ch === "\n") break;
267
+ out += ch;
268
+ i++;
269
+ }
270
+ throw new TokenizeError("unterminated string literal", line, startCol);
271
+ }
272
+ function readTripleString(src, start, line, startCol) {
273
+ let i = start + 3;
274
+ let out = "";
275
+ while (i < src.length) {
276
+ if (src[i] === '"' && src[i + 1] === '"' && src[i + 2] === '"') {
277
+ return { value: out, advanced: i + 3 };
278
+ }
279
+ out += src[i];
280
+ i++;
281
+ }
282
+ throw new TokenizeError("unterminated triple-quoted string", line, startCol);
283
+ }
284
+ function readAsset(src, start, triple, line, startCol) {
285
+ const delimLen = triple ? 3 : 1;
286
+ let i = start + delimLen;
287
+ let out = "";
288
+ while (i < src.length) {
289
+ if (triple) {
290
+ if (src[i] === "@" && src[i + 1] === "@" && src[i + 2] === "@") {
291
+ return { value: out, advanced: i + 3 };
292
+ }
293
+ } else if (src[i] === "@") {
294
+ return { value: out, advanced: i + 1 };
295
+ }
296
+ if (src[i] === "\n") break;
297
+ out += src[i];
298
+ i++;
299
+ }
300
+ throw new TokenizeError("unterminated asset path", line, startCol);
301
+ }
302
+ function readPath(src, start, line, startCol) {
303
+ let i = start + 1;
304
+ let out = "";
305
+ while (i < src.length) {
306
+ if (src[i] === ">") {
307
+ return { value: out, advanced: i + 1 };
308
+ }
309
+ if (src[i] === "\n") break;
310
+ out += src[i];
311
+ i++;
312
+ }
313
+ throw new TokenizeError("unterminated path <...>", line, startCol);
314
+ }
315
+ var ESCAPES = {
316
+ n: "\n",
317
+ t: " ",
318
+ r: "\r",
319
+ '"': '"',
320
+ "'": "'",
321
+ "\\": "\\"
322
+ };
323
+
324
+ // src/parser/valueParser.ts
325
+ function parseLiteral(r) {
326
+ const t = r.peek();
327
+ switch (t.type) {
328
+ case "number":
329
+ r.next();
330
+ return { t: "scalar", v: t.num ?? Number(t.value) };
331
+ case "string":
332
+ r.next();
333
+ return { t: "scalar", v: t.value };
334
+ case "asset":
335
+ r.next();
336
+ return { t: "asset", v: new AssetPath(t.value) };
337
+ case "path":
338
+ r.next();
339
+ return { t: "path", v: t.value };
340
+ case "ident": {
341
+ r.next();
342
+ if (t.value === "true") return { t: "scalar", v: true };
343
+ if (t.value === "false") return { t: "scalar", v: false };
344
+ if (t.value === "None" || t.value === "none") return { t: "scalar", v: null };
345
+ return { t: "scalar", v: t.value };
346
+ }
347
+ case "lparen":
348
+ return parseGroup(r, "lparen", "rparen", "tuple");
349
+ case "lbracket":
350
+ return parseGroup(r, "lbracket", "rbracket", "array");
351
+ default:
352
+ throw r.error(`unexpected token ${t.type} ${JSON.stringify(t.value)} while parsing a value`);
353
+ }
354
+ }
355
+ function parseGroup(r, open, close, kind) {
356
+ r.expect(open);
357
+ const items = [];
358
+ while (!r.is(close) && !r.atEnd()) {
359
+ items.push(parseLiteral(r));
360
+ if (!r.accept("comma")) break;
361
+ }
362
+ r.expect(close);
363
+ return { t: kind, items };
364
+ }
365
+ function parseTypedValue(r, typeName, isArray) {
366
+ return coerceValue(typeName, isArray, parseLiteral(r));
367
+ }
368
+ function coerceValue(typeName, isArray, raw) {
369
+ if (raw.t === "scalar" && raw.v === null) return null;
370
+ if (isArray) {
371
+ if (raw.t !== "array") {
372
+ throw new TypeError(`expected an array literal for ${typeName}[] but got ${raw.t}`);
373
+ }
374
+ return raw.items.map((item) => coerceScalar(typeName, item));
375
+ }
376
+ return coerceScalar(typeName, raw);
377
+ }
378
+ function coerceScalar(typeName, raw) {
379
+ if (QUAT_TYPES.has(typeName)) {
380
+ const nums = expectNumberTuple(raw, 4, typeName);
381
+ return new Quat(nums[0], [nums[1], nums[2], nums[3]]);
382
+ }
383
+ if (typeName === "matrix4d" || typeName === "matrix4f" || typeName === "frame4d") {
384
+ return flattenMatrix(raw, 4, typeName);
385
+ }
386
+ if (typeName === "matrix3d" || typeName === "matrix3f") {
387
+ return flattenMatrix(raw, 3, typeName);
388
+ }
389
+ const dim = VEC_DIM[typeName];
390
+ if (dim !== void 0) {
391
+ const nums = expectNumberTuple(raw, dim, typeName);
392
+ return nums;
393
+ }
394
+ if (typeName === "asset") {
395
+ if (raw.t === "asset") return raw.v;
396
+ if (raw.t === "scalar" && typeof raw.v === "string") return new AssetPath(raw.v);
397
+ throw new TypeError(`expected an asset path for ${typeName}`);
398
+ }
399
+ if (raw.t === "path") return raw.v;
400
+ if (raw.t !== "scalar") {
401
+ if (raw.t === "tuple") return raw.items.map((it) => coerceScalar(typeName, it));
402
+ throw new TypeError(`expected a scalar for ${typeName} but got ${raw.t}`);
403
+ }
404
+ const v = raw.v;
405
+ if (typeName === "bool") {
406
+ if (typeof v === "boolean") return v;
407
+ if (v === 1 || v === 0) return v === 1;
408
+ }
409
+ return v;
410
+ }
411
+ function expectNumberTuple(raw, dim, typeName) {
412
+ if (raw.t !== "tuple") {
413
+ throw new TypeError(`expected a ${dim}-tuple for ${typeName} but got ${raw.t}`);
414
+ }
415
+ if (raw.items.length !== dim) {
416
+ throw new TypeError(`expected ${dim} components for ${typeName} but got ${raw.items.length}`);
417
+ }
418
+ return raw.items.map((it) => {
419
+ if (it.t !== "scalar" || typeof it.v !== "number") {
420
+ throw new TypeError(`expected a number component for ${typeName}`);
421
+ }
422
+ return it.v;
423
+ });
424
+ }
425
+ function flattenMatrix(raw, dim, typeName) {
426
+ if (raw.t !== "tuple" || raw.items.length !== dim) {
427
+ throw new TypeError(`expected ${dim} rows for ${typeName}`);
428
+ }
429
+ const values = [];
430
+ for (const row of raw.items) {
431
+ values.push(...expectNumberTuple(row, dim, typeName));
432
+ }
433
+ return new UsdMatrix(values, dim);
434
+ }
435
+ function rawToUsdValue(raw) {
436
+ switch (raw.t) {
437
+ case "scalar":
438
+ return raw.v;
439
+ case "asset":
440
+ return raw.v;
441
+ case "path":
442
+ return raw.v;
443
+ case "tuple":
444
+ case "array":
445
+ return raw.items.map(rawToUsdValue);
446
+ }
447
+ }
448
+ var QUAT_TYPES = /* @__PURE__ */ new Set(["quatf", "quatd", "quath"]);
449
+ var VEC_DIM = {
450
+ float2: 2,
451
+ double2: 2,
452
+ half2: 2,
453
+ int2: 2,
454
+ texCoord2f: 2,
455
+ texCoord2d: 2,
456
+ texCoord2h: 2,
457
+ float3: 3,
458
+ double3: 3,
459
+ half3: 3,
460
+ int3: 3,
461
+ point3f: 3,
462
+ point3d: 3,
463
+ point3h: 3,
464
+ normal3f: 3,
465
+ normal3d: 3,
466
+ normal3h: 3,
467
+ vector3f: 3,
468
+ vector3d: 3,
469
+ vector3h: 3,
470
+ color3f: 3,
471
+ color3d: 3,
472
+ color3h: 3,
473
+ texCoord3f: 3,
474
+ float4: 4,
475
+ double4: 4,
476
+ half4: 4,
477
+ int4: 4,
478
+ color4f: 4,
479
+ color4d: 4,
480
+ color4h: 4
481
+ };
482
+
483
+ // src/parser/parseUsda.ts
484
+ var SPECIFIERS = /* @__PURE__ */ new Set(["def", "over", "class"]);
485
+ var LIST_OPS = /* @__PURE__ */ new Set(["prepend", "append", "add", "delete", "reorder"]);
486
+ var MAGIC_RE = /^\s*#usda\s+(\S+)/;
487
+ function parseUsda(text) {
488
+ const magic = MAGIC_RE.exec(text);
489
+ const version = magic?.[1] ?? "1.0";
490
+ const r = new TokenReader(tokenize(text));
491
+ const metadata = r.is("lparen") ? parseMetadataBlock(r) : {};
492
+ const prims = [];
493
+ while (!r.atEnd()) {
494
+ prims.push(parsePrim(r));
495
+ }
496
+ return { version, metadata, prims };
497
+ }
498
+ function parsePrim(r) {
499
+ const head = r.peek();
500
+ const specifier = r.expectIdent();
501
+ if (!SPECIFIERS.has(specifier)) {
502
+ throw r.error(
503
+ `expected a prim specifier (def/over/class) but found ${JSON.stringify(specifier)}`
504
+ );
505
+ }
506
+ let typeName = "";
507
+ if (r.is("ident")) typeName = r.expectIdent();
508
+ const name = r.expect("string").value;
509
+ const metadata = r.is("lparen") ? parseMetadataBlock(r) : {};
510
+ const properties = [];
511
+ const children = [];
512
+ r.expect("lbrace");
513
+ while (!r.is("rbrace") && !r.atEnd()) {
514
+ if (r.is("ident") && SPECIFIERS.has(r.peek().value)) {
515
+ children.push(parsePrim(r));
516
+ } else {
517
+ properties.push(parseProperty(r));
518
+ }
519
+ }
520
+ r.expect("rbrace");
521
+ return {
522
+ specifier,
523
+ typeName,
524
+ name,
525
+ metadata,
526
+ properties,
527
+ children,
528
+ line: head.line
529
+ };
530
+ }
531
+ function parseProperty(r) {
532
+ const line = r.peek().line;
533
+ let custom = false;
534
+ let variability = "varying";
535
+ let listOp = "explicit";
536
+ for (; ; ) {
537
+ if (r.acceptIdent("custom")) {
538
+ custom = true;
539
+ } else if (r.acceptIdent("uniform")) {
540
+ variability = "uniform";
541
+ } else if (r.acceptIdent("varying")) {
542
+ variability = "varying";
543
+ } else if (r.is("ident") && LIST_OPS.has(r.peek().value)) {
544
+ listOp = r.expectIdent();
545
+ } else {
546
+ break;
547
+ }
548
+ }
549
+ if (r.isIdent("rel")) {
550
+ r.next();
551
+ return parseRelationship(r, custom, listOp, line);
552
+ }
553
+ return parseAttribute(r, custom, variability, line);
554
+ }
555
+ function parseAttribute(r, custom, variability, line) {
556
+ const typeName = r.expectIdent();
557
+ let isArray = false;
558
+ if (r.accept("lbracket")) {
559
+ r.expect("rbracket");
560
+ isArray = true;
561
+ }
562
+ const name = r.expectIdent();
563
+ const attr = {
564
+ kind: "attribute",
565
+ name,
566
+ typeName,
567
+ isArray,
568
+ variability,
569
+ custom,
570
+ metadata: {},
571
+ line
572
+ };
573
+ if (r.accept("dot")) {
574
+ const suffix = r.expectIdent();
575
+ r.expect("equals");
576
+ if (suffix === "connect") {
577
+ attr.connections = parseTargetList(r);
578
+ } else if (suffix === "timeSamples") {
579
+ attr.timeSamples = parseTimeSamples(r, typeName, isArray);
580
+ } else {
581
+ throw r.error(`unsupported attribute qualifier .${suffix}`);
582
+ }
583
+ } else if (r.accept("equals")) {
584
+ if (r.is("lbrace")) {
585
+ attr.timeSamples = parseTimeSamples(r, typeName, isArray);
586
+ } else {
587
+ attr.value = parseTypedValue(r, typeName, isArray);
588
+ }
589
+ }
590
+ if (r.is("lparen")) attr.metadata = parseMetadataBlock(r);
591
+ return attr;
592
+ }
593
+ function parseRelationship(r, custom, listOp, line) {
594
+ const name = r.expectIdent();
595
+ let targets = [];
596
+ if (r.accept("equals")) {
597
+ targets = parseTargetList(r);
598
+ }
599
+ const metadata = r.is("lparen") ? parseMetadataBlock(r) : {};
600
+ return { kind: "relationship", name, custom, listOp, targets, metadata, line };
601
+ }
602
+ function parseTargetList(r) {
603
+ if (r.acceptIdent("None") || r.acceptIdent("none")) return [];
604
+ if (r.is("path")) return [r.next().value];
605
+ if (r.accept("lbracket")) {
606
+ const targets = [];
607
+ while (!r.is("rbracket") && !r.atEnd()) {
608
+ targets.push(r.expect("path").value);
609
+ if (!r.accept("comma")) break;
610
+ }
611
+ r.expect("rbracket");
612
+ return targets;
613
+ }
614
+ throw r.error("expected a relationship/connection target path");
615
+ }
616
+ function parseTimeSamples(r, typeName, isArray) {
617
+ r.expect("lbrace");
618
+ const samples = /* @__PURE__ */ new Map();
619
+ while (!r.is("rbrace") && !r.atEnd()) {
620
+ const time = r.expect("number").num ?? Number(r.peek().value);
621
+ r.expect("colon");
622
+ samples.set(time, parseTypedValue(r, typeName, isArray));
623
+ if (!r.accept("comma")) break;
624
+ }
625
+ r.expect("rbrace");
626
+ return samples;
627
+ }
628
+ function parseMetadataBlock(r) {
629
+ r.expect("lparen");
630
+ const meta = {};
631
+ while (!r.is("rparen") && !r.atEnd()) {
632
+ if (r.is("string") && !r.is("equals", 1)) {
633
+ meta.doc = r.next().value;
634
+ continue;
635
+ }
636
+ if (r.is("ident") && LIST_OPS.has(r.peek().value)) r.next();
637
+ const key = r.expectIdent();
638
+ r.expect("equals");
639
+ meta[key] = parseMetadataValue(r);
640
+ }
641
+ r.expect("rparen");
642
+ return meta;
643
+ }
644
+ function parseMetadataValue(r) {
645
+ if (r.is("lbrace")) return parseDictionary(r);
646
+ if (r.is("lbracket")) return parseMetadataList(r);
647
+ const raw = parseLiteral(r);
648
+ if (raw.t === "asset" && r.is("path")) {
649
+ const arc = { assetPath: raw.v, primPath: r.next().value };
650
+ return arc;
651
+ }
652
+ if (raw.t === "asset") {
653
+ return raw.v;
654
+ }
655
+ return rawToUsdValue(raw);
656
+ }
657
+ function parseMetadataList(r) {
658
+ r.expect("lbracket");
659
+ const items = [];
660
+ while (!r.is("rbracket") && !r.atEnd()) {
661
+ if (r.is("asset")) {
662
+ const assetPath = new AssetPath(r.next().value);
663
+ if (r.is("path")) {
664
+ const arc = { assetPath, primPath: r.next().value };
665
+ items.push(arc);
666
+ } else {
667
+ items.push(assetPath);
668
+ }
669
+ } else {
670
+ items.push(rawToUsdValue(parseLiteral(r)));
671
+ }
672
+ if (!r.accept("comma")) break;
673
+ }
674
+ r.expect("rbracket");
675
+ return items;
676
+ }
677
+ function parseDictionary(r) {
678
+ r.expect("lbrace");
679
+ const dict = {};
680
+ while (!r.is("rbrace") && !r.atEnd()) {
681
+ r.expectIdent();
682
+ if (r.accept("lbracket")) r.expect("rbracket");
683
+ const key = r.is("string") ? r.next().value : r.expectIdent();
684
+ r.expect("equals");
685
+ dict[key] = parseMetadataValue(r);
686
+ }
687
+ r.expect("rbrace");
688
+ return dict;
689
+ }
690
+
691
+ // src/usd/names.ts
692
+ function splitName(name) {
693
+ const idx = name.lastIndexOf(":");
694
+ if (idx === -1) return { namespace: "", baseName: name };
695
+ return { namespace: name.slice(0, idx), baseName: name.slice(idx + 1) };
696
+ }
697
+
698
+ // src/usd/Attribute.ts
699
+ var Attribute = class {
700
+ constructor(_prim, _name, _spec) {
701
+ this._prim = _prim;
702
+ this._name = _name;
703
+ this._spec = _spec;
704
+ }
705
+ _prim;
706
+ _name;
707
+ _spec;
708
+ IsValid() {
709
+ return this._spec !== null;
710
+ }
711
+ GetPrim() {
712
+ return this._prim;
713
+ }
714
+ GetName() {
715
+ return this._name;
716
+ }
717
+ GetBaseName() {
718
+ return splitName(this._name).baseName;
719
+ }
720
+ GetNamespace() {
721
+ return splitName(this._name).namespace;
722
+ }
723
+ /** Scalar type name (without the `[]` suffix); pair with {@link IsArray}. */
724
+ GetTypeName() {
725
+ return this._spec?.typeName ?? "";
726
+ }
727
+ IsArray() {
728
+ return this._spec?.isArray ?? false;
729
+ }
730
+ GetVariability() {
731
+ return this._spec?.variability ?? "varying";
732
+ }
733
+ IsCustom() {
734
+ return this._spec?.custom ?? false;
735
+ }
736
+ /** True if a default value or any time sample is authored. */
737
+ HasValue() {
738
+ return this.HasAuthoredValue();
739
+ }
740
+ HasAuthoredValue() {
741
+ if (!this._spec) return false;
742
+ return this._spec.value !== void 0 || (this._spec.timeSamples?.size ?? 0) > 0;
743
+ }
744
+ /**
745
+ * Resolve the attribute value. With no `time`, returns the default value (or
746
+ * the earliest time sample if only samples are authored). With a `time`,
747
+ * returns the exact sample if present, else the default, else the earliest
748
+ * sample. Returns `undefined` when nothing is authored.
749
+ */
750
+ Get(time) {
751
+ const spec = this._spec;
752
+ if (!spec) return void 0;
753
+ if (time !== void 0 && spec.timeSamples?.has(time)) {
754
+ return spec.timeSamples.get(time);
755
+ }
756
+ if (spec.value !== void 0) return spec.value;
757
+ if (spec.timeSamples && spec.timeSamples.size > 0) {
758
+ const firstKey = [...spec.timeSamples.keys()].sort((a, b) => a - b)[0];
759
+ return spec.timeSamples.get(firstKey);
760
+ }
761
+ return void 0;
762
+ }
763
+ GetTimeSamples() {
764
+ return this._spec?.timeSamples ?? /* @__PURE__ */ new Map();
765
+ }
766
+ GetConnections() {
767
+ return this._spec?.connections ?? [];
768
+ }
769
+ };
770
+ var Relationship = class {
771
+ constructor(_prim, _name, _spec) {
772
+ this._prim = _prim;
773
+ this._name = _name;
774
+ this._spec = _spec;
775
+ }
776
+ _prim;
777
+ _name;
778
+ _spec;
779
+ IsValid() {
780
+ return this._spec !== null;
781
+ }
782
+ GetPrim() {
783
+ return this._prim;
784
+ }
785
+ GetName() {
786
+ return this._name;
787
+ }
788
+ GetBaseName() {
789
+ return splitName(this._name).baseName;
790
+ }
791
+ GetNamespace() {
792
+ return splitName(this._name).namespace;
793
+ }
794
+ IsCustom() {
795
+ return this._spec?.custom ?? false;
796
+ }
797
+ GetTargets() {
798
+ return this._spec?.targets ?? [];
799
+ }
800
+ };
801
+
802
+ // src/usd/Layer.ts
803
+ var Layer = class {
804
+ constructor(_file) {
805
+ this._file = _file;
806
+ }
807
+ _file;
808
+ GetVersion() {
809
+ return this._file.version;
810
+ }
811
+ GetPseudoRootMetadata() {
812
+ return this._file.metadata;
813
+ }
814
+ GetMetadata(key) {
815
+ return this._file.metadata[key];
816
+ }
817
+ GetDefaultPrimName() {
818
+ const v = this._file.metadata.defaultPrim;
819
+ return typeof v === "string" ? v : void 0;
820
+ }
821
+ GetRootPrimSpecs() {
822
+ return this._file.prims;
823
+ }
824
+ };
825
+
826
+ // src/usd/Prim.ts
827
+ var Prim = class {
828
+ constructor(_stage, _spec, _path, _parent) {
829
+ this._stage = _stage;
830
+ this._spec = _spec;
831
+ this._path = _path;
832
+ this._parent = _parent;
833
+ }
834
+ _stage;
835
+ _spec;
836
+ _path;
837
+ _parent;
838
+ _children = [];
839
+ _attributes;
840
+ _relationships;
841
+ /** @internal Used by {@link Stage} while building the prim tree. */
842
+ _addChild(child) {
843
+ this._children.push(child);
844
+ }
845
+ GetStage() {
846
+ return this._stage;
847
+ }
848
+ IsValid() {
849
+ return true;
850
+ }
851
+ IsPseudoRoot() {
852
+ return this._spec === null;
853
+ }
854
+ GetName() {
855
+ return this._spec?.name ?? "";
856
+ }
857
+ GetPath() {
858
+ return this._path;
859
+ }
860
+ GetTypeName() {
861
+ return this._spec?.typeName ?? "";
862
+ }
863
+ GetSpecifier() {
864
+ return this._spec?.specifier ?? null;
865
+ }
866
+ GetParent() {
867
+ return this._parent;
868
+ }
869
+ GetChildren() {
870
+ return this._children;
871
+ }
872
+ GetChild(name) {
873
+ return this._children.find((c) => c.GetName() === name) ?? null;
874
+ }
875
+ // -- Attributes ----------------------------------------------------------
876
+ attrMap() {
877
+ if (!this._attributes) {
878
+ this._attributes = /* @__PURE__ */ new Map();
879
+ for (const p of this._spec?.properties ?? []) {
880
+ if (p.kind === "attribute") this._attributes.set(p.name, p);
881
+ }
882
+ }
883
+ return this._attributes;
884
+ }
885
+ /** Always returns an Attribute; check {@link Attribute.IsValid}. */
886
+ GetAttribute(name) {
887
+ return new Attribute(this, name, this.attrMap().get(name) ?? null);
888
+ }
889
+ HasAttribute(name) {
890
+ return this.attrMap().has(name);
891
+ }
892
+ GetAttributes() {
893
+ return [...this.attrMap().values()].map((spec) => new Attribute(this, spec.name, spec));
894
+ }
895
+ // -- Relationships -------------------------------------------------------
896
+ relMap() {
897
+ if (!this._relationships) {
898
+ this._relationships = /* @__PURE__ */ new Map();
899
+ for (const p of this._spec?.properties ?? []) {
900
+ if (p.kind === "relationship") this._relationships.set(p.name, p);
901
+ }
902
+ }
903
+ return this._relationships;
904
+ }
905
+ /** Always returns a Relationship; check {@link Relationship.IsValid}. */
906
+ GetRelationship(name) {
907
+ return new Relationship(this, name, this.relMap().get(name) ?? null);
908
+ }
909
+ HasRelationship(name) {
910
+ return this.relMap().has(name);
911
+ }
912
+ GetRelationships() {
913
+ return [...this.relMap().values()].map((spec) => new Relationship(this, spec.name, spec));
914
+ }
915
+ // -- Metadata / schemas --------------------------------------------------
916
+ GetMetadata(key) {
917
+ return this._spec?.metadata[key];
918
+ }
919
+ GetAllMetadata() {
920
+ return this._spec?.metadata ?? {};
921
+ }
922
+ /** Applied API schema names from `apiSchemas` (e.g. `PhysicsArticulationRootAPI`). */
923
+ GetAppliedSchemas() {
924
+ const raw = this._spec?.metadata.apiSchemas;
925
+ if (!Array.isArray(raw)) return [];
926
+ const out = [];
927
+ for (const v of raw) {
928
+ if (typeof v === "string") out.push(v);
929
+ }
930
+ return out;
931
+ }
932
+ /**
933
+ * Whether the given API schema is applied. Matches the bare schema name as
934
+ * well as multi-apply instances (e.g. `HasAPI("PhysicsDriveAPI")` is true for
935
+ * an applied `PhysicsDriveAPI:angular`).
936
+ */
937
+ HasAPI(schemaName) {
938
+ return this.GetAppliedSchemas().some((s) => s === schemaName || s.startsWith(`${schemaName}:`));
939
+ }
940
+ };
941
+
942
+ // src/usd/Stage.ts
943
+ var DEFAULT_METERS_PER_UNIT = 0.01;
944
+ var Stage = class _Stage {
945
+ _layer;
946
+ _byPath = /* @__PURE__ */ new Map();
947
+ _pseudoRoot;
948
+ constructor(file) {
949
+ this._layer = new Layer(file);
950
+ this._pseudoRoot = new Prim(this, null, "/", null);
951
+ this._byPath.set("/", this._pseudoRoot);
952
+ for (const spec of file.prims) this.buildPrim(spec, this._pseudoRoot);
953
+ }
954
+ /** Parse and open a stage from USDA source text. */
955
+ static OpenFromString(usda) {
956
+ return new _Stage(parseUsda(usda));
957
+ }
958
+ /** Open a stage from an already-parsed layer. */
959
+ static OpenFromFile(file) {
960
+ return new _Stage(file);
961
+ }
962
+ buildPrim(spec, parent) {
963
+ const path = parent.IsPseudoRoot() ? `/${spec.name}` : `${parent.GetPath()}/${spec.name}`;
964
+ const prim = new Prim(this, spec, path, parent);
965
+ this._byPath.set(path, prim);
966
+ parent._addChild(prim);
967
+ for (const child of spec.children) this.buildPrim(child, prim);
968
+ }
969
+ GetRootLayer() {
970
+ return this._layer;
971
+ }
972
+ GetPseudoRoot() {
973
+ return this._pseudoRoot;
974
+ }
975
+ /** Returns the prim at the absolute path, or `null` if none exists. */
976
+ GetPrimAtPath(path) {
977
+ return this._byPath.get(path) ?? null;
978
+ }
979
+ /** The stage's default prim (from layer `defaultPrim` metadata), if any. */
980
+ GetDefaultPrim() {
981
+ const name = this._layer.GetDefaultPrimName();
982
+ return name ? this.GetPrimAtPath(`/${name}`) : null;
983
+ }
984
+ /** Depth-first traversal of all prims (excludes the pseudo-root). */
985
+ Traverse() {
986
+ const out = [];
987
+ const visit = (prim) => {
988
+ for (const child of prim.GetChildren()) {
989
+ out.push(child);
990
+ visit(child);
991
+ }
992
+ };
993
+ visit(this._pseudoRoot);
994
+ return out;
995
+ }
996
+ GetMetadata(key) {
997
+ return this._layer.GetMetadata(key);
998
+ }
999
+ /** Stage up axis (`upAxis` metadata); defaults to `"Y"` per OpenUSD. */
1000
+ GetUpAxis() {
1001
+ return this._layer.GetMetadata("upAxis") === "Z" ? "Z" : "Y";
1002
+ }
1003
+ /** Stage linear unit (`metersPerUnit` metadata); defaults to {@link DEFAULT_METERS_PER_UNIT}. */
1004
+ GetMetersPerUnit() {
1005
+ const v = this._layer.GetMetadata("metersPerUnit");
1006
+ return typeof v === "number" ? v : DEFAULT_METERS_PER_UNIT;
1007
+ }
1008
+ };
1009
+
1010
+ // src/usd/AssetResolver.ts
1011
+ var DefaultAssetResolver = class {
1012
+ resolve(assetPath, baseUrl) {
1013
+ try {
1014
+ return new URL(assetPath, baseUrl || void 0).href;
1015
+ } catch {
1016
+ return joinPosix(baseUrl, assetPath);
1017
+ }
1018
+ }
1019
+ async fetchText(url) {
1020
+ const res = await fetch(url);
1021
+ if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
1022
+ return res.text();
1023
+ }
1024
+ async fetchBytes(url) {
1025
+ const res = await fetch(url);
1026
+ if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
1027
+ return new Uint8Array(await res.arrayBuffer());
1028
+ }
1029
+ };
1030
+ function createMemoryResolver(files) {
1031
+ return {
1032
+ resolve(assetPath, baseUrl) {
1033
+ return joinPosix(baseUrl, assetPath);
1034
+ },
1035
+ fetchText(url) {
1036
+ const text = files[url];
1037
+ if (text === void 0) return Promise.reject(new Error(`asset not found: ${url}`));
1038
+ return Promise.resolve(text);
1039
+ }
1040
+ };
1041
+ }
1042
+ function joinPosix(baseUrl, rel) {
1043
+ if (rel.startsWith("/")) return normalizePosix(rel);
1044
+ const dir = baseUrl.slice(0, baseUrl.lastIndexOf("/") + 1);
1045
+ return normalizePosix(dir + rel);
1046
+ }
1047
+ function normalizePosix(path) {
1048
+ const isAbsolute = path.startsWith("/");
1049
+ const out = [];
1050
+ for (const part of path.split("/")) {
1051
+ if (part === "" || part === ".") continue;
1052
+ if (part === "..") out.pop();
1053
+ else out.push(part);
1054
+ }
1055
+ return (isAbsolute ? "/" : "") + out.join("/");
1056
+ }
1057
+
1058
+ // src/usd/composition.ts
1059
+ var ARC_KEYS = ["references", "payload", "payloads"];
1060
+ async function composeLayer(text, baseUrl, resolver, options = {}, stack = /* @__PURE__ */ new Set()) {
1061
+ const warn = options.onWarn ?? (() => {
1062
+ });
1063
+ const file = parseUsda(text);
1064
+ let weak = [];
1065
+ const subLayers = toArcs(file.metadata.subLayers);
1066
+ for (let i = subLayers.length - 1; i >= 0; i--) {
1067
+ const sub = await loadComposedFile(subLayers[i], baseUrl, resolver, options, stack, warn);
1068
+ if (sub) weak = mergePrimLists(weak, sub.prims);
1069
+ }
1070
+ const resolved = [];
1071
+ for (const prim of file.prims) {
1072
+ resolved.push(await resolvePrimArcs(prim, baseUrl, resolver, options, stack, warn));
1073
+ }
1074
+ const prims = weak.length > 0 ? mergePrimLists(weak, resolved) : resolved;
1075
+ return { version: file.version, metadata: stripKeys(file.metadata, ["subLayers"]), prims };
1076
+ }
1077
+ async function resolvePrimArcs(spec, baseUrl, resolver, options, stack, warn) {
1078
+ const children = [];
1079
+ for (const child of spec.children) {
1080
+ children.push(await resolvePrimArcs(child, baseUrl, resolver, options, stack, warn));
1081
+ }
1082
+ const local = { ...spec, children, metadata: stripKeys(spec.metadata, ARC_KEYS) };
1083
+ const arcs = ARC_KEYS.flatMap((k) => toArcs(spec.metadata[k]));
1084
+ if (arcs.length === 0) return local;
1085
+ let base = null;
1086
+ for (const arc of arcs) {
1087
+ const target = await loadReferencedPrim(arc, baseUrl, resolver, options, stack, warn);
1088
+ if (!target) continue;
1089
+ base = base ? mergePrim(target, base) : target;
1090
+ }
1091
+ return base ? mergePrim(base, local) : local;
1092
+ }
1093
+ async function loadReferencedPrim(arc, baseUrl, resolver, options, stack, warn) {
1094
+ if (!arc.assetPath) {
1095
+ warn(`internal references (no asset path) are not supported yet: <${arc.primPath ?? "?"}>`);
1096
+ return null;
1097
+ }
1098
+ const composed = await loadComposedFile(arc, baseUrl, resolver, options, stack, warn);
1099
+ if (!composed) return null;
1100
+ const target = arc.primPath ? findPrimByPath(composed, arc.primPath) : defaultPrim(composed, warn);
1101
+ if (!target) {
1102
+ warn(`reference target ${arc.primPath ?? "(defaultPrim)"} not found in ${arc.assetPath.path}`);
1103
+ return null;
1104
+ }
1105
+ return target;
1106
+ }
1107
+ async function loadComposedFile(arc, baseUrl, resolver, options, stack, warn) {
1108
+ if (!arc.assetPath) return null;
1109
+ const url = resolver.resolve(arc.assetPath.path, baseUrl);
1110
+ if (stack.has(url)) {
1111
+ warn(`composition cycle detected at ${url}; skipping`);
1112
+ return null;
1113
+ }
1114
+ if (stack.size >= (options.maxDepth ?? 64)) {
1115
+ warn(`composition exceeded max depth at ${url}; skipping`);
1116
+ return null;
1117
+ }
1118
+ let text;
1119
+ try {
1120
+ text = await resolver.fetchText(url);
1121
+ } catch (err) {
1122
+ warn(`cannot resolve "${arc.assetPath.path}" -> ${url}: ${err.message}`);
1123
+ return null;
1124
+ }
1125
+ return composeLayer(text, url, resolver, options, /* @__PURE__ */ new Set([...stack, url]));
1126
+ }
1127
+ function mergePrim(base, over) {
1128
+ return {
1129
+ // `over` (def) wins; a pure `over` opinion keeps the base's specifier.
1130
+ specifier: over.specifier === "over" ? base.specifier : over.specifier,
1131
+ typeName: over.typeName || base.typeName,
1132
+ name: over.name,
1133
+ metadata: mergeMetadata(base.metadata, over.metadata),
1134
+ properties: mergeProperties(base.properties, over.properties),
1135
+ children: mergePrimLists(base.children, over.children),
1136
+ line: over.line
1137
+ };
1138
+ }
1139
+ function mergePrimLists(base, over) {
1140
+ const byName = /* @__PURE__ */ new Map();
1141
+ for (const p of base) byName.set(p.name, p);
1142
+ for (const p of over) {
1143
+ const existing = byName.get(p.name);
1144
+ byName.set(p.name, existing ? mergePrim(existing, p) : p);
1145
+ }
1146
+ return [...byName.values()];
1147
+ }
1148
+ function mergeProperties(base, over) {
1149
+ const byName = /* @__PURE__ */ new Map();
1150
+ for (const p of base) byName.set(p.name, p);
1151
+ for (const p of over) {
1152
+ const existing = byName.get(p.name);
1153
+ byName.set(p.name, existing ? mergeProperty(existing, p) : p);
1154
+ }
1155
+ return [...byName.values()];
1156
+ }
1157
+ function mergeProperty(base, over) {
1158
+ if (base.kind !== over.kind) return over;
1159
+ if (base.kind === "attribute" && over.kind === "attribute") {
1160
+ const merged = {
1161
+ ...over,
1162
+ typeName: over.typeName || base.typeName,
1163
+ metadata: mergeMetadata(base.metadata, over.metadata)
1164
+ };
1165
+ const value = over.value !== void 0 ? over.value : base.value;
1166
+ if (value !== void 0) merged.value = value;
1167
+ const timeSamples = over.timeSamples ?? base.timeSamples;
1168
+ if (timeSamples) merged.timeSamples = timeSamples;
1169
+ const connections = over.connections ?? base.connections;
1170
+ if (connections) merged.connections = connections;
1171
+ return merged;
1172
+ }
1173
+ if (base.kind === "relationship" && over.kind === "relationship") {
1174
+ return {
1175
+ ...over,
1176
+ targets: over.targets.length > 0 ? over.targets : base.targets,
1177
+ metadata: mergeMetadata(base.metadata, over.metadata)
1178
+ };
1179
+ }
1180
+ return over;
1181
+ }
1182
+ function mergeMetadata(base, over) {
1183
+ const merged = { ...base, ...over };
1184
+ const a = base.apiSchemas;
1185
+ const b = over.apiSchemas;
1186
+ if (Array.isArray(a) || Array.isArray(b)) {
1187
+ const seen = /* @__PURE__ */ new Set();
1188
+ const union = [];
1189
+ for (const v of [...Array.isArray(a) ? a : [], ...Array.isArray(b) ? b : []]) {
1190
+ if (!seen.has(v)) {
1191
+ seen.add(v);
1192
+ union.push(v);
1193
+ }
1194
+ }
1195
+ merged.apiSchemas = union;
1196
+ }
1197
+ return merged;
1198
+ }
1199
+ function findPrimByPath(file, path) {
1200
+ const segments = path.split("/").filter(Boolean);
1201
+ let level = file.prims;
1202
+ let found = null;
1203
+ for (const seg of segments) {
1204
+ found = level.find((p) => p.name === seg) ?? null;
1205
+ if (!found) return null;
1206
+ level = found.children;
1207
+ }
1208
+ return found;
1209
+ }
1210
+ function defaultPrim(file, warn) {
1211
+ const name = file.metadata.defaultPrim;
1212
+ if (typeof name === "string") {
1213
+ return file.prims.find((p) => p.name === name) ?? null;
1214
+ }
1215
+ const first = file.prims[0];
1216
+ if (first) warn(`referenced layer has no defaultPrim; using first root prim "${first.name}"`);
1217
+ return first ?? null;
1218
+ }
1219
+ function toArcs(value) {
1220
+ if (value === void 0) return [];
1221
+ const list = Array.isArray(value) ? value : [value];
1222
+ const arcs = [];
1223
+ for (const v of list) {
1224
+ if (v instanceof AssetPath) arcs.push({ assetPath: v });
1225
+ else if (v && typeof v === "object" && "assetPath" in v) arcs.push(v);
1226
+ }
1227
+ return arcs;
1228
+ }
1229
+ function stripKeys(meta, keys) {
1230
+ const out = {};
1231
+ for (const [k, v] of Object.entries(meta)) {
1232
+ if (!keys.includes(k)) out[k] = v;
1233
+ }
1234
+ return out;
1235
+ }
1236
+ var USD_ENTRY = /\.(usda|usdc|usd)$/i;
1237
+ function openUsdz(bytes) {
1238
+ const entries = unzipSync(bytes);
1239
+ const names = Object.keys(entries);
1240
+ const rootEntry = names.find((n) => USD_ENTRY.test(n)) ?? names[0];
1241
+ if (!rootEntry) throw new Error("usdz package contains no entries");
1242
+ const decoder = new TextDecoder();
1243
+ const resolver = {
1244
+ resolve(assetPath, baseUrl) {
1245
+ return joinPosix(baseUrl, assetPath);
1246
+ },
1247
+ fetchText(url) {
1248
+ const data = entries[url] ?? entries[url.replace(/^\/+/, "")];
1249
+ if (!data) return Promise.reject(new Error(`not found in usdz: ${url}`));
1250
+ if (/\.usdc$/i.test(url)) {
1251
+ return Promise.reject(
1252
+ new Error(`USDC (binary crate) entries are not supported yet (M10): ${url}`)
1253
+ );
1254
+ }
1255
+ return Promise.resolve(decoder.decode(data));
1256
+ }
1257
+ };
1258
+ return { rootEntry, resolver };
1259
+ }
1260
+
1261
+ // src/usd/crate/lz4.ts
1262
+ var MAX_CHUNK_INPUT = 2113929216;
1263
+ function lz4DecompressBlock(src, dst) {
1264
+ let s = 0;
1265
+ let d = 0;
1266
+ const n = src.length;
1267
+ while (s < n) {
1268
+ const token = src[s++];
1269
+ let literals = token >> 4;
1270
+ if (literals === 15) {
1271
+ let add;
1272
+ do {
1273
+ add = src[s++];
1274
+ literals += add;
1275
+ } while (add === 255);
1276
+ }
1277
+ for (let i = 0; i < literals; i++) dst[d++] = src[s++];
1278
+ if (s >= n) break;
1279
+ const offset = src[s++] | src[s++] << 8;
1280
+ let matchLen = token & 15;
1281
+ if (matchLen === 15) {
1282
+ let add;
1283
+ do {
1284
+ add = src[s++];
1285
+ matchLen += add;
1286
+ } while (add === 255);
1287
+ }
1288
+ matchLen += 4;
1289
+ let m = d - offset;
1290
+ for (let i = 0; i < matchLen; i++) dst[d++] = dst[m++];
1291
+ }
1292
+ return d;
1293
+ }
1294
+ function fastDecompress(src, decompressedSize) {
1295
+ const out = new Uint8Array(decompressedSize);
1296
+ const view = new DataView(src.buffer, src.byteOffset, src.byteLength);
1297
+ const numWholeChunks = src[0];
1298
+ let s = 1;
1299
+ let d = 0;
1300
+ for (let c = 0; c < numWholeChunks; c++) {
1301
+ const chunkCompressedSize = view.getInt32(s, true);
1302
+ s += 4;
1303
+ lz4DecompressBlock(
1304
+ src.subarray(s, s + chunkCompressedSize),
1305
+ out.subarray(d, d + MAX_CHUNK_INPUT)
1306
+ );
1307
+ s += chunkCompressedSize;
1308
+ d += MAX_CHUNK_INPUT;
1309
+ }
1310
+ if (d < decompressedSize) {
1311
+ lz4DecompressBlock(src.subarray(s), out.subarray(d));
1312
+ }
1313
+ return out;
1314
+ }
1315
+
1316
+ // src/usd/crate/integerCompression.ts
1317
+ function decodeIntegers32(compressed, numInts) {
1318
+ if (numInts === 0) return [];
1319
+ const codeBytes = Math.ceil(numInts / 4);
1320
+ const worstCase = 4 + codeBytes + numInts * 4;
1321
+ const encoded = fastDecompress(compressed, worstCase);
1322
+ const view = new DataView(encoded.buffer, encoded.byteOffset, encoded.byteLength);
1323
+ const commonDelta = view.getInt32(0, true);
1324
+ const codesStart = 4;
1325
+ let p = codesStart + codeBytes;
1326
+ const out = new Array(numInts);
1327
+ let prev = 0;
1328
+ for (let i = 0; i < numInts; i++) {
1329
+ const code = encoded[codesStart + (i >> 2)] >> (i & 3) * 2 & 3;
1330
+ let delta;
1331
+ if (code === 0) {
1332
+ delta = commonDelta;
1333
+ } else if (code === 1) {
1334
+ delta = view.getInt8(p);
1335
+ p += 1;
1336
+ } else if (code === 2) {
1337
+ delta = view.getInt16(p, true);
1338
+ p += 2;
1339
+ } else {
1340
+ delta = view.getInt32(p, true);
1341
+ p += 4;
1342
+ }
1343
+ prev += delta;
1344
+ out[i] = prev;
1345
+ }
1346
+ return out;
1347
+ }
1348
+
1349
+ // src/usd/crate/valueTypes.ts
1350
+ var CrateType = {
1351
+ Bool: 1,
1352
+ UChar: 2,
1353
+ Int: 3,
1354
+ UInt: 4,
1355
+ Int64: 5,
1356
+ UInt64: 6,
1357
+ Half: 7,
1358
+ Float: 8,
1359
+ Double: 9,
1360
+ String: 10,
1361
+ Token: 11,
1362
+ AssetPath: 12,
1363
+ Matrix3d: 14,
1364
+ Matrix4d: 15,
1365
+ Quatd: 16,
1366
+ Quatf: 17,
1367
+ Vec2d: 19,
1368
+ Vec2f: 20,
1369
+ Vec3d: 23,
1370
+ Vec3f: 24,
1371
+ Vec4d: 27,
1372
+ Vec4f: 28,
1373
+ TokenListOp: 32,
1374
+ PathListOp: 34,
1375
+ IntListOp: 36,
1376
+ PathVector: 40,
1377
+ TokenVector: 41,
1378
+ Specifier: 42,
1379
+ Permission: 43,
1380
+ Variability: 44};
1381
+ var ListOpBits = {
1382
+ HasExplicit: 1 << 1,
1383
+ HasAdded: 1 << 2,
1384
+ HasDeleted: 1 << 3,
1385
+ HasOrdered: 1 << 4,
1386
+ HasPrepended: 1 << 5,
1387
+ HasAppended: 1 << 6
1388
+ };
1389
+ function decodeRepBits(rep) {
1390
+ return {
1391
+ isArray: (rep & 1n << 63n) !== 0n,
1392
+ isInlined: (rep & 1n << 62n) !== 0n,
1393
+ isCompressed: (rep & 1n << 61n) !== 0n,
1394
+ type: Number(rep >> 48n & 0xffn),
1395
+ payload: rep & (1n << 48n) - 1n
1396
+ };
1397
+ }
1398
+ function halfToFloat(h) {
1399
+ const sign = (h & 32768) >> 15;
1400
+ const exp = (h & 31744) >> 10;
1401
+ const frac = h & 1023;
1402
+ let value;
1403
+ if (exp === 0) value = frac / 1024;
1404
+ else if (exp === 31) value = frac ? Number.NaN : Number.POSITIVE_INFINITY;
1405
+ else return (sign ? -1 : 1) * 2 ** (exp - 15) * (1 + frac / 1024);
1406
+ return (sign ? -1 : 1) * (exp === 0 ? 2 ** -14 * value : value);
1407
+ }
1408
+
1409
+ // src/usd/crate/CrateReader.ts
1410
+ var MAGIC = "PXR-USDC";
1411
+ var scratch = new DataView(new ArrayBuffer(8));
1412
+ var FIELDSET_END = -1;
1413
+ var CrateReader = class {
1414
+ version;
1415
+ view;
1416
+ bytes;
1417
+ sections = /* @__PURE__ */ new Map();
1418
+ _tokens;
1419
+ _strings;
1420
+ _fields;
1421
+ _fieldSets;
1422
+ _paths;
1423
+ _specs;
1424
+ constructor(bytes) {
1425
+ this.bytes = bytes;
1426
+ this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
1427
+ const magic = asciiAt(bytes, 0, 8);
1428
+ if (magic !== MAGIC) {
1429
+ throw new Error(`not a USDC crate file (magic ${JSON.stringify(magic)})`);
1430
+ }
1431
+ this.version = [bytes[8] ?? 0, bytes[9] ?? 0, bytes[10] ?? 0];
1432
+ const tocOffset = this.u64(16);
1433
+ this.readToc(tocOffset);
1434
+ }
1435
+ /** True if `bytes` begins with the crate magic. */
1436
+ static isCrate(bytes) {
1437
+ return asciiAt(bytes, 0, 8) === MAGIC;
1438
+ }
1439
+ getSection(name) {
1440
+ return this.sections.get(name);
1441
+ }
1442
+ /** Read a little-endian uint64 as a JS number (safe for crate-sized files). */
1443
+ u64(offset) {
1444
+ return Number(this.view.getBigUint64(offset, true));
1445
+ }
1446
+ i64(offset) {
1447
+ return this.view.getBigInt64(offset, true);
1448
+ }
1449
+ readToc(offset) {
1450
+ const count = this.u64(offset);
1451
+ let p = offset + 8;
1452
+ for (let i = 0; i < count; i++) {
1453
+ const name = asciiAt(this.bytes, p, 16).replace(/\0+$/, "");
1454
+ const start = this.u64(p + 16);
1455
+ const size = this.u64(p + 24);
1456
+ this.sections.set(name, { name, start, size });
1457
+ p += 32;
1458
+ }
1459
+ }
1460
+ // --- TOKENS -------------------------------------------------------------
1461
+ getTokens() {
1462
+ if (!this._tokens) this._tokens = this.readTokens();
1463
+ return this._tokens;
1464
+ }
1465
+ getToken(index) {
1466
+ return this.getTokens()[index] ?? "";
1467
+ }
1468
+ readTokens() {
1469
+ const section = this.sections.get("TOKENS");
1470
+ if (!section) return [];
1471
+ let p = section.start;
1472
+ const numTokens = this.u64(p);
1473
+ p += 8;
1474
+ const uncompressedSize = this.u64(p);
1475
+ p += 8;
1476
+ const compressedSize = this.u64(p);
1477
+ p += 8;
1478
+ const compressed = this.bytes.subarray(p, p + compressedSize);
1479
+ const buffer = fastDecompress(compressed, uncompressedSize);
1480
+ const tokens = [];
1481
+ const decoder = new TextDecoder();
1482
+ let start = 0;
1483
+ for (let i = 0; i < buffer.length && tokens.length < numTokens; i++) {
1484
+ if (buffer[i] === 0) {
1485
+ tokens.push(decoder.decode(buffer.subarray(start, i)));
1486
+ start = i + 1;
1487
+ }
1488
+ }
1489
+ return tokens;
1490
+ }
1491
+ // --- STRINGS ------------------------------------------------------------
1492
+ /** String values are token indices. */
1493
+ getStrings() {
1494
+ if (!this._strings) this._strings = this.readStrings();
1495
+ return this._strings;
1496
+ }
1497
+ readStrings() {
1498
+ const section = this.sections.get("STRINGS");
1499
+ if (!section) return [];
1500
+ const count = this.u64(section.start);
1501
+ const out = new Array(count);
1502
+ let p = section.start + 8;
1503
+ for (let i = 0; i < count; i++) {
1504
+ out[i] = this.view.getUint32(p, true);
1505
+ p += 4;
1506
+ }
1507
+ return out;
1508
+ }
1509
+ /** Read a `TfFastCompression`-wrapped, delta+integer-compressed array of `count` ints. */
1510
+ readCompressedInts(p, count) {
1511
+ const compressedSize = this.u64(p);
1512
+ const dataStart = p + 8;
1513
+ const buf = this.bytes.subarray(dataStart, dataStart + compressedSize);
1514
+ return { values: decodeIntegers32(buf, count), next: dataStart + compressedSize };
1515
+ }
1516
+ // --- FIELDS -------------------------------------------------------------
1517
+ getFields() {
1518
+ if (!this._fields) this._fields = this.readFields();
1519
+ return this._fields;
1520
+ }
1521
+ readFields() {
1522
+ const section = this.sections.get("FIELDS");
1523
+ if (!section) return [];
1524
+ let p = section.start;
1525
+ const numFields = this.u64(p);
1526
+ p += 8;
1527
+ const names = this.readCompressedInts(p, numFields);
1528
+ p = names.next;
1529
+ const repsCompressedSize = this.u64(p);
1530
+ p += 8;
1531
+ const repsBuf = this.bytes.subarray(p, p + repsCompressedSize);
1532
+ const repBytes = fastDecompress(repsBuf, numFields * 8);
1533
+ const repView = new DataView(repBytes.buffer, repBytes.byteOffset, repBytes.byteLength);
1534
+ const fields = new Array(numFields);
1535
+ for (let i = 0; i < numFields; i++) {
1536
+ fields[i] = { nameIndex: names.values[i], rep: repView.getBigUint64(i * 8, true) };
1537
+ }
1538
+ return fields;
1539
+ }
1540
+ // --- FIELDSETS ----------------------------------------------------------
1541
+ getFieldSets() {
1542
+ if (!this._fieldSets) this._fieldSets = this.readFieldSets();
1543
+ return this._fieldSets;
1544
+ }
1545
+ readFieldSets() {
1546
+ const section = this.sections.get("FIELDSETS");
1547
+ if (!section) return [];
1548
+ const numFieldSets = this.u64(section.start);
1549
+ return this.readCompressedInts(section.start + 8, numFieldSets).values;
1550
+ }
1551
+ /** The field indices of the field set starting at `index` (until the sentinel). */
1552
+ getFieldSet(index) {
1553
+ const all = this.getFieldSets();
1554
+ const out = [];
1555
+ for (let i = index; i < all.length && all[i] !== FIELDSET_END; i++) {
1556
+ out.push(all[i]);
1557
+ }
1558
+ return out;
1559
+ }
1560
+ // --- PATHS --------------------------------------------------------------
1561
+ getPaths() {
1562
+ if (!this._paths) this._paths = this.readPaths();
1563
+ return this._paths;
1564
+ }
1565
+ readPaths() {
1566
+ const section = this.sections.get("PATHS");
1567
+ if (!section) return [];
1568
+ let p = section.start;
1569
+ const numPaths = this.u64(p);
1570
+ p += 8;
1571
+ const numEncoded = this.u64(p);
1572
+ p += 8;
1573
+ const pathIndexes = this.readCompressedInts(p, numEncoded);
1574
+ p = pathIndexes.next;
1575
+ const elementTokenIndexes = this.readCompressedInts(p, numEncoded);
1576
+ p = elementTokenIndexes.next;
1577
+ const jumps = this.readCompressedInts(p, numEncoded);
1578
+ const paths = new Array(numPaths).fill("");
1579
+ this.buildPaths(pathIndexes.values, elementTokenIndexes.values, jumps.values, 0, "", paths);
1580
+ return paths;
1581
+ }
1582
+ /** Reconstruct path strings from the compressed path tree (pxr `_BuildDecompressedPathsImpl`). */
1583
+ buildPaths(pathIndexes, elementTokenIndexes, jumps, startIndex, parentPath, paths) {
1584
+ let curIndex = startIndex;
1585
+ let parent = parentPath;
1586
+ let hasChild = false;
1587
+ let hasSibling = false;
1588
+ do {
1589
+ const thisIndex = curIndex++;
1590
+ const pathIdx = pathIndexes[thisIndex];
1591
+ if (parent === "") {
1592
+ paths[pathIdx] = "/";
1593
+ parent = "/";
1594
+ } else {
1595
+ let tokenIndex = elementTokenIndexes[thisIndex];
1596
+ const isProperty = tokenIndex < 0;
1597
+ if (tokenIndex < 0) tokenIndex = -tokenIndex;
1598
+ const elem = this.getToken(tokenIndex);
1599
+ paths[pathIdx] = appendElement(parent, elem, isProperty);
1600
+ }
1601
+ const jump = jumps[thisIndex];
1602
+ hasChild = jump > 0 || jump === -1;
1603
+ hasSibling = jump >= 0;
1604
+ if (hasChild) {
1605
+ if (hasSibling) {
1606
+ this.buildPaths(pathIndexes, elementTokenIndexes, jumps, thisIndex + jump, parent, paths);
1607
+ }
1608
+ parent = paths[pathIdx];
1609
+ }
1610
+ } while (hasChild || hasSibling);
1611
+ }
1612
+ // --- SPECS --------------------------------------------------------------
1613
+ getSpecs() {
1614
+ if (!this._specs) this._specs = this.readSpecs();
1615
+ return this._specs;
1616
+ }
1617
+ readSpecs() {
1618
+ const section = this.sections.get("SPECS");
1619
+ if (!section) return [];
1620
+ let p = section.start;
1621
+ const numSpecs = this.u64(p);
1622
+ p += 8;
1623
+ const pathIndexes = this.readCompressedInts(p, numSpecs);
1624
+ p = pathIndexes.next;
1625
+ const fieldSetIndexes = this.readCompressedInts(p, numSpecs);
1626
+ p = fieldSetIndexes.next;
1627
+ const specTypes = this.readCompressedInts(p, numSpecs);
1628
+ const specs = new Array(numSpecs);
1629
+ for (let i = 0; i < numSpecs; i++) {
1630
+ specs[i] = {
1631
+ pathIndex: pathIndexes.values[i],
1632
+ fieldSetIndex: fieldSetIndexes.values[i],
1633
+ specType: specTypes.values[i]
1634
+ };
1635
+ }
1636
+ return specs;
1637
+ }
1638
+ // --- Values -------------------------------------------------------------
1639
+ /** Decode a `ValueRep` into a {@link UsdValue} (or `undefined` if unsupported). */
1640
+ getValue(rep) {
1641
+ const b = decodeRepBits(rep);
1642
+ if (b.isArray) return this.readArray(b.type, Number(b.payload), b.isCompressed);
1643
+ if (b.isInlined) return this.readInlined(b.type, b.payload);
1644
+ return this.readScalar(b.type, Number(b.payload));
1645
+ }
1646
+ readInlined(type, payload) {
1647
+ const low = Number(payload & 0xffffffffn);
1648
+ switch (type) {
1649
+ case CrateType.Bool:
1650
+ return payload !== 0n;
1651
+ case CrateType.UChar:
1652
+ return low & 255;
1653
+ case CrateType.Int:
1654
+ case CrateType.Int64:
1655
+ return low | 0;
1656
+ case CrateType.UInt:
1657
+ case CrateType.UInt64:
1658
+ return low >>> 0;
1659
+ case CrateType.Half:
1660
+ return halfToFloat(low & 65535);
1661
+ case CrateType.Float:
1662
+ case CrateType.Double:
1663
+ scratch.setUint32(0, low >>> 0, true);
1664
+ return scratch.getFloat32(0, true);
1665
+ case CrateType.Token:
1666
+ return this.getToken(low);
1667
+ case CrateType.String:
1668
+ return this.getToken(this.getStrings()[low] ?? 0);
1669
+ case CrateType.AssetPath:
1670
+ return new AssetPath(this.getToken(low));
1671
+ case CrateType.Specifier:
1672
+ case CrateType.Permission:
1673
+ case CrateType.Variability:
1674
+ return low;
1675
+ default:
1676
+ return void 0;
1677
+ }
1678
+ }
1679
+ readScalar(type, off) {
1680
+ const v = this.view;
1681
+ switch (type) {
1682
+ case CrateType.Float:
1683
+ return v.getFloat32(off, true);
1684
+ case CrateType.Double:
1685
+ return v.getFloat64(off, true);
1686
+ case CrateType.Half:
1687
+ return halfToFloat(v.getUint16(off, true));
1688
+ case CrateType.Int:
1689
+ return v.getInt32(off, true);
1690
+ case CrateType.UInt:
1691
+ return v.getUint32(off, true);
1692
+ case CrateType.Token:
1693
+ return this.getToken(v.getUint32(off, true));
1694
+ case CrateType.String:
1695
+ return this.getToken(this.getStrings()[v.getUint32(off, true)] ?? 0);
1696
+ case CrateType.AssetPath:
1697
+ return new AssetPath(this.getToken(v.getUint32(off, true)));
1698
+ case CrateType.Vec2f:
1699
+ return this.readFloat32s(off, 2);
1700
+ case CrateType.Vec3f:
1701
+ return this.readFloat32s(off, 3);
1702
+ case CrateType.Vec4f:
1703
+ return this.readFloat32s(off, 4);
1704
+ case CrateType.Vec2d:
1705
+ return this.readFloat64s(off, 2);
1706
+ case CrateType.Vec3d:
1707
+ return this.readFloat64s(off, 3);
1708
+ case CrateType.Vec4d:
1709
+ return this.readFloat64s(off, 4);
1710
+ case CrateType.Quatf: {
1711
+ const q = this.readFloat32s(off, 4);
1712
+ return new Quat(q[3], [q[0], q[1], q[2]]);
1713
+ }
1714
+ case CrateType.Quatd: {
1715
+ const q = this.readFloat64s(off, 4);
1716
+ return new Quat(q[3], [q[0], q[1], q[2]]);
1717
+ }
1718
+ case CrateType.Matrix4d:
1719
+ return new UsdMatrix(this.readFloat64s(off, 16), 4);
1720
+ case CrateType.Matrix3d:
1721
+ return new UsdMatrix(this.readFloat64s(off, 9), 3);
1722
+ case CrateType.TokenListOp:
1723
+ case CrateType.IntListOp:
1724
+ return this.readListOp(off, "token");
1725
+ case CrateType.PathListOp:
1726
+ return this.readListOp(off, "path");
1727
+ case CrateType.TokenVector:
1728
+ return this.readIndexVector(off, "token").items;
1729
+ case CrateType.PathVector:
1730
+ return this.readIndexVector(off, "path").items;
1731
+ default:
1732
+ return void 0;
1733
+ }
1734
+ }
1735
+ readArray(type, off, compressed) {
1736
+ if (off === 0) return [];
1737
+ const count = this.u64(off);
1738
+ let p = off + 8;
1739
+ if (compressed) {
1740
+ const compressedSize = this.u64(p);
1741
+ p += 8;
1742
+ return decodeIntegers32(this.bytes.subarray(p, p + compressedSize), count);
1743
+ }
1744
+ const v = this.view;
1745
+ switch (type) {
1746
+ case CrateType.Int:
1747
+ case CrateType.UInt: {
1748
+ const out = new Array(count);
1749
+ for (let i = 0; i < count; i++) out[i] = v.getInt32(p + i * 4, true);
1750
+ return out;
1751
+ }
1752
+ case CrateType.Float: {
1753
+ const out = new Array(count);
1754
+ for (let i = 0; i < count; i++) out[i] = v.getFloat32(p + i * 4, true);
1755
+ return out;
1756
+ }
1757
+ case CrateType.Token: {
1758
+ const out = new Array(count);
1759
+ for (let i = 0; i < count; i++) out[i] = this.getToken(v.getUint32(p + i * 4, true));
1760
+ return out;
1761
+ }
1762
+ case CrateType.Vec3f:
1763
+ return this.readVec3fArray(p, count, false);
1764
+ case CrateType.Vec3d:
1765
+ return this.readVec3fArray(p, count, true);
1766
+ default:
1767
+ return void 0;
1768
+ }
1769
+ }
1770
+ readFloat32s(off, n) {
1771
+ const out = new Array(n);
1772
+ for (let i = 0; i < n; i++) out[i] = this.view.getFloat32(off + i * 4, true);
1773
+ return out;
1774
+ }
1775
+ readFloat64s(off, n) {
1776
+ const out = new Array(n);
1777
+ for (let i = 0; i < n; i++) out[i] = this.view.getFloat64(off + i * 8, true);
1778
+ return out;
1779
+ }
1780
+ readVec3fArray(off, count, double) {
1781
+ const out = new Array(count);
1782
+ const stride = double ? 24 : 12;
1783
+ for (let i = 0; i < count; i++) {
1784
+ const o = off + i * stride;
1785
+ out[i] = double ? [
1786
+ this.view.getFloat64(o, true),
1787
+ this.view.getFloat64(o + 8, true),
1788
+ this.view.getFloat64(o + 16, true)
1789
+ ] : [
1790
+ this.view.getFloat32(o, true),
1791
+ this.view.getFloat32(o + 4, true),
1792
+ this.view.getFloat32(o + 8, true)
1793
+ ];
1794
+ }
1795
+ return out;
1796
+ }
1797
+ /** Read a `[u64 count][count × uint32|int32 index]` vector → resolved strings. */
1798
+ readIndexVector(off, kind) {
1799
+ const count = this.u64(off);
1800
+ let p = off + 8;
1801
+ const items = new Array(count);
1802
+ for (let i = 0; i < count; i++) {
1803
+ const idx = this.view.getInt32(p, true);
1804
+ items[i] = kind === "token" ? this.getToken(idx) : this.getPaths()[idx] ?? "";
1805
+ p += 4;
1806
+ }
1807
+ return { items, next: p };
1808
+ }
1809
+ /** Read an SdfListOp; returns the effective (explicit ∪ prepended ∪ added ∪ appended) items. */
1810
+ readListOp(off, kind) {
1811
+ const bits = this.bytes[off];
1812
+ let p = off + 1;
1813
+ const explicit = [];
1814
+ const prepended = [];
1815
+ const added = [];
1816
+ const appended = [];
1817
+ const read = (target) => {
1818
+ const r = this.readIndexVector(p, kind);
1819
+ target.push(...r.items);
1820
+ p = r.next;
1821
+ };
1822
+ if (bits & ListOpBits.HasExplicit) read(explicit);
1823
+ if (bits & ListOpBits.HasAdded) read(added);
1824
+ if (bits & ListOpBits.HasPrepended) read(prepended);
1825
+ if (bits & ListOpBits.HasAppended) read(appended);
1826
+ if (bits & ListOpBits.HasDeleted) read([]);
1827
+ if (bits & ListOpBits.HasOrdered) read([]);
1828
+ return [...explicit, ...prepended, ...added, ...appended];
1829
+ }
1830
+ };
1831
+ function appendElement(parent, elem, isProperty) {
1832
+ if (isProperty) return `${parent}.${elem}`;
1833
+ if (elem.startsWith("{")) return `${parent}${elem}`;
1834
+ return parent === "/" ? `/${elem}` : `${parent}/${elem}`;
1835
+ }
1836
+ function asciiAt(bytes, offset, length) {
1837
+ let out = "";
1838
+ for (let i = 0; i < length; i++) {
1839
+ const c = bytes[offset + i];
1840
+ if (c === void 0) break;
1841
+ out += String.fromCharCode(c);
1842
+ }
1843
+ return out;
1844
+ }
1845
+
1846
+ // src/usd/crate/toUsdaFile.ts
1847
+ var SPEC_PRIM = 6;
1848
+ var SPEC_PSEUDO_ROOT = 7;
1849
+ var SPEC_ATTRIBUTE = 1;
1850
+ var SPEC_RELATIONSHIP = 8;
1851
+ var SPECIFIERS2 = ["def", "over", "class"];
1852
+ function crateToUsdaFile(crate) {
1853
+ const paths = crate.getPaths();
1854
+ const specs = crate.getSpecs();
1855
+ const fields = crate.getFields();
1856
+ const fieldsOf = (fieldSetIndex) => {
1857
+ const map = /* @__PURE__ */ new Map();
1858
+ for (const fi of crate.getFieldSet(fieldSetIndex)) {
1859
+ const f = fields[fi];
1860
+ if (f) map.set(crate.getToken(f.nameIndex), f.rep);
1861
+ }
1862
+ return map;
1863
+ };
1864
+ const primByPath = /* @__PURE__ */ new Map();
1865
+ const rootPrims = [];
1866
+ let layerMetadata = {};
1867
+ for (const spec of specs) {
1868
+ const path = paths[spec.pathIndex] ?? "";
1869
+ if (spec.specType === SPEC_PSEUDO_ROOT) {
1870
+ layerMetadata = buildLayerMetadata(crate, fieldsOf(spec.fieldSetIndex));
1871
+ continue;
1872
+ }
1873
+ if (spec.specType !== SPEC_PRIM) continue;
1874
+ const fm = fieldsOf(spec.fieldSetIndex);
1875
+ primByPath.set(path, {
1876
+ specifier: SPECIFIERS2[asNumber(crate, fm.get("specifier")) ?? 0] ?? "def",
1877
+ typeName: asString(crate, fm.get("typeName")) ?? "",
1878
+ name: leaf(path),
1879
+ metadata: buildPrimMetadata(crate, fm),
1880
+ properties: [],
1881
+ children: [],
1882
+ line: 0
1883
+ });
1884
+ }
1885
+ for (const spec of specs) {
1886
+ if (spec.specType !== SPEC_ATTRIBUTE && spec.specType !== SPEC_RELATIONSHIP) continue;
1887
+ const split = splitProperty(paths[spec.pathIndex] ?? "");
1888
+ if (!split) continue;
1889
+ const prim = primByPath.get(split.primPath);
1890
+ if (!prim) continue;
1891
+ const fm = fieldsOf(spec.fieldSetIndex);
1892
+ prim.properties.push(
1893
+ spec.specType === SPEC_ATTRIBUTE ? buildAttribute(crate, split.propName, fm) : buildRelationship(crate, split.propName, fm)
1894
+ );
1895
+ }
1896
+ for (const [path, prim] of primByPath) {
1897
+ const parentPath = parentOf(path);
1898
+ if (parentPath === "/") rootPrims.push(prim);
1899
+ else primByPath.get(parentPath)?.children.push(prim);
1900
+ }
1901
+ return { version: crate.version.join("."), metadata: layerMetadata, prims: rootPrims };
1902
+ }
1903
+ function buildAttribute(crate, name, fm) {
1904
+ const defaultRep = fm.get("default");
1905
+ const attr = {
1906
+ kind: "attribute",
1907
+ name,
1908
+ typeName: asString(crate, fm.get("typeName")) ?? "",
1909
+ isArray: defaultRep !== void 0 ? decodeRepBits(defaultRep).isArray : false,
1910
+ variability: asNumber(crate, fm.get("variability")) === 1 ? "uniform" : "varying",
1911
+ custom: false,
1912
+ metadata: {},
1913
+ line: 0
1914
+ };
1915
+ if (defaultRep !== void 0) {
1916
+ const value = crate.getValue(defaultRep);
1917
+ if (value !== void 0) attr.value = value;
1918
+ }
1919
+ return attr;
1920
+ }
1921
+ function buildRelationship(crate, name, fm) {
1922
+ const targetsValue = fm.has("targetPaths") ? crate.getValue(fm.get("targetPaths")) : void 0;
1923
+ const targets = Array.isArray(targetsValue) ? targetsValue.filter((t) => typeof t === "string") : [];
1924
+ return {
1925
+ kind: "relationship",
1926
+ name,
1927
+ custom: false,
1928
+ listOp: "explicit",
1929
+ targets,
1930
+ metadata: {},
1931
+ line: 0
1932
+ };
1933
+ }
1934
+ function buildPrimMetadata(crate, fm) {
1935
+ const meta = {};
1936
+ const apiSchemas = fm.has("apiSchemas") ? crate.getValue(fm.get("apiSchemas")) : void 0;
1937
+ if (Array.isArray(apiSchemas)) meta.apiSchemas = apiSchemas;
1938
+ const kind = asString(crate, fm.get("kind"));
1939
+ if (kind !== void 0) meta.kind = kind;
1940
+ return meta;
1941
+ }
1942
+ function buildLayerMetadata(crate, fm) {
1943
+ const meta = {};
1944
+ const upAxis = asString(crate, fm.get("upAxis"));
1945
+ if (upAxis !== void 0) meta.upAxis = upAxis;
1946
+ const defaultPrim2 = asString(crate, fm.get("defaultPrim"));
1947
+ if (defaultPrim2 !== void 0) meta.defaultPrim = defaultPrim2;
1948
+ const metersPerUnit = asNumber(crate, fm.get("metersPerUnit"));
1949
+ if (metersPerUnit !== void 0) meta.metersPerUnit = metersPerUnit;
1950
+ return meta;
1951
+ }
1952
+ function asString(crate, rep) {
1953
+ if (rep === void 0) return void 0;
1954
+ const v = crate.getValue(rep);
1955
+ return typeof v === "string" ? v : void 0;
1956
+ }
1957
+ function asNumber(crate, rep) {
1958
+ if (rep === void 0) return void 0;
1959
+ const v = crate.getValue(rep);
1960
+ return typeof v === "number" ? v : void 0;
1961
+ }
1962
+ function splitProperty(path) {
1963
+ const slash = path.lastIndexOf("/");
1964
+ const dot = path.indexOf(".", slash < 0 ? 0 : slash);
1965
+ if (dot === -1) return null;
1966
+ if (path.includes("[")) return null;
1967
+ return { primPath: path.slice(0, dot), propName: path.slice(dot + 1) };
1968
+ }
1969
+ function parentOf(path) {
1970
+ const i = path.lastIndexOf("/");
1971
+ return i <= 0 ? "/" : path.slice(0, i);
1972
+ }
1973
+ function leaf(path) {
1974
+ return path.slice(path.lastIndexOf("/") + 1);
1975
+ }
1976
+
1977
+ // src/kinematics/transforms.ts
1978
+ var DEG2RAD = Math.PI / 180;
1979
+ var RAD2DEG = 180 / Math.PI;
1980
+ function identity4() {
1981
+ return [
1982
+ 1,
1983
+ 0,
1984
+ 0,
1985
+ 0,
1986
+ 0,
1987
+ 1,
1988
+ 0,
1989
+ 0,
1990
+ 0,
1991
+ 0,
1992
+ 1,
1993
+ 0,
1994
+ 0,
1995
+ 0,
1996
+ 0,
1997
+ 1
1998
+ ];
1999
+ }
2000
+ function multiply(a, b) {
2001
+ const a11 = a[0], a21 = a[1], a31 = a[2], a41 = a[3];
2002
+ const a12 = a[4], a22 = a[5], a32 = a[6], a42 = a[7];
2003
+ const a13 = a[8], a23 = a[9], a33 = a[10], a43 = a[11];
2004
+ const a14 = a[12], a24 = a[13], a34 = a[14], a44 = a[15];
2005
+ const b11 = b[0], b21 = b[1], b31 = b[2], b41 = b[3];
2006
+ const b12 = b[4], b22 = b[5], b32 = b[6], b42 = b[7];
2007
+ const b13 = b[8], b23 = b[9], b33 = b[10], b43 = b[11];
2008
+ const b14 = b[12], b24 = b[13], b34 = b[14], b44 = b[15];
2009
+ return [
2010
+ a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41,
2011
+ a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41,
2012
+ a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41,
2013
+ a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41,
2014
+ a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42,
2015
+ a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42,
2016
+ a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42,
2017
+ a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42,
2018
+ a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43,
2019
+ a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43,
2020
+ a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43,
2021
+ a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43,
2022
+ a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44,
2023
+ a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44,
2024
+ a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44,
2025
+ a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44
2026
+ ];
2027
+ }
2028
+ function multiplyAll(matrices) {
2029
+ let m = identity4();
2030
+ for (const next of matrices) m = multiply(m, next);
2031
+ return m;
2032
+ }
2033
+ function invert(m) {
2034
+ const n11 = m[0], n21 = m[1], n31 = m[2], n41 = m[3];
2035
+ const n12 = m[4], n22 = m[5], n32 = m[6], n42 = m[7];
2036
+ const n13 = m[8], n23 = m[9], n33 = m[10], n43 = m[11];
2037
+ const n14 = m[12], n24 = m[13], n34 = m[14], n44 = m[15];
2038
+ const t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44;
2039
+ const t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44;
2040
+ const t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44;
2041
+ const t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
2042
+ const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
2043
+ if (det === 0) throw new Error("cannot invert a singular matrix");
2044
+ const idet = 1 / det;
2045
+ return [
2046
+ t11 * idet,
2047
+ (n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44) * idet,
2048
+ (n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44) * idet,
2049
+ (n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43) * idet,
2050
+ t12 * idet,
2051
+ (n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44) * idet,
2052
+ (n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44) * idet,
2053
+ (n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43) * idet,
2054
+ t13 * idet,
2055
+ (n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44) * idet,
2056
+ (n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44) * idet,
2057
+ (n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43) * idet,
2058
+ t14 * idet,
2059
+ (n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34) * idet,
2060
+ (n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34) * idet,
2061
+ (n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33) * idet
2062
+ ];
2063
+ }
2064
+ function makeTranslation([x, y, z]) {
2065
+ return [
2066
+ 1,
2067
+ 0,
2068
+ 0,
2069
+ 0,
2070
+ 0,
2071
+ 1,
2072
+ 0,
2073
+ 0,
2074
+ 0,
2075
+ 0,
2076
+ 1,
2077
+ 0,
2078
+ x,
2079
+ y,
2080
+ z,
2081
+ 1
2082
+ ];
2083
+ }
2084
+ function makeScale([x, y, z]) {
2085
+ return [
2086
+ x,
2087
+ 0,
2088
+ 0,
2089
+ 0,
2090
+ 0,
2091
+ y,
2092
+ 0,
2093
+ 0,
2094
+ 0,
2095
+ 0,
2096
+ z,
2097
+ 0,
2098
+ 0,
2099
+ 0,
2100
+ 0,
2101
+ 1
2102
+ ];
2103
+ }
2104
+ function makeRotationX(rad) {
2105
+ const c = Math.cos(rad);
2106
+ const s = Math.sin(rad);
2107
+ return [
2108
+ 1,
2109
+ 0,
2110
+ 0,
2111
+ 0,
2112
+ 0,
2113
+ c,
2114
+ s,
2115
+ 0,
2116
+ 0,
2117
+ -s,
2118
+ c,
2119
+ 0,
2120
+ 0,
2121
+ 0,
2122
+ 0,
2123
+ 1
2124
+ ];
2125
+ }
2126
+ function makeRotationY(rad) {
2127
+ const c = Math.cos(rad);
2128
+ const s = Math.sin(rad);
2129
+ return [
2130
+ c,
2131
+ 0,
2132
+ -s,
2133
+ 0,
2134
+ 0,
2135
+ 1,
2136
+ 0,
2137
+ 0,
2138
+ s,
2139
+ 0,
2140
+ c,
2141
+ 0,
2142
+ 0,
2143
+ 0,
2144
+ 0,
2145
+ 1
2146
+ ];
2147
+ }
2148
+ function makeRotationZ(rad) {
2149
+ const c = Math.cos(rad);
2150
+ const s = Math.sin(rad);
2151
+ return [
2152
+ c,
2153
+ s,
2154
+ 0,
2155
+ 0,
2156
+ -s,
2157
+ c,
2158
+ 0,
2159
+ 0,
2160
+ 0,
2161
+ 0,
2162
+ 1,
2163
+ 0,
2164
+ 0,
2165
+ 0,
2166
+ 0,
2167
+ 1
2168
+ ];
2169
+ }
2170
+ function makeRotationFromQuat(q) {
2171
+ let x = q.imaginary[0];
2172
+ let y = q.imaginary[1];
2173
+ let z = q.imaginary[2];
2174
+ let w = q.real;
2175
+ const len = Math.hypot(x, y, z, w);
2176
+ if (len > 0 && Math.abs(len - 1) > 1e-9) {
2177
+ x /= len;
2178
+ y /= len;
2179
+ z /= len;
2180
+ w /= len;
2181
+ }
2182
+ const x2 = x + x, y2 = y + y, z2 = z + z;
2183
+ const xx = x * x2, xy = x * y2, xz = x * z2;
2184
+ const yy = y * y2, yz = y * z2, zz = z * z2;
2185
+ const wx = w * x2, wy = w * y2, wz = w * z2;
2186
+ return [
2187
+ 1 - (yy + zz),
2188
+ xy + wz,
2189
+ xz - wy,
2190
+ 0,
2191
+ xy - wz,
2192
+ 1 - (xx + zz),
2193
+ yz + wx,
2194
+ 0,
2195
+ xz + wy,
2196
+ yz - wx,
2197
+ 1 - (xx + yy),
2198
+ 0,
2199
+ 0,
2200
+ 0,
2201
+ 0,
2202
+ 1
2203
+ ];
2204
+ }
2205
+ function makeEuler(angles, order) {
2206
+ const perAxis = {
2207
+ X: makeRotationX(angles[0]),
2208
+ Y: makeRotationY(angles[1]),
2209
+ Z: makeRotationZ(angles[2])
2210
+ };
2211
+ let m = identity4();
2212
+ for (let i = order.length - 1; i >= 0; i--) {
2213
+ const axis = perAxis[order[i]];
2214
+ if (!axis)
2215
+ throw new Error(
2216
+ `invalid euler axis ${JSON.stringify(order[i])} in order ${JSON.stringify(order)}`
2217
+ );
2218
+ m = multiply(m, axis);
2219
+ }
2220
+ return m;
2221
+ }
2222
+ function fromUsdMatrix(m) {
2223
+ if (m.dim !== 4 || m.values.length !== 16) {
2224
+ throw new Error(`expected a 4x4 matrix but got dim=${m.dim}, length=${m.values.length}`);
2225
+ }
2226
+ return [...m.values];
2227
+ }
2228
+ function getTranslation(m) {
2229
+ return [m[12], m[13], m[14]];
2230
+ }
2231
+
2232
+ // src/usd/xformOps.ts
2233
+ var INVERT_PREFIX = "!invert!";
2234
+ var RESET_STACK = "!resetXformStack!";
2235
+ var ROTATE_ORDERS = /* @__PURE__ */ new Set([
2236
+ "rotateXYZ",
2237
+ "rotateXZY",
2238
+ "rotateYXZ",
2239
+ "rotateYZX",
2240
+ "rotateZXY",
2241
+ "rotateZYX"
2242
+ ]);
2243
+ function computeLocalTransform(prim) {
2244
+ const orderAttr = prim.GetAttribute("xformOpOrder");
2245
+ const order = orderAttr.Get();
2246
+ if (!Array.isArray(order)) {
2247
+ return { matrix: identity4(), resetsXformStack: false };
2248
+ }
2249
+ let matrix = identity4();
2250
+ let resetsXformStack = false;
2251
+ for (const entry of order) {
2252
+ if (typeof entry !== "string") continue;
2253
+ if (entry === RESET_STACK) {
2254
+ resetsXformStack = true;
2255
+ continue;
2256
+ }
2257
+ let opName = entry;
2258
+ let doInvert = false;
2259
+ if (opName.startsWith(INVERT_PREFIX)) {
2260
+ doInvert = true;
2261
+ opName = opName.slice(INVERT_PREFIX.length);
2262
+ }
2263
+ const attr = prim.GetAttribute(opName);
2264
+ if (!attr.IsValid()) {
2265
+ throw new Error(`${prim.GetPath()}: xformOpOrder references missing op "${opName}"`);
2266
+ }
2267
+ const opValue = attr.Get();
2268
+ if (opValue === void 0) continue;
2269
+ let opMatrix = opMatrixFor(parseOpType(opName), opValue, `${prim.GetPath()}.${opName}`);
2270
+ if (doInvert) opMatrix = invert(opMatrix);
2271
+ matrix = multiply(matrix, opMatrix);
2272
+ }
2273
+ return { matrix, resetsXformStack };
2274
+ }
2275
+ function parseOpType(opName) {
2276
+ const body = opName.startsWith("xformOp:") ? opName.slice("xformOp:".length) : opName;
2277
+ return body.split(":")[0] ?? body;
2278
+ }
2279
+ function opMatrixFor(opType, value, where) {
2280
+ switch (opType) {
2281
+ case "translate":
2282
+ return makeTranslation(asVec3(value, where));
2283
+ case "scale":
2284
+ return makeScale(asVec3(value, where));
2285
+ case "orient":
2286
+ return makeRotationFromQuat(asQuat(value, where));
2287
+ case "transform":
2288
+ return fromUsdMatrix(asMatrix(value, where));
2289
+ case "rotateX":
2290
+ return makeRotationX(asNumber2(value, where) * DEG2RAD);
2291
+ case "rotateY":
2292
+ return makeRotationY(asNumber2(value, where) * DEG2RAD);
2293
+ case "rotateZ":
2294
+ return makeRotationZ(asNumber2(value, where) * DEG2RAD);
2295
+ default:
2296
+ if (ROTATE_ORDERS.has(opType)) {
2297
+ const [x, y, z] = asVec3(value, where);
2298
+ return makeEuler([x * DEG2RAD, y * DEG2RAD, z * DEG2RAD], opType.slice("rotate".length));
2299
+ }
2300
+ throw new Error(`${where}: unsupported xformOp type "${opType}"`);
2301
+ }
2302
+ }
2303
+ function asVec3(v, where) {
2304
+ if (Array.isArray(v) && v.length === 3 && v.every((n) => typeof n === "number")) {
2305
+ return v;
2306
+ }
2307
+ throw new Error(`${where}: expected a 3-component value`);
2308
+ }
2309
+ function asNumber2(v, where) {
2310
+ if (typeof v === "number") return v;
2311
+ throw new Error(`${where}: expected a number`);
2312
+ }
2313
+ function asQuat(v, where) {
2314
+ if (v && typeof v === "object" && "real" in v && "imaginary" in v) return v;
2315
+ throw new Error(`${where}: expected a quaternion`);
2316
+ }
2317
+ function asMatrix(v, where) {
2318
+ if (v && typeof v === "object" && "values" in v && "dim" in v) return v;
2319
+ throw new Error(`${where}: expected a matrix`);
2320
+ }
2321
+
2322
+ // src/schemas/usdGeom.ts
2323
+ function isXform(prim) {
2324
+ return prim.GetTypeName() === "Xform";
2325
+ }
2326
+ function isScope(prim) {
2327
+ return prim.GetTypeName() === "Scope";
2328
+ }
2329
+ function isMesh(prim) {
2330
+ return prim.GetTypeName() === "Mesh";
2331
+ }
2332
+ function getPurpose(prim) {
2333
+ const v = prim.GetAttribute("purpose").Get();
2334
+ return typeof v === "string" ? v : "default";
2335
+ }
2336
+ function isNonVisualPurpose(prim) {
2337
+ const p = getPurpose(prim);
2338
+ return p === "guide" || p === "proxy";
2339
+ }
2340
+ function* iterDescendants(prim) {
2341
+ for (const child of prim.GetChildren()) {
2342
+ yield child;
2343
+ yield* iterDescendants(child);
2344
+ }
2345
+ }
2346
+ function gatherMeshDescendants(prim) {
2347
+ const paths = [];
2348
+ for (const d of iterDescendants(prim)) {
2349
+ if (isMesh(d)) paths.push(d.GetPath());
2350
+ }
2351
+ return paths;
2352
+ }
2353
+
2354
+ // src/schemas/usdPhysics.ts
2355
+ var JOINT_TYPE_BY_SCHEMA = {
2356
+ PhysicsFixedJoint: "fixed",
2357
+ PhysicsRevoluteJoint: "revolute",
2358
+ PhysicsPrismaticJoint: "prismatic"
2359
+ };
2360
+ var ARTICULATION_ROOT_API = "PhysicsArticulationRootAPI";
2361
+ var RIGID_BODY_API = "PhysicsRigidBodyAPI";
2362
+ var COLLISION_API = "PhysicsCollisionAPI";
2363
+ function getJointType(prim) {
2364
+ return JOINT_TYPE_BY_SCHEMA[prim.GetTypeName()] ?? null;
2365
+ }
2366
+ function getJointBodies(prim) {
2367
+ const body0 = prim.GetRelationship("physics:body0").GetTargets()[0];
2368
+ const body1 = prim.GetRelationship("physics:body1").GetTargets()[0];
2369
+ return {
2370
+ ...body0 !== void 0 ? { body0 } : {},
2371
+ ...body1 !== void 0 ? { body1 } : {}
2372
+ };
2373
+ }
2374
+ function getJointAxis(prim) {
2375
+ const v = prim.GetAttribute("physics:axis").Get();
2376
+ return v === "Y" || v === "Z" ? v : "X";
2377
+ }
2378
+ function getJointLimits(prim) {
2379
+ const lower = readNumber(prim, "physics:lowerLimit");
2380
+ const upper = readNumber(prim, "physics:upperLimit");
2381
+ return {
2382
+ ...lower !== void 0 ? { lower } : {},
2383
+ ...upper !== void 0 ? { upper } : {}
2384
+ };
2385
+ }
2386
+ function getJointLocalFrame(prim, index) {
2387
+ const pos = readVec3(prim, `physics:localPos${index}`, [0, 0, 0]);
2388
+ const rot = readQuat(prim, `physics:localRot${index}`, Quat.identity());
2389
+ return multiply(makeTranslation(pos), makeRotationFromQuat(rot));
2390
+ }
2391
+ function hasArticulationRootAPI(prim) {
2392
+ return prim.HasAPI(ARTICULATION_ROOT_API);
2393
+ }
2394
+ function hasRigidBodyAPI(prim) {
2395
+ return prim.HasAPI(RIGID_BODY_API);
2396
+ }
2397
+ function hasCollisionAPI(prim) {
2398
+ return prim.HasAPI(COLLISION_API);
2399
+ }
2400
+ function driveKindFor(type) {
2401
+ return type === "prismatic" ? "linear" : "angular";
2402
+ }
2403
+ function getJointDrive(prim, kind) {
2404
+ const targetPosition = readNumber(prim, `drive:${kind}:physics:targetPosition`);
2405
+ const stiffness = readNumber(prim, `drive:${kind}:physics:stiffness`);
2406
+ const damping = readNumber(prim, `drive:${kind}:physics:damping`);
2407
+ const maxForce = readNumber(prim, `drive:${kind}:physics:maxForce`);
2408
+ return {
2409
+ ...targetPosition !== void 0 ? { targetPosition } : {},
2410
+ ...stiffness !== void 0 ? { stiffness } : {},
2411
+ ...damping !== void 0 ? { damping } : {},
2412
+ ...maxForce !== void 0 ? { maxForce } : {}
2413
+ };
2414
+ }
2415
+ function getJointStatePosition(prim, kind) {
2416
+ return readNumber(prim, `state:${kind}:physics:position`);
2417
+ }
2418
+ function readNumber(prim, name) {
2419
+ const v = prim.GetAttribute(name).Get();
2420
+ return typeof v === "number" ? v : void 0;
2421
+ }
2422
+ function readVec3(prim, name, def) {
2423
+ const v = prim.GetAttribute(name).Get();
2424
+ if (Array.isArray(v) && v.length === 3 && v.every((n) => typeof n === "number")) {
2425
+ return v;
2426
+ }
2427
+ return def;
2428
+ }
2429
+ function readQuat(prim, name, def) {
2430
+ const v = prim.GetAttribute(name).Get();
2431
+ return v instanceof Quat ? v : def;
2432
+ }
2433
+
2434
+ // src/robot/buildKinematicTree.ts
2435
+ var WORLD = "";
2436
+ function buildKinematicTree(robot, options = {}) {
2437
+ const warnings = [];
2438
+ const warn = (m) => {
2439
+ warnings.push(m);
2440
+ options.onWarn?.(m);
2441
+ };
2442
+ const links = new Set(Object.keys(robot.links));
2443
+ const outgoing = /* @__PURE__ */ new Map();
2444
+ const worldJointByChild = /* @__PURE__ */ new Map();
2445
+ const inRealDegree = /* @__PURE__ */ new Map();
2446
+ for (const [jointKey, joint] of Object.entries(robot.joints)) {
2447
+ if (!links.has(joint.child)) {
2448
+ warn(`joint "${jointKey}": child link "${joint.child}" is unknown; skipping edge`);
2449
+ continue;
2450
+ }
2451
+ if (joint.parent === WORLD) {
2452
+ if (worldJointByChild.has(joint.child)) {
2453
+ warn(`link "${joint.child}" is fixed to world by multiple joints; keeping "${jointKey}"`);
2454
+ }
2455
+ worldJointByChild.set(joint.child, jointKey);
2456
+ continue;
2457
+ }
2458
+ if (!links.has(joint.parent)) {
2459
+ warn(`joint "${jointKey}": parent link "${joint.parent}" is unknown; skipping edge`);
2460
+ continue;
2461
+ }
2462
+ const edges = outgoing.get(joint.parent) ?? [];
2463
+ edges.push({ joint: jointKey, child: joint.child });
2464
+ outgoing.set(joint.parent, edges);
2465
+ inRealDegree.set(joint.child, (inRealDegree.get(joint.child) ?? 0) + 1);
2466
+ }
2467
+ const root = chooseRoot(links, inRealDegree, worldJointByChild, robot, warn);
2468
+ const nodes = {};
2469
+ const order = [];
2470
+ const loopJoints = [];
2471
+ const visited = /* @__PURE__ */ new Set();
2472
+ if (root !== "") {
2473
+ nodes[root] = { link: root, parent: null, jointToParent: null, children: [], depth: 0 };
2474
+ visited.add(root);
2475
+ order.push(root);
2476
+ const queue = [root];
2477
+ while (queue.length > 0) {
2478
+ const cur = queue.shift();
2479
+ const edges = [...outgoing.get(cur) ?? []].sort((a, b) => a.joint.localeCompare(b.joint));
2480
+ for (const edge of edges) {
2481
+ if (visited.has(edge.child)) {
2482
+ loopJoints.push(edge.joint);
2483
+ continue;
2484
+ }
2485
+ visited.add(edge.child);
2486
+ nodes[edge.child] = {
2487
+ link: edge.child,
2488
+ parent: cur,
2489
+ jointToParent: edge.joint,
2490
+ children: [],
2491
+ depth: nodes[cur].depth + 1
2492
+ };
2493
+ nodes[cur].children.push(edge);
2494
+ order.push(edge.child);
2495
+ queue.push(edge.child);
2496
+ }
2497
+ }
2498
+ }
2499
+ const isolatedLinks = [...links].filter((l) => !visited.has(l)).sort();
2500
+ if (isolatedLinks.length > 0) {
2501
+ warn(
2502
+ `${isolatedLinks.length} link(s) not reachable from root "${root}": ${isolatedLinks.join(", ")}`
2503
+ );
2504
+ }
2505
+ if (loopJoints.length > 0) {
2506
+ warn(`closed loop(s) detected; dropped joints from tree: ${loopJoints.sort().join(", ")}`);
2507
+ }
2508
+ return {
2509
+ root,
2510
+ rootJoint: worldJointByChild.get(root) ?? null,
2511
+ nodes,
2512
+ order,
2513
+ loopJoints: loopJoints.sort(),
2514
+ isolatedLinks,
2515
+ warnings
2516
+ };
2517
+ }
2518
+ function chooseRoot(links, inRealDegree, worldJointByChild, robot, warn) {
2519
+ if (links.size === 0) return "";
2520
+ const candidates = [...links].filter((l) => (inRealDegree.get(l) ?? 0) === 0).sort();
2521
+ if (candidates.length === 0) {
2522
+ const fallback = [...links].sort()[0];
2523
+ warn(`no root candidate (every link has a parent \u2014 likely a full cycle); using "${fallback}"`);
2524
+ return fallback;
2525
+ }
2526
+ const articulation = (robot.articulationRoots ?? []).filter((a) => candidates.includes(a));
2527
+ const worldFixed = candidates.filter((c) => worldJointByChild.has(c));
2528
+ const chosen = articulation[0] ?? worldFixed[0] ?? candidates[0];
2529
+ if (candidates.length > 1) {
2530
+ warn(`multiple root candidates (${candidates.join(", ")}); using "${chosen}"`);
2531
+ }
2532
+ return chosen;
2533
+ }
2534
+
2535
+ // src/robot/normalize.ts
2536
+ var isFinite_ = (x) => x !== void 0 && Number.isFinite(x);
2537
+ function normalizeJointLimits(type, rawLower, rawUpper) {
2538
+ const angular = type === "revolute" || type === "continuous";
2539
+ const conv = (x) => {
2540
+ if (!isFinite_(x)) return void 0;
2541
+ return angular ? x * DEG2RAD : x;
2542
+ };
2543
+ const lower = conv(rawLower);
2544
+ const upper = conv(rawUpper);
2545
+ return {
2546
+ ...lower !== void 0 ? { lower } : {},
2547
+ ...upper !== void 0 ? { upper } : {}
2548
+ };
2549
+ }
2550
+ function jointValueToSI(angular, raw) {
2551
+ return angular ? raw * DEG2RAD : raw;
2552
+ }
2553
+ function refineJointType(base, lower, upper) {
2554
+ if (base === "revolute" && lower === void 0 && upper === void 0) return "continuous";
2555
+ return base;
2556
+ }
2557
+
2558
+ // src/robot/RobotExtractor.ts
2559
+ var WORLD2 = "";
2560
+ function extractRobotDescription(stage, options = {}) {
2561
+ const warnings = [];
2562
+ const warn = (m) => {
2563
+ warnings.push(m);
2564
+ options.onWarn?.(m);
2565
+ };
2566
+ const jointPrims = stage.Traverse().filter((p) => getJointType(p) !== null);
2567
+ const linkPaths = /* @__PURE__ */ new Set();
2568
+ for (const jp of jointPrims) {
2569
+ const { body0, body1 } = getJointBodies(jp);
2570
+ if (body0) linkPaths.add(body0);
2571
+ if (body1) linkPaths.add(body1);
2572
+ }
2573
+ for (const p of stage.Traverse()) {
2574
+ if (hasRigidBodyAPI(p)) linkPaths.add(p.GetPath());
2575
+ }
2576
+ const linkKeyByPath = buildKeyMap([...linkPaths]);
2577
+ const links = {};
2578
+ const articulationRoots = [];
2579
+ for (const path of linkPaths) {
2580
+ const key = linkKeyByPath.get(path);
2581
+ const prim = stage.GetPrimAtPath(path);
2582
+ links[key] = buildLink(path, prim);
2583
+ if (prim && hasArticulationRootAPI(prim)) articulationRoots.push(key);
2584
+ }
2585
+ const joints = {};
2586
+ const jointKeyByPath = buildKeyMap(jointPrims.map((p) => p.GetPath()));
2587
+ for (const jp of jointPrims) {
2588
+ const joint = buildJoint(jp, linkKeyByPath, warn);
2589
+ if (joint) joints[jointKeyByPath.get(jp.GetPath())] = joint;
2590
+ }
2591
+ const name = options.robotName ?? stage.GetDefaultPrim()?.GetName() ?? stage.GetPseudoRoot().GetChildren()[0]?.GetName() ?? "robot";
2592
+ const robot = {
2593
+ name,
2594
+ rootLink: "",
2595
+ links,
2596
+ joints,
2597
+ upAxis: stage.GetUpAxis(),
2598
+ metersPerUnit: stage.GetMetersPerUnit(),
2599
+ ...articulationRoots.length ? { articulationRoots } : {}
2600
+ };
2601
+ const tree = buildKinematicTree(robot, { onWarn: warn });
2602
+ robot.rootLink = tree.root;
2603
+ if (tree.loopJoints.length) robot.loopJoints = tree.loopJoints;
2604
+ if (warnings.length) robot.warnings = warnings;
2605
+ return robot;
2606
+ }
2607
+ function buildLink(path, prim) {
2608
+ const name = leafName(path);
2609
+ if (!prim) return { name, primPath: path, visualPrims: [] };
2610
+ const visualPrims = [];
2611
+ const collisionPrims = [];
2612
+ for (const meshPath of gatherMeshDescendants(prim)) {
2613
+ const mp = prim.GetStage().GetPrimAtPath(meshPath);
2614
+ if (mp && (hasCollisionAPI(mp) || isNonVisualPurpose(mp))) collisionPrims.push(meshPath);
2615
+ else visualPrims.push(meshPath);
2616
+ }
2617
+ return {
2618
+ name,
2619
+ primPath: path,
2620
+ visualPrims,
2621
+ ...collisionPrims.length ? { collisionPrims } : {}
2622
+ };
2623
+ }
2624
+ function buildJoint(prim, linkKeyByPath, warn) {
2625
+ const base = getJointType(prim);
2626
+ if (!base) return null;
2627
+ const path = prim.GetPath();
2628
+ const { body0, body1 } = getJointBodies(prim);
2629
+ if (!body1) {
2630
+ warn(`${path}: joint has no physics:body1 target; skipping`);
2631
+ return null;
2632
+ }
2633
+ const parent = body0 ? linkKeyByPath.get(body0) ?? body0 : WORLD2;
2634
+ const child = linkKeyByPath.get(body1) ?? body1;
2635
+ const raw = getJointLimits(prim);
2636
+ const { lower, upper } = normalizeJointLimits(base, raw.lower, raw.upper);
2637
+ const type = refineJointType(base, lower, upper);
2638
+ const joint = {
2639
+ name: leafName(path),
2640
+ primPath: path,
2641
+ type,
2642
+ parent,
2643
+ child,
2644
+ axis: getJointAxis(prim),
2645
+ jointFrame0: getJointLocalFrame(prim, 0),
2646
+ jointFrame1: getJointLocalFrame(prim, 1),
2647
+ ...lower !== void 0 ? { lower } : {},
2648
+ ...upper !== void 0 ? { upper } : {}
2649
+ };
2650
+ const kind = driveKindFor(type);
2651
+ const angular = kind === "angular";
2652
+ const drive = getJointDrive(prim, kind);
2653
+ const statePos = getJointStatePosition(prim, kind);
2654
+ const initialValue = statePos !== void 0 ? jointValueToSI(angular, statePos) : drive.targetPosition !== void 0 ? jointValueToSI(angular, drive.targetPosition) : void 0;
2655
+ if (initialValue !== void 0) joint.initialValue = initialValue;
2656
+ const driveDesc = {
2657
+ ...drive.targetPosition !== void 0 ? { targetPosition: jointValueToSI(angular, drive.targetPosition) } : {},
2658
+ ...drive.stiffness !== void 0 ? { stiffness: drive.stiffness } : {},
2659
+ ...drive.damping !== void 0 ? { damping: drive.damping } : {},
2660
+ ...drive.maxForce !== void 0 ? { maxForce: drive.maxForce } : {}
2661
+ };
2662
+ if (Object.keys(driveDesc).length > 0) joint.drive = driveDesc;
2663
+ return joint;
2664
+ }
2665
+ function buildKeyMap(paths) {
2666
+ const leafCounts = /* @__PURE__ */ new Map();
2667
+ for (const p of paths) {
2668
+ const leaf2 = leafName(p);
2669
+ leafCounts.set(leaf2, (leafCounts.get(leaf2) ?? 0) + 1);
2670
+ }
2671
+ const map = /* @__PURE__ */ new Map();
2672
+ for (const p of paths) {
2673
+ const leaf2 = leafName(p);
2674
+ map.set(p, leafCounts.get(leaf2) === 1 ? leaf2 : p);
2675
+ }
2676
+ return map;
2677
+ }
2678
+ function leafName(path) {
2679
+ const parts = path.split("/").filter(Boolean);
2680
+ return parts[parts.length - 1] ?? path;
2681
+ }
2682
+
2683
+ export { ARTICULATION_ROOT_API, AssetPath, Attribute, COLLISION_API, CrateReader, DEFAULT_METERS_PER_UNIT, DEG2RAD, DefaultAssetResolver, Layer, PACKAGE_NAME, ParseError, Prim, Quat, RAD2DEG, RIGID_BODY_API, Relationship, Stage, TokenizeError, UsdMatrix, VERSION, buildKinematicTree, composeLayer, computeLocalTransform, crateToUsdaFile, createMemoryResolver, driveKindFor, extractRobotDescription, fromUsdMatrix, gatherMeshDescendants, getJointAxis, getJointBodies, getJointDrive, getJointLimits, getJointLocalFrame, getJointStatePosition, getJointType, getTranslation, hasArticulationRootAPI, hasCollisionAPI, hasRigidBodyAPI, identity4, invert, isMesh, isScope, isXform, iterDescendants, joinPosix, jointValueToSI, makeEuler, makeRotationFromQuat, makeRotationX, makeRotationY, makeRotationZ, makeScale, makeTranslation, multiply, multiplyAll, normalizeJointLimits, openUsdz, parseOpType, parseUsda, refineJointType, tokenize };
2684
+ //# sourceMappingURL=chunk-XCP5GZPY.js.map
2685
+ //# sourceMappingURL=chunk-XCP5GZPY.js.map