three-usd-robot 0.3.0 → 0.4.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.
@@ -1040,6 +1040,21 @@ var Stage = class _Stage {
1040
1040
  const v = this._layer.GetMetadata("metersPerUnit");
1041
1041
  return typeof v === "number" ? v : DEFAULT_METERS_PER_UNIT;
1042
1042
  }
1043
+ /** Animation start time code, if authored. */
1044
+ GetStartTimeCode() {
1045
+ const v = this._layer.GetMetadata("startTimeCode");
1046
+ return typeof v === "number" ? v : void 0;
1047
+ }
1048
+ /** Animation end time code, if authored. */
1049
+ GetEndTimeCode() {
1050
+ const v = this._layer.GetMetadata("endTimeCode");
1051
+ return typeof v === "number" ? v : void 0;
1052
+ }
1053
+ /** Time codes per second for playback; defaults to 24. */
1054
+ GetTimeCodesPerSecond() {
1055
+ const v = this._layer.GetMetadata("timeCodesPerSecond") ?? this._layer.GetMetadata("framesPerSecond");
1056
+ return typeof v === "number" && v > 0 ? v : 24;
1057
+ }
1043
1058
  };
1044
1059
 
1045
1060
  // src/usd/AssetResolver.ts
@@ -1063,14 +1078,21 @@ var DefaultAssetResolver = class {
1063
1078
  }
1064
1079
  };
1065
1080
  function createMemoryResolver(files) {
1081
+ const decoder = new TextDecoder();
1082
+ const encoder = new TextEncoder();
1066
1083
  return {
1067
1084
  resolve(assetPath, baseUrl) {
1068
1085
  return joinPosix(baseUrl, assetPath);
1069
1086
  },
1070
1087
  fetchText(url) {
1071
- const text = files[url];
1072
- if (text === void 0) return Promise.reject(new Error(`asset not found: ${url}`));
1073
- return Promise.resolve(text);
1088
+ const v = files[url];
1089
+ if (v === void 0) return Promise.reject(new Error(`asset not found: ${url}`));
1090
+ return Promise.resolve(typeof v === "string" ? v : decoder.decode(v));
1091
+ },
1092
+ fetchBytes(url) {
1093
+ const v = files[url];
1094
+ if (v === void 0) return Promise.reject(new Error(`asset not found: ${url}`));
1095
+ return Promise.resolve(typeof v === "string" ? encoder.encode(v) : v);
1074
1096
  }
1075
1097
  };
1076
1098
  }
@@ -1090,261 +1112,6 @@ function normalizePosix(path) {
1090
1112
  return (isAbsolute ? "/" : "") + out.join("/");
1091
1113
  }
1092
1114
 
1093
- // src/usd/composition.ts
1094
- var ARC_KEYS = ["references", "payload", "payloads", "inherits", "specializes"];
1095
- var STRIP_KEYS = [...ARC_KEYS, "variants", "variantSets"];
1096
- async function composeLayer(text, baseUrl, resolver, options = {}, stack = /* @__PURE__ */ new Set()) {
1097
- const warn = options.onWarn ?? (() => {
1098
- });
1099
- const file = parseUsda(text);
1100
- let weak = [];
1101
- const subLayers = toArcs(file.metadata.subLayers);
1102
- for (let i = subLayers.length - 1; i >= 0; i--) {
1103
- const sub = await loadExternalFile(subLayers[i], baseUrl, resolver, options, stack, warn);
1104
- if (sub) weak = mergePrimLists(weak, sub.prims);
1105
- }
1106
- const ctx = {
1107
- baseUrl,
1108
- resolver,
1109
- options,
1110
- warn,
1111
- stack,
1112
- index: buildPathIndex(file.prims),
1113
- resolving: /* @__PURE__ */ new Set()
1114
- };
1115
- const resolved = [];
1116
- for (const prim of file.prims) resolved.push(await resolvePrim(prim, ctx));
1117
- const prims = weak.length > 0 ? mergePrimLists(weak, resolved) : resolved;
1118
- return { version: file.version, metadata: stripKeys(file.metadata, STRIP_KEYS), prims };
1119
- }
1120
- async function resolvePrim(spec, ctx) {
1121
- let properties = spec.properties;
1122
- let children = spec.children;
1123
- const selection = spec.metadata.variants;
1124
- if (spec.variantSets && isDictionary(selection)) {
1125
- for (const [setName, variantName] of Object.entries(selection)) {
1126
- const variant = spec.variantSets[setName]?.[String(variantName)];
1127
- if (!variant) continue;
1128
- properties = mergeProperties(variant.properties, properties);
1129
- children = mergePrimLists(variant.children, children);
1130
- }
1131
- }
1132
- const resolvedChildren = [];
1133
- for (const child of children) resolvedChildren.push(await resolvePrim(child, ctx));
1134
- const local = {
1135
- specifier: spec.specifier,
1136
- typeName: spec.typeName,
1137
- name: spec.name,
1138
- metadata: stripKeys(spec.metadata, STRIP_KEYS),
1139
- properties,
1140
- children: resolvedChildren,
1141
- line: spec.line
1142
- };
1143
- const arcs = ARC_KEYS.flatMap((k) => toArcs(spec.metadata[k]));
1144
- let base = null;
1145
- for (const arc of arcs) {
1146
- const target = await loadReferencedPrim(arc, ctx);
1147
- if (target) base = base ? mergePrim(target, base) : target;
1148
- }
1149
- return base ? mergePrim(base, local) : local;
1150
- }
1151
- async function loadReferencedPrim(arc, ctx) {
1152
- if (arc.assetPath) {
1153
- const composed = await loadExternalFile(
1154
- arc,
1155
- ctx.baseUrl,
1156
- ctx.resolver,
1157
- ctx.options,
1158
- ctx.stack,
1159
- ctx.warn
1160
- );
1161
- if (!composed) return null;
1162
- const target = arc.primPath ? findPrimByPath(composed, arc.primPath) : defaultPrim(composed, ctx.warn);
1163
- if (!target) {
1164
- ctx.warn(
1165
- `reference target ${arc.primPath ?? "(defaultPrim)"} not found in ${arc.assetPath.path}`
1166
- );
1167
- return null;
1168
- }
1169
- return target;
1170
- }
1171
- if (arc.primPath) {
1172
- if (ctx.resolving.has(arc.primPath)) {
1173
- ctx.warn(`internal composition cycle at ${arc.primPath}; skipping`);
1174
- return null;
1175
- }
1176
- const target = ctx.index.get(arc.primPath);
1177
- if (!target) {
1178
- ctx.warn(`internal reference target ${arc.primPath} not found`);
1179
- return null;
1180
- }
1181
- return resolvePrim(target, { ...ctx, resolving: /* @__PURE__ */ new Set([...ctx.resolving, arc.primPath]) });
1182
- }
1183
- return null;
1184
- }
1185
- async function loadExternalFile(arc, baseUrl, resolver, options, stack, warn) {
1186
- if (!arc.assetPath) return null;
1187
- const url = resolver.resolve(arc.assetPath.path, baseUrl);
1188
- if (stack.has(url)) {
1189
- warn(`composition cycle detected at ${url}; skipping`);
1190
- return null;
1191
- }
1192
- if (stack.size >= (options.maxDepth ?? 64)) {
1193
- warn(`composition exceeded max depth at ${url}; skipping`);
1194
- return null;
1195
- }
1196
- let text;
1197
- try {
1198
- text = await resolver.fetchText(url);
1199
- } catch (err) {
1200
- warn(`cannot resolve "${arc.assetPath.path}" -> ${url}: ${err.message}`);
1201
- return null;
1202
- }
1203
- return composeLayer(text, url, resolver, options, /* @__PURE__ */ new Set([...stack, url]));
1204
- }
1205
- function mergePrim(base, over) {
1206
- return {
1207
- specifier: over.specifier === "over" ? base.specifier : over.specifier,
1208
- typeName: over.typeName || base.typeName,
1209
- name: over.name,
1210
- metadata: mergeMetadata(base.metadata, over.metadata),
1211
- properties: mergeProperties(base.properties, over.properties),
1212
- children: mergePrimLists(base.children, over.children),
1213
- line: over.line
1214
- };
1215
- }
1216
- function mergePrimLists(base, over) {
1217
- const byName = /* @__PURE__ */ new Map();
1218
- for (const p of base) byName.set(p.name, p);
1219
- for (const p of over) {
1220
- const existing = byName.get(p.name);
1221
- byName.set(p.name, existing ? mergePrim(existing, p) : p);
1222
- }
1223
- return [...byName.values()];
1224
- }
1225
- function mergeProperties(base, over) {
1226
- const byName = /* @__PURE__ */ new Map();
1227
- for (const p of base) byName.set(p.name, p);
1228
- for (const p of over) {
1229
- const existing = byName.get(p.name);
1230
- byName.set(p.name, existing ? mergeProperty(existing, p) : p);
1231
- }
1232
- return [...byName.values()];
1233
- }
1234
- function mergeProperty(base, over) {
1235
- if (base.kind !== over.kind) return over;
1236
- if (base.kind === "attribute" && over.kind === "attribute") {
1237
- const merged = {
1238
- ...over,
1239
- typeName: over.typeName || base.typeName,
1240
- metadata: mergeMetadata(base.metadata, over.metadata)
1241
- };
1242
- const value = over.value !== void 0 ? over.value : base.value;
1243
- if (value !== void 0) merged.value = value;
1244
- const timeSamples = over.timeSamples ?? base.timeSamples;
1245
- if (timeSamples) merged.timeSamples = timeSamples;
1246
- const connections = over.connections ?? base.connections;
1247
- if (connections) merged.connections = connections;
1248
- return merged;
1249
- }
1250
- if (base.kind === "relationship" && over.kind === "relationship") {
1251
- return {
1252
- ...over,
1253
- targets: over.targets.length > 0 ? over.targets : base.targets,
1254
- metadata: mergeMetadata(base.metadata, over.metadata)
1255
- };
1256
- }
1257
- return over;
1258
- }
1259
- function mergeMetadata(base, over) {
1260
- const merged = { ...base, ...over };
1261
- const a = base.apiSchemas;
1262
- const b = over.apiSchemas;
1263
- if (Array.isArray(a) || Array.isArray(b)) {
1264
- const seen = /* @__PURE__ */ new Set();
1265
- const union = [];
1266
- for (const v of [...Array.isArray(a) ? a : [], ...Array.isArray(b) ? b : []]) {
1267
- if (!seen.has(v)) {
1268
- seen.add(v);
1269
- union.push(v);
1270
- }
1271
- }
1272
- merged.apiSchemas = union;
1273
- }
1274
- return merged;
1275
- }
1276
- function buildPathIndex(prims, parent = "/", map = /* @__PURE__ */ new Map()) {
1277
- for (const p of prims) {
1278
- const path = parent === "/" ? `/${p.name}` : `${parent}/${p.name}`;
1279
- map.set(path, p);
1280
- buildPathIndex(p.children, path, map);
1281
- }
1282
- return map;
1283
- }
1284
- function findPrimByPath(file, path) {
1285
- const segments = path.split("/").filter(Boolean);
1286
- let level = file.prims;
1287
- let found = null;
1288
- for (const seg of segments) {
1289
- found = level.find((p) => p.name === seg) ?? null;
1290
- if (!found) return null;
1291
- level = found.children;
1292
- }
1293
- return found;
1294
- }
1295
- function defaultPrim(file, warn) {
1296
- const name = file.metadata.defaultPrim;
1297
- if (typeof name === "string") return file.prims.find((p) => p.name === name) ?? null;
1298
- const first = file.prims[0];
1299
- if (first) warn(`referenced layer has no defaultPrim; using first root prim "${first.name}"`);
1300
- return first ?? null;
1301
- }
1302
- function toArcs(value) {
1303
- if (value === void 0) return [];
1304
- const list = Array.isArray(value) ? value : [value];
1305
- const arcs = [];
1306
- for (const v of list) {
1307
- if (v instanceof AssetPath) arcs.push({ assetPath: v });
1308
- else if (v && typeof v === "object" && ("assetPath" in v || "primPath" in v))
1309
- arcs.push(v);
1310
- }
1311
- return arcs;
1312
- }
1313
- function isDictionary(v) {
1314
- return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Quat) && !(v instanceof UsdMatrix) && !(v instanceof AssetPath);
1315
- }
1316
- function stripKeys(meta, keys) {
1317
- const out = {};
1318
- for (const [k, v] of Object.entries(meta)) {
1319
- if (!keys.includes(k)) out[k] = v;
1320
- }
1321
- return out;
1322
- }
1323
- var USD_ENTRY = /\.(usda|usdc|usd)$/i;
1324
- function openUsdz(bytes) {
1325
- const entries = unzipSync(bytes);
1326
- const names = Object.keys(entries);
1327
- const rootEntry = names.find((n) => USD_ENTRY.test(n)) ?? names[0];
1328
- if (!rootEntry) throw new Error("usdz package contains no entries");
1329
- const decoder = new TextDecoder();
1330
- const resolver = {
1331
- resolve(assetPath, baseUrl) {
1332
- return joinPosix(baseUrl, assetPath);
1333
- },
1334
- fetchText(url) {
1335
- const data = entries[url] ?? entries[url.replace(/^\/+/, "")];
1336
- if (!data) return Promise.reject(new Error(`not found in usdz: ${url}`));
1337
- if (/\.usdc$/i.test(url)) {
1338
- return Promise.reject(
1339
- new Error(`USDC (binary crate) entries are not supported yet (M10): ${url}`)
1340
- );
1341
- }
1342
- return Promise.resolve(decoder.decode(data));
1343
- }
1344
- };
1345
- return { rootEntry, resolver };
1346
- }
1347
-
1348
1115
  // src/usd/crate/lz4.ts
1349
1116
  var MAX_CHUNK_INPUT = 2113929216;
1350
1117
  function lz4DecompressBlock(src, dst) {
@@ -1459,12 +1226,14 @@ var CrateType = {
1459
1226
  Vec4f: 28,
1460
1227
  TokenListOp: 32,
1461
1228
  PathListOp: 34,
1229
+ ReferenceListOp: 35,
1462
1230
  IntListOp: 36,
1463
1231
  PathVector: 40,
1464
1232
  TokenVector: 41,
1465
1233
  Specifier: 42,
1466
1234
  Permission: 43,
1467
- Variability: 44};
1235
+ Variability: 44,
1236
+ PayloadListOp: 55};
1468
1237
  var ListOpBits = {
1469
1238
  HasExplicit: 1 << 1,
1470
1239
  HasAdded: 1 << 2,
@@ -1811,6 +1580,10 @@ var CrateReader = class {
1811
1580
  return this.readListOp(off, "token");
1812
1581
  case CrateType.PathListOp:
1813
1582
  return this.readListOp(off, "path");
1583
+ case CrateType.ReferenceListOp:
1584
+ return this.readArcListOp(off, true);
1585
+ case CrateType.PayloadListOp:
1586
+ return this.readArcListOp(off, false);
1814
1587
  case CrateType.TokenVector:
1815
1588
  return this.readIndexVector(off, "token").items;
1816
1589
  case CrateType.PathVector:
@@ -1914,6 +1687,41 @@ var CrateReader = class {
1914
1687
  if (bits & ListOpBits.HasOrdered) read([]);
1915
1688
  return [...explicit, ...prepended, ...added, ...appended];
1916
1689
  }
1690
+ /**
1691
+ * Read a Reference/Payload list-op into composition arcs. Each item is
1692
+ * `[assetPath: string-index][primPath: path-index][layerOffset: 2 doubles]`,
1693
+ * and a Reference additionally carries a (usually empty) customData dict.
1694
+ */
1695
+ readArcListOp(off, isReference) {
1696
+ const bits = this.bytes[off];
1697
+ let p = off + 1;
1698
+ const out = [];
1699
+ const readList = (collect) => {
1700
+ const count = this.u64(p);
1701
+ p += 8;
1702
+ for (let i = 0; i < count; i++) {
1703
+ const assetStrIndex = this.view.getUint32(p, true);
1704
+ p += 4;
1705
+ const primPathIndex = this.view.getInt32(p, true);
1706
+ p += 4;
1707
+ p += 16;
1708
+ if (isReference) p += 8;
1709
+ if (!collect) continue;
1710
+ const assetPath = this.getToken(this.getStrings()[assetStrIndex] ?? -1);
1711
+ const primPath = this.getPaths()[primPathIndex] ?? "";
1712
+ const arc = { assetPath: new AssetPath(assetPath) };
1713
+ if (primPath) arc.primPath = primPath;
1714
+ out.push(arc);
1715
+ }
1716
+ };
1717
+ if (bits & ListOpBits.HasExplicit) readList(true);
1718
+ if (bits & ListOpBits.HasAdded) readList(true);
1719
+ if (bits & ListOpBits.HasPrepended) readList(true);
1720
+ if (bits & ListOpBits.HasAppended) readList(true);
1721
+ if (bits & ListOpBits.HasDeleted) readList(false);
1722
+ if (bits & ListOpBits.HasOrdered) readList(false);
1723
+ return out;
1724
+ }
1917
1725
  };
1918
1726
  function appendElement(parent, elem, isProperty) {
1919
1727
  if (isProperty) return `${parent}.${elem}`;
@@ -1957,108 +1765,410 @@ function crateToUsdaFile(crate) {
1957
1765
  layerMetadata = buildLayerMetadata(crate, fieldsOf(spec.fieldSetIndex));
1958
1766
  continue;
1959
1767
  }
1960
- if (spec.specType !== SPEC_PRIM) continue;
1961
- const fm = fieldsOf(spec.fieldSetIndex);
1962
- primByPath.set(path, {
1963
- specifier: SPECIFIERS2[asNumber(crate, fm.get("specifier")) ?? 0] ?? "def",
1964
- typeName: asString(crate, fm.get("typeName")) ?? "",
1965
- name: leaf(path),
1966
- metadata: buildPrimMetadata(crate, fm),
1967
- properties: [],
1968
- children: [],
1969
- line: 0
1768
+ if (spec.specType !== SPEC_PRIM) continue;
1769
+ const fm = fieldsOf(spec.fieldSetIndex);
1770
+ primByPath.set(path, {
1771
+ specifier: SPECIFIERS2[asNumber(crate, fm.get("specifier")) ?? 0] ?? "def",
1772
+ typeName: asString(crate, fm.get("typeName")) ?? "",
1773
+ name: leaf(path),
1774
+ metadata: buildPrimMetadata(crate, fm),
1775
+ properties: [],
1776
+ children: [],
1777
+ line: 0
1778
+ });
1779
+ }
1780
+ for (const spec of specs) {
1781
+ if (spec.specType !== SPEC_ATTRIBUTE && spec.specType !== SPEC_RELATIONSHIP) continue;
1782
+ const split = splitProperty(paths[spec.pathIndex] ?? "");
1783
+ if (!split) continue;
1784
+ const prim = primByPath.get(split.primPath);
1785
+ if (!prim) continue;
1786
+ const fm = fieldsOf(spec.fieldSetIndex);
1787
+ prim.properties.push(
1788
+ spec.specType === SPEC_ATTRIBUTE ? buildAttribute(crate, split.propName, fm) : buildRelationship(crate, split.propName, fm)
1789
+ );
1790
+ }
1791
+ for (const [path, prim] of primByPath) {
1792
+ const parentPath = parentOf(path);
1793
+ if (parentPath === "/") rootPrims.push(prim);
1794
+ else primByPath.get(parentPath)?.children.push(prim);
1795
+ }
1796
+ return { version: crate.version.join("."), metadata: layerMetadata, prims: rootPrims };
1797
+ }
1798
+ function buildAttribute(crate, name, fm) {
1799
+ const defaultRep = fm.get("default");
1800
+ const attr = {
1801
+ kind: "attribute",
1802
+ name,
1803
+ typeName: asString(crate, fm.get("typeName")) ?? "",
1804
+ isArray: defaultRep !== void 0 ? decodeRepBits(defaultRep).isArray : false,
1805
+ variability: asNumber(crate, fm.get("variability")) === 1 ? "uniform" : "varying",
1806
+ custom: false,
1807
+ metadata: {},
1808
+ line: 0
1809
+ };
1810
+ if (defaultRep !== void 0) {
1811
+ const value = crate.getValue(defaultRep);
1812
+ if (value !== void 0) attr.value = value;
1813
+ }
1814
+ return attr;
1815
+ }
1816
+ function buildRelationship(crate, name, fm) {
1817
+ const targetsValue = fm.has("targetPaths") ? crate.getValue(fm.get("targetPaths")) : void 0;
1818
+ const targets = Array.isArray(targetsValue) ? targetsValue.filter((t) => typeof t === "string") : [];
1819
+ return {
1820
+ kind: "relationship",
1821
+ name,
1822
+ custom: false,
1823
+ listOp: "explicit",
1824
+ targets,
1825
+ metadata: {},
1826
+ line: 0
1827
+ };
1828
+ }
1829
+ var ARC_FIELDS = ["references", "payload", "payloads", "inherits", "specializes"];
1830
+ function buildPrimMetadata(crate, fm) {
1831
+ const meta = {};
1832
+ const apiSchemas = fm.has("apiSchemas") ? crate.getValue(fm.get("apiSchemas")) : void 0;
1833
+ if (Array.isArray(apiSchemas)) meta.apiSchemas = apiSchemas;
1834
+ const kind = asString(crate, fm.get("kind"));
1835
+ if (kind !== void 0) meta.kind = kind;
1836
+ for (const key of ARC_FIELDS) {
1837
+ if (!fm.has(key)) continue;
1838
+ const arcs = crate.getValue(fm.get(key));
1839
+ if (Array.isArray(arcs) && arcs.length > 0) meta[key] = arcs;
1840
+ }
1841
+ return meta;
1842
+ }
1843
+ function buildLayerMetadata(crate, fm) {
1844
+ const meta = {};
1845
+ const upAxis = asString(crate, fm.get("upAxis"));
1846
+ if (upAxis !== void 0) meta.upAxis = upAxis;
1847
+ const defaultPrim2 = asString(crate, fm.get("defaultPrim"));
1848
+ if (defaultPrim2 !== void 0) meta.defaultPrim = defaultPrim2;
1849
+ const metersPerUnit = asNumber(crate, fm.get("metersPerUnit"));
1850
+ if (metersPerUnit !== void 0) meta.metersPerUnit = metersPerUnit;
1851
+ return meta;
1852
+ }
1853
+ function asString(crate, rep) {
1854
+ if (rep === void 0) return void 0;
1855
+ const v = crate.getValue(rep);
1856
+ return typeof v === "string" ? v : void 0;
1857
+ }
1858
+ function asNumber(crate, rep) {
1859
+ if (rep === void 0) return void 0;
1860
+ const v = crate.getValue(rep);
1861
+ return typeof v === "number" ? v : void 0;
1862
+ }
1863
+ function splitProperty(path) {
1864
+ const slash = path.lastIndexOf("/");
1865
+ const dot = path.indexOf(".", slash < 0 ? 0 : slash);
1866
+ if (dot === -1) return null;
1867
+ if (path.includes("[")) return null;
1868
+ return { primPath: path.slice(0, dot), propName: path.slice(dot + 1) };
1869
+ }
1870
+ function parentOf(path) {
1871
+ const i = path.lastIndexOf("/");
1872
+ return i <= 0 ? "/" : path.slice(0, i);
1873
+ }
1874
+ function leaf(path) {
1875
+ return path.slice(path.lastIndexOf("/") + 1);
1876
+ }
1877
+
1878
+ // src/usd/composition.ts
1879
+ var ARC_KEYS = ["references", "payload", "payloads", "inherits", "specializes"];
1880
+ var STRIP_KEYS = [...ARC_KEYS, "variants", "variantSets"];
1881
+ async function composeLayer(text, baseUrl, resolver, options = {}, stack = /* @__PURE__ */ new Set()) {
1882
+ return composeFile(parseUsda(text), baseUrl, resolver, options, stack);
1883
+ }
1884
+ async function composeFile(file, baseUrl, resolver, options = {}, stack = /* @__PURE__ */ new Set()) {
1885
+ const warn = options.onWarn ?? (() => {
1886
+ });
1887
+ let weak = [];
1888
+ const subLayers = toArcs(file.metadata.subLayers);
1889
+ for (let i = subLayers.length - 1; i >= 0; i--) {
1890
+ const sub = await loadExternalFile(subLayers[i], baseUrl, resolver, options, stack, warn);
1891
+ if (sub) weak = mergePrimLists(weak, sub.prims);
1892
+ }
1893
+ const ctx = {
1894
+ baseUrl,
1895
+ resolver,
1896
+ options,
1897
+ warn,
1898
+ stack,
1899
+ index: buildPathIndex(file.prims),
1900
+ resolving: /* @__PURE__ */ new Set()
1901
+ };
1902
+ const resolved = [];
1903
+ for (const prim of file.prims) resolved.push(await resolvePrim(prim, "", ctx));
1904
+ const prims = weak.length > 0 ? mergePrimLists(weak, resolved) : resolved;
1905
+ return { version: file.version, metadata: stripKeys(file.metadata, STRIP_KEYS), prims };
1906
+ }
1907
+ async function resolvePrim(spec, parentPath, ctx) {
1908
+ const path = `${parentPath}/${spec.name}`;
1909
+ let properties = spec.properties;
1910
+ let children = spec.children;
1911
+ const selection = spec.metadata.variants;
1912
+ if (spec.variantSets && isDictionary(selection)) {
1913
+ for (const [setName, variantName] of Object.entries(selection)) {
1914
+ const variant = spec.variantSets[setName]?.[String(variantName)];
1915
+ if (!variant) continue;
1916
+ properties = mergeProperties(variant.properties, properties);
1917
+ children = mergePrimLists(variant.children, children);
1918
+ }
1919
+ }
1920
+ const resolvedChildren = [];
1921
+ for (const child of children) resolvedChildren.push(await resolvePrim(child, path, ctx));
1922
+ const local = {
1923
+ specifier: spec.specifier,
1924
+ typeName: spec.typeName,
1925
+ name: spec.name,
1926
+ metadata: stripKeys(spec.metadata, STRIP_KEYS),
1927
+ properties,
1928
+ children: resolvedChildren,
1929
+ line: spec.line
1930
+ };
1931
+ const arcs = ARC_KEYS.flatMap((k) => toArcs(spec.metadata[k]));
1932
+ let base = null;
1933
+ for (const arc of arcs) {
1934
+ const target = await loadReferencedPrim(arc, ctx, path);
1935
+ if (target) base = base ? mergePrim(target, base) : target;
1936
+ }
1937
+ return base ? mergePrim(base, local) : local;
1938
+ }
1939
+ async function loadReferencedPrim(arc, ctx, destPath) {
1940
+ if (arc.assetPath) {
1941
+ const composed = await loadExternalFile(
1942
+ arc,
1943
+ ctx.baseUrl,
1944
+ ctx.resolver,
1945
+ ctx.options,
1946
+ ctx.stack,
1947
+ ctx.warn
1948
+ );
1949
+ if (!composed) return null;
1950
+ const target = arc.primPath ? findPrimByPath(composed, arc.primPath) : defaultPrim(composed, ctx.warn);
1951
+ if (!target) {
1952
+ ctx.warn(
1953
+ `reference target ${arc.primPath ?? "(defaultPrim)"} not found in ${arc.assetPath.path}`
1954
+ );
1955
+ return null;
1956
+ }
1957
+ const sourceRoot = arc.primPath ?? `/${target.name}`;
1958
+ return remapPaths(target, sourceRoot, destPath);
1959
+ }
1960
+ if (arc.primPath) {
1961
+ if (ctx.resolving.has(arc.primPath)) {
1962
+ ctx.warn(`internal composition cycle at ${arc.primPath}; skipping`);
1963
+ return null;
1964
+ }
1965
+ const target = ctx.index.get(arc.primPath);
1966
+ if (!target) {
1967
+ ctx.warn(`internal reference target ${arc.primPath} not found`);
1968
+ return null;
1969
+ }
1970
+ const parentPath = arc.primPath.slice(0, arc.primPath.lastIndexOf("/"));
1971
+ const composed = await resolvePrim(target, parentPath, {
1972
+ ...ctx,
1973
+ resolving: /* @__PURE__ */ new Set([...ctx.resolving, arc.primPath])
1970
1974
  });
1975
+ return remapPaths(composed, arc.primPath, destPath);
1971
1976
  }
1972
- for (const spec of specs) {
1973
- if (spec.specType !== SPEC_ATTRIBUTE && spec.specType !== SPEC_RELATIONSHIP) continue;
1974
- const split = splitProperty(paths[spec.pathIndex] ?? "");
1975
- if (!split) continue;
1976
- const prim = primByPath.get(split.primPath);
1977
- if (!prim) continue;
1978
- const fm = fieldsOf(spec.fieldSetIndex);
1979
- prim.properties.push(
1980
- spec.specType === SPEC_ATTRIBUTE ? buildAttribute(crate, split.propName, fm) : buildRelationship(crate, split.propName, fm)
1981
- );
1977
+ return null;
1978
+ }
1979
+ async function loadExternalFile(arc, baseUrl, resolver, options, stack, warn) {
1980
+ if (!arc.assetPath) return null;
1981
+ const url = resolver.resolve(arc.assetPath.path, baseUrl);
1982
+ if (stack.has(url)) {
1983
+ warn(`composition cycle detected at ${url}; skipping`);
1984
+ return null;
1982
1985
  }
1983
- for (const [path, prim] of primByPath) {
1984
- const parentPath = parentOf(path);
1985
- if (parentPath === "/") rootPrims.push(prim);
1986
- else primByPath.get(parentPath)?.children.push(prim);
1986
+ if (stack.size >= (options.maxDepth ?? 64)) {
1987
+ warn(`composition exceeded max depth at ${url}; skipping`);
1988
+ return null;
1987
1989
  }
1988
- return { version: crate.version.join("."), metadata: layerMetadata, prims: rootPrims };
1990
+ let bytes;
1991
+ try {
1992
+ bytes = await fetchLayerBytes(resolver, url);
1993
+ } catch (err) {
1994
+ warn(`cannot resolve "${arc.assetPath.path}" -> ${url}: ${err.message}`);
1995
+ return null;
1996
+ }
1997
+ const childStack = /* @__PURE__ */ new Set([...stack, url]);
1998
+ if (CrateReader.isCrate(bytes)) {
1999
+ return composeFile(crateToUsdaFile(new CrateReader(bytes)), url, resolver, options, childStack);
2000
+ }
2001
+ return composeLayer(new TextDecoder().decode(bytes), url, resolver, options, childStack);
1989
2002
  }
1990
- function buildAttribute(crate, name, fm) {
1991
- const defaultRep = fm.get("default");
1992
- const attr = {
1993
- kind: "attribute",
1994
- name,
1995
- typeName: asString(crate, fm.get("typeName")) ?? "",
1996
- isArray: defaultRep !== void 0 ? decodeRepBits(defaultRep).isArray : false,
1997
- variability: asNumber(crate, fm.get("variability")) === 1 ? "uniform" : "varying",
1998
- custom: false,
1999
- metadata: {},
2000
- line: 0
2003
+ async function fetchLayerBytes(resolver, url) {
2004
+ if (resolver.fetchBytes) return resolver.fetchBytes(url);
2005
+ return new TextEncoder().encode(await resolver.fetchText(url));
2006
+ }
2007
+ function remapPaths(prim, from, to) {
2008
+ if (from === to) return prim;
2009
+ return {
2010
+ ...prim,
2011
+ properties: prim.properties.map((p) => remapProperty(p, from, to)),
2012
+ children: prim.children.map((c) => remapPaths(c, from, to))
2001
2013
  };
2002
- if (defaultRep !== void 0) {
2003
- const value = crate.getValue(defaultRep);
2004
- if (value !== void 0) attr.value = value;
2014
+ }
2015
+ function remapProperty(prop, from, to) {
2016
+ if (prop.kind === "relationship") {
2017
+ return { ...prop, targets: prop.targets.map((t) => remapPath(t, from, to)) };
2005
2018
  }
2006
- return attr;
2019
+ if (prop.kind === "attribute" && prop.connections) {
2020
+ return { ...prop, connections: prop.connections.map((c) => remapPath(c, from, to)) };
2021
+ }
2022
+ return prop;
2007
2023
  }
2008
- function buildRelationship(crate, name, fm) {
2009
- const targetsValue = fm.has("targetPaths") ? crate.getValue(fm.get("targetPaths")) : void 0;
2010
- const targets = Array.isArray(targetsValue) ? targetsValue.filter((t) => typeof t === "string") : [];
2024
+ function remapPath(path, from, to) {
2025
+ if (path === from) return to;
2026
+ if (path.startsWith(from) && /[/.[{]/.test(path[from.length] ?? "")) {
2027
+ return to + path.slice(from.length);
2028
+ }
2029
+ return path;
2030
+ }
2031
+ function mergePrim(base, over) {
2011
2032
  return {
2012
- kind: "relationship",
2013
- name,
2014
- custom: false,
2015
- listOp: "explicit",
2016
- targets,
2017
- metadata: {},
2018
- line: 0
2033
+ specifier: over.specifier === "over" ? base.specifier : over.specifier,
2034
+ typeName: over.typeName || base.typeName,
2035
+ name: over.name,
2036
+ metadata: mergeMetadata(base.metadata, over.metadata),
2037
+ properties: mergeProperties(base.properties, over.properties),
2038
+ children: mergePrimLists(base.children, over.children),
2039
+ line: over.line
2019
2040
  };
2020
2041
  }
2021
- function buildPrimMetadata(crate, fm) {
2022
- const meta = {};
2023
- const apiSchemas = fm.has("apiSchemas") ? crate.getValue(fm.get("apiSchemas")) : void 0;
2024
- if (Array.isArray(apiSchemas)) meta.apiSchemas = apiSchemas;
2025
- const kind = asString(crate, fm.get("kind"));
2026
- if (kind !== void 0) meta.kind = kind;
2027
- return meta;
2042
+ function mergePrimLists(base, over) {
2043
+ const byName = /* @__PURE__ */ new Map();
2044
+ for (const p of base) byName.set(p.name, p);
2045
+ for (const p of over) {
2046
+ const existing = byName.get(p.name);
2047
+ byName.set(p.name, existing ? mergePrim(existing, p) : p);
2048
+ }
2049
+ return [...byName.values()];
2028
2050
  }
2029
- function buildLayerMetadata(crate, fm) {
2030
- const meta = {};
2031
- const upAxis = asString(crate, fm.get("upAxis"));
2032
- if (upAxis !== void 0) meta.upAxis = upAxis;
2033
- const defaultPrim2 = asString(crate, fm.get("defaultPrim"));
2034
- if (defaultPrim2 !== void 0) meta.defaultPrim = defaultPrim2;
2035
- const metersPerUnit = asNumber(crate, fm.get("metersPerUnit"));
2036
- if (metersPerUnit !== void 0) meta.metersPerUnit = metersPerUnit;
2037
- return meta;
2051
+ function mergeProperties(base, over) {
2052
+ const byName = /* @__PURE__ */ new Map();
2053
+ for (const p of base) byName.set(p.name, p);
2054
+ for (const p of over) {
2055
+ const existing = byName.get(p.name);
2056
+ byName.set(p.name, existing ? mergeProperty(existing, p) : p);
2057
+ }
2058
+ return [...byName.values()];
2038
2059
  }
2039
- function asString(crate, rep) {
2040
- if (rep === void 0) return void 0;
2041
- const v = crate.getValue(rep);
2042
- return typeof v === "string" ? v : void 0;
2060
+ function mergeProperty(base, over) {
2061
+ if (base.kind !== over.kind) return over;
2062
+ if (base.kind === "attribute" && over.kind === "attribute") {
2063
+ const merged = {
2064
+ ...over,
2065
+ typeName: over.typeName || base.typeName,
2066
+ metadata: mergeMetadata(base.metadata, over.metadata)
2067
+ };
2068
+ const value = over.value !== void 0 ? over.value : base.value;
2069
+ if (value !== void 0) merged.value = value;
2070
+ const timeSamples = over.timeSamples ?? base.timeSamples;
2071
+ if (timeSamples) merged.timeSamples = timeSamples;
2072
+ const connections = over.connections ?? base.connections;
2073
+ if (connections) merged.connections = connections;
2074
+ return merged;
2075
+ }
2076
+ if (base.kind === "relationship" && over.kind === "relationship") {
2077
+ return {
2078
+ ...over,
2079
+ targets: over.targets.length > 0 ? over.targets : base.targets,
2080
+ metadata: mergeMetadata(base.metadata, over.metadata)
2081
+ };
2082
+ }
2083
+ return over;
2043
2084
  }
2044
- function asNumber(crate, rep) {
2045
- if (rep === void 0) return void 0;
2046
- const v = crate.getValue(rep);
2047
- return typeof v === "number" ? v : void 0;
2085
+ function mergeMetadata(base, over) {
2086
+ const merged = { ...base, ...over };
2087
+ const a = base.apiSchemas;
2088
+ const b = over.apiSchemas;
2089
+ if (Array.isArray(a) || Array.isArray(b)) {
2090
+ const seen = /* @__PURE__ */ new Set();
2091
+ const union = [];
2092
+ for (const v of [...Array.isArray(a) ? a : [], ...Array.isArray(b) ? b : []]) {
2093
+ if (!seen.has(v)) {
2094
+ seen.add(v);
2095
+ union.push(v);
2096
+ }
2097
+ }
2098
+ merged.apiSchemas = union;
2099
+ }
2100
+ return merged;
2048
2101
  }
2049
- function splitProperty(path) {
2050
- const slash = path.lastIndexOf("/");
2051
- const dot = path.indexOf(".", slash < 0 ? 0 : slash);
2052
- if (dot === -1) return null;
2053
- if (path.includes("[")) return null;
2054
- return { primPath: path.slice(0, dot), propName: path.slice(dot + 1) };
2102
+ function buildPathIndex(prims, parent = "/", map = /* @__PURE__ */ new Map()) {
2103
+ for (const p of prims) {
2104
+ const path = parent === "/" ? `/${p.name}` : `${parent}/${p.name}`;
2105
+ map.set(path, p);
2106
+ buildPathIndex(p.children, path, map);
2107
+ }
2108
+ return map;
2055
2109
  }
2056
- function parentOf(path) {
2057
- const i = path.lastIndexOf("/");
2058
- return i <= 0 ? "/" : path.slice(0, i);
2110
+ function findPrimByPath(file, path) {
2111
+ const segments = path.split("/").filter(Boolean);
2112
+ let level = file.prims;
2113
+ let found = null;
2114
+ for (const seg of segments) {
2115
+ found = level.find((p) => p.name === seg) ?? null;
2116
+ if (!found) return null;
2117
+ level = found.children;
2118
+ }
2119
+ return found;
2059
2120
  }
2060
- function leaf(path) {
2061
- return path.slice(path.lastIndexOf("/") + 1);
2121
+ function defaultPrim(file, warn) {
2122
+ const name = file.metadata.defaultPrim;
2123
+ if (typeof name === "string") return file.prims.find((p) => p.name === name) ?? null;
2124
+ const first = file.prims[0];
2125
+ if (first) warn(`referenced layer has no defaultPrim; using first root prim "${first.name}"`);
2126
+ return first ?? null;
2127
+ }
2128
+ function toArcs(value) {
2129
+ if (value === void 0) return [];
2130
+ const list = Array.isArray(value) ? value : [value];
2131
+ const arcs = [];
2132
+ for (const v of list) {
2133
+ if (v instanceof AssetPath) arcs.push({ assetPath: v });
2134
+ else if (v && typeof v === "object" && ("assetPath" in v || "primPath" in v))
2135
+ arcs.push(v);
2136
+ }
2137
+ return arcs;
2138
+ }
2139
+ function isDictionary(v) {
2140
+ return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Quat) && !(v instanceof UsdMatrix) && !(v instanceof AssetPath);
2141
+ }
2142
+ function stripKeys(meta, keys) {
2143
+ const out = {};
2144
+ for (const [k, v] of Object.entries(meta)) {
2145
+ if (!keys.includes(k)) out[k] = v;
2146
+ }
2147
+ return out;
2148
+ }
2149
+ var USD_ENTRY = /\.(usda|usdc|usd)$/i;
2150
+ function openUsdz(bytes) {
2151
+ const entries = unzipSync(bytes);
2152
+ const names = Object.keys(entries);
2153
+ const rootEntry = names.find((n) => USD_ENTRY.test(n)) ?? names[0];
2154
+ if (!rootEntry) throw new Error("usdz package contains no entries");
2155
+ const decoder = new TextDecoder();
2156
+ const resolver = {
2157
+ resolve(assetPath, baseUrl) {
2158
+ return joinPosix(baseUrl, assetPath);
2159
+ },
2160
+ fetchText(url) {
2161
+ const data = entries[url] ?? entries[url.replace(/^\/+/, "")];
2162
+ if (!data) return Promise.reject(new Error(`not found in usdz: ${url}`));
2163
+ if (/\.usdc$/i.test(url)) {
2164
+ return Promise.reject(
2165
+ new Error(`USDC (binary crate) entries are not supported yet (M10): ${url}`)
2166
+ );
2167
+ }
2168
+ return Promise.resolve(decoder.decode(data));
2169
+ }
2170
+ };
2171
+ return { rootEntry, resolver };
2062
2172
  }
2063
2173
 
2064
2174
  // src/kinematics/transforms.ts
@@ -2406,6 +2516,33 @@ function asMatrix(v, where) {
2406
2516
  throw new Error(`${where}: expected a matrix`);
2407
2517
  }
2408
2518
 
2519
+ // src/kinematics/sampling.ts
2520
+ function interpolate(channel, t) {
2521
+ const { times, values } = channel;
2522
+ const n = times.length;
2523
+ if (n === 0) return 0;
2524
+ if (t <= times[0]) return values[0];
2525
+ if (t >= times[n - 1]) return values[n - 1];
2526
+ let lo = 0;
2527
+ let hi = n - 1;
2528
+ while (lo < hi) {
2529
+ const mid = lo + hi >> 1;
2530
+ if (times[mid] <= t) lo = mid + 1;
2531
+ else hi = mid;
2532
+ }
2533
+ const i = lo - 1;
2534
+ const t0 = times[i];
2535
+ const t1 = times[i + 1];
2536
+ const span = t1 - t0;
2537
+ const f = span > 0 ? (t - t0) / span : 0;
2538
+ return values[i] + (values[i + 1] - values[i]) * f;
2539
+ }
2540
+ function channelFromSamples(samples) {
2541
+ const times = [...samples.keys()].sort((a, b) => a - b);
2542
+ const values = times.map((t) => samples.get(t) ?? 0);
2543
+ return { times, values };
2544
+ }
2545
+
2409
2546
  // src/schemas/usdGeom.ts
2410
2547
  function isXform(prim) {
2411
2548
  return prim.GetTypeName() === "Xform";
@@ -2683,8 +2820,13 @@ function extractRobotDescription(stage, options = {}) {
2683
2820
  joints,
2684
2821
  upAxis: stage.GetUpAxis(),
2685
2822
  metersPerUnit: stage.GetMetersPerUnit(),
2823
+ timeCodesPerSecond: stage.GetTimeCodesPerSecond(),
2686
2824
  ...articulationRoots.length ? { articulationRoots } : {}
2687
2825
  };
2826
+ const startTimeCode = stage.GetStartTimeCode();
2827
+ if (startTimeCode !== void 0) robot.startTimeCode = startTimeCode;
2828
+ const endTimeCode = stage.GetEndTimeCode();
2829
+ if (endTimeCode !== void 0) robot.endTimeCode = endTimeCode;
2688
2830
  const tree = buildKinematicTree(robot, { onWarn: warn });
2689
2831
  robot.rootLink = tree.root;
2690
2832
  if (tree.loopJoints.length) robot.loopJoints = tree.loopJoints;
@@ -2747,6 +2889,17 @@ function buildJoint(prim, linkKeyByPath, warn) {
2747
2889
  ...drive.maxForce !== void 0 ? { maxForce: drive.maxForce } : {}
2748
2890
  };
2749
2891
  if (Object.keys(driveDesc).length > 0) joint.drive = driveDesc;
2892
+ const stateSamples = prim.GetAttribute(`state:${kind}:physics:position`).GetTimeSamples();
2893
+ const driveSamples = prim.GetAttribute(`drive:${kind}:physics:targetPosition`).GetTimeSamples();
2894
+ const samples = stateSamples.size > 0 ? stateSamples : driveSamples;
2895
+ if (samples.size > 0) {
2896
+ const times = [...samples.keys()].sort((a, b) => a - b);
2897
+ const values = times.map((t) => {
2898
+ const v = samples.get(t);
2899
+ return typeof v === "number" ? jointValueToSI(angular, v) : 0;
2900
+ });
2901
+ joint.valueSamples = { times, values };
2902
+ }
2750
2903
  return joint;
2751
2904
  }
2752
2905
  function buildKeyMap(paths) {
@@ -2767,6 +2920,6 @@ function leafName(path) {
2767
2920
  return parts[parts.length - 1] ?? path;
2768
2921
  }
2769
2922
 
2770
- 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 };
2771
- //# sourceMappingURL=chunk-XH3L7XDJ.js.map
2772
- //# sourceMappingURL=chunk-XH3L7XDJ.js.map
2923
+ 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, channelFromSamples, composeFile, composeLayer, computeLocalTransform, crateToUsdaFile, createMemoryResolver, driveKindFor, extractRobotDescription, fromUsdMatrix, gatherMeshDescendants, getJointAxis, getJointBodies, getJointDrive, getJointLimits, getJointLocalFrame, getJointStatePosition, getJointType, getTranslation, hasArticulationRootAPI, hasCollisionAPI, hasRigidBodyAPI, identity4, interpolate, invert, isMesh, isScope, isXform, iterDescendants, joinPosix, jointValueToSI, makeEuler, makeRotationFromQuat, makeRotationX, makeRotationY, makeRotationZ, makeScale, makeTranslation, multiply, multiplyAll, normalizeJointLimits, openUsdz, parseOpType, parseUsda, refineJointType, tokenize };
2924
+ //# sourceMappingURL=chunk-FYVZ7YPW.js.map
2925
+ //# sourceMappingURL=chunk-FYVZ7YPW.js.map