three-usd-robot 0.7.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,8 +23,10 @@ exported back to `.usda` / `.usdz` in the browser.
23
23
  instanceable prims are composed for you.
24
24
  - **Robots** — links, joints (fixed / revolute / continuous / prismatic), limits,
25
25
  drives and the initial pose become a `setJointValue`-able hierarchy.
26
- - **Rendering** — meshes with `UsdShade` materials (UsdPreviewSurface / OmniPBR)
27
- and textures; up-axis and units normalized automatically.
26
+ - **Rendering** — meshes and solid gprims (`Cube` / `Sphere` / `Cylinder` /
27
+ `Capsule` / `Cone`) with `UsdShade` materials (UsdPreviewSurface / OmniPBR)
28
+ and textures; up-axis and units normalized automatically. Articulation-free
29
+ stages load as static scenes.
28
30
  - **Animation** — plays back time-sampled joint trajectories.
29
31
  - **Export** — write robots and whole cells back to `.usda` / `.usdz`,
30
32
  simulation-ready for Isaac Sim.
@@ -48,8 +50,8 @@ The CDN is public and CORS-enabled, so this works in the browser too. Try
48
50
  FK check, and a re-export to one self-contained file), or open the Vite example
49
51
  and pick a robot from the preset list.
50
52
 
51
- Not yet supported: time samples stored inside binary crate files, non-mesh
52
- gprims (`Cube`, `Sphere`, …), and full material/shader fidelity.
53
+ Not yet supported: time samples stored inside binary crate files, point/curve
54
+ gprims (`Points`, `BasisCurves`, …), and full material/shader fidelity.
53
55
 
54
56
  ## Install
55
57
 
@@ -79,8 +81,57 @@ robot.getJointNames(); // controllable joints
79
81
  robot.getKinematicTree(); // root, ordering, loop joints, ...
80
82
  ```
81
83
 
82
- Already have the bytes? Use `parse(usdaText)`, `parseCrate(usdcBytes)` or
83
- `parseUsdz(bytes)` instead of `loadAsync`.
84
+ No URL? `parse` also takes in-memory content: USDA source text, or an
85
+ `ArrayBuffer` / typed array / `Blob` holding any supported format — the zip /
86
+ crate magic is sniffed, so a dropped `File` or a response body works as-is:
87
+
88
+ ```ts
89
+ const loader = new ThreeUsdRobotLoader();
90
+ await loader.parse(usdaText); // USDA source string
91
+ await loader.parse(file); // File / Blob from drag & drop or <input type="file">
92
+ await loader.parse(await res.arrayBuffer()); // a fetch you did yourself
93
+ ```
94
+
95
+ `parseUsdz(data)` / `parseCrate(data, baseUrl)` stay as explicit-format entries,
96
+ and `parseRobotDescription(data)` returns the Three.js-independent IR. Pass a
97
+ `baseUrl` as the second `parse` argument if the layer has relative references
98
+ or texture paths to resolve.
99
+
100
+ ### World up-axis & units
101
+
102
+ Stages load normalized: `metersPerUnit` scales the root, and the authored
103
+ `upAxis` (`"Y"` or `"Z"`) is rotated into your world convention via `worldUp`:
104
+
105
+ ```ts
106
+ new ThreeUsdRobotLoader(); // default: "Y" — upright in a stock three.js scene
107
+ new ThreeUsdRobotLoader({ worldUp: "Z" }); // robotics-style Z-up world
108
+ new ThreeUsdRobotLoader({ worldUp: "keep" }); // leave the authored orientation
109
+
110
+ robot.upAxis; // authored stage value ("Y" | "Z"), independent of normalization
111
+ robot.metersPerUnit; // authored stage scale (already applied to the root)
112
+ ```
113
+
114
+ Isaac Sim assets are Z-up, so the default makes them stand upright in a plain
115
+ three.js scene; a Z-up app (ROS-style) passes `worldUp: "Z"` once instead of
116
+ counter-rotating per asset. The M9 option `upAxisConversion` remains as a
117
+ deprecated alias (`"auto"` ≡ `worldUp: "Y"`, `"none"` ≡ `"keep"`).
118
+
119
+ ### Stable addressing (naming contract)
120
+
121
+ Joints and links are keyed by their prim's **leaf name** while it is unique
122
+ across the robot; on a collision (say, two arms each with a `seg` link) the
123
+ colliding entries are keyed by their **full prim path** instead —
124
+ deterministically. Every accessor also takes the full prim path directly, so
125
+ tooling can pin exact prims no matter how the asset is named:
126
+
127
+ ```ts
128
+ robot.setJointValue("/World/armL/j1", 0.4); // same joint as its key
129
+ robot.getLinkWorldMatrix("/World/armL/seg");
130
+ robot.getLinkObjectsByPath(); // Map<primPath, LinkObject>
131
+ robot.getJointObjectsByPath(); // Map<primPath, JointObject>
132
+ ```
133
+
134
+ `LinkObject.primPath` / `JointObject.primPath` carry the reverse direction.
84
135
 
85
136
  ### Viewer toggles & helpers
86
137
 
@@ -94,9 +145,38 @@ import { addJointLimitHelpers } from "three-usd-robot/helpers";
94
145
  addJointLimitHelpers(robot); // arc (revolute) / segment (prismatic) per joint
95
146
  ```
96
147
 
148
+ ### Link highlighting & ghosts
149
+
150
+ Per-link appearance helpers cover the common viewer chores — flagging
151
+ colliding links, material swaps, and translucent "ghost" pose previews:
152
+
153
+ ```ts
154
+ import {
155
+ createGhostRobot,
156
+ highlightLink,
157
+ restoreLinkMaterials,
158
+ setLinkMaterial,
159
+ } from "three-usd-robot/helpers";
160
+
161
+ highlightLink(robot, "link1"); // emissive red tint; maps/colors kept
162
+ highlightLink(robot, "/World/armL/seg", { color: 0xffaa00, opacity: 0.6 });
163
+ setLinkMaterial(robot, "link2", new THREE.MeshBasicMaterial({ wireframe: true }));
164
+ restoreLinkMaterials(robot, "link1"); // exact original materials back
165
+
166
+ const ghost = createGhostRobot(robot, { jointValues: { joint1: 1.2 } });
167
+ scene.add(ghost); // translucent copy previewing the target pose
168
+ ghost.setJointValues(ikSolution); // a full ThreeUsdRobot, driveable like the source
169
+ ```
170
+
171
+ Highlights never stack (each call re-tints from the originals), and ghosts
172
+ share the source's geometry — cloning is cheap enough for onion-skinning.
173
+
97
174
  Loading a whole cell rather than a bare robot? Pass
98
175
  `{ loadSceneGeometry: true }` to the loader to draw the static environment
99
- (floor, guarding, racking, …) around the machines.
176
+ (floor, guarding, racking, …) around the machines. A stage with **no
177
+ articulation at all** — a plain static USD scene — is detected and rendered as
178
+ scene geometry automatically, with the same unit / up-axis normalization; pass
179
+ `loadSceneGeometry: false` to opt out.
100
180
 
101
181
  ### Joint slider panel (lil-gui)
102
182
 
@@ -1,5 +1,5 @@
1
1
  import * as THREE from 'three';
2
- import { J as JointType, A as Axis, a as JointDescription, L as LinkDescription, R as RobotDescription, K as KinematicTree } from './buildKinematicTree-Ccd2DIKH.js';
2
+ import { J as JointType, A as Axis, a as JointDescription, L as LinkDescription, R as RobotDescription, K as KinematicTree } from './buildKinematicTree-D4R0hEtN.js';
3
3
 
4
4
  /**
5
5
  * The articulated "motion" node of a joint, inserted between the joint's two
@@ -10,6 +10,8 @@ import { J as JointType, A as Axis, a as JointDescription, L as LinkDescription,
10
10
  declare class JointObject extends THREE.Object3D {
11
11
  readonly isJointObject = true;
12
12
  readonly jointName: string;
13
+ /** Full USD prim path of the joint — the collision-proof address. */
14
+ readonly primPath: string;
13
15
  readonly jointType: JointType;
14
16
  readonly axisToken: Axis;
15
17
  readonly axis: THREE.Vector3;
@@ -39,15 +41,25 @@ declare class LinkObject extends THREE.Object3D {
39
41
  constructor(link: LinkDescription);
40
42
  }
41
43
 
44
+ /** Target world up-axis: normalize to Y-up / Z-up, or keep the authored orientation. */
45
+ type WorldUpAxis = "Y" | "Z" | "keep";
42
46
  type ThreeUsdRobotOptions = {
43
47
  /** Clamp `setJointValue` to authored limits (default `true`). */
44
48
  clampJointLimits?: boolean;
45
49
  /** Size of the built-in joint-axis / link-frame helpers (stage units, default `0.15`). */
46
50
  helperSize?: number;
47
51
  /**
48
- * Up-axis correction applied at the robot root. `"auto"` rotates Z-up assets
49
- * into the Three.js Y-up scene; `"Z"` forces it, `"Y"`/`"none"` leave the
50
- * orientation as authored. Default `"none"` (the loader defaults to `"auto"`).
52
+ * Target world up-axis. The root is rotated so the stage's authored `upAxis`
53
+ * lands in that convention: `"Y"` for a standard three.js scene, `"Z"` for a
54
+ * robotics-style Z-up world, `"keep"` for no correction. Takes precedence
55
+ * over the deprecated {@link ThreeUsdRobotOptions.upAxisConversion}.
56
+ */
57
+ worldUp?: WorldUpAxis;
58
+ /**
59
+ * Legacy up-axis correction: `"auto"` ≡ `worldUp: "Y"`, `"Y"` / `"none"` ≡
60
+ * `worldUp: "keep"`, and `"Z"` forces the Z-up→Y-up rotation regardless of
61
+ * stage metadata. Default `"none"` (the loader defaults to `"auto"`).
62
+ * @deprecated Use {@link ThreeUsdRobotOptions.worldUp}.
51
63
  */
52
64
  upAxisConversion?: "auto" | "Y" | "Z" | "none";
53
65
  /** Extra uniform scale multiplied with the stage `metersPerUnit` (default `1`). */
@@ -63,6 +75,12 @@ type ThreeUsdRobotOptions = {
63
75
  * `parentLink → jointFrame0 → jointMotion → jointFrame1⁻¹ → childLink`,
64
76
  * where only `jointMotion` (a {@link JointObject}) changes with the joint value;
65
77
  * world poses then fall out of Three.js's `updateMatrixWorld`.
78
+ *
79
+ * **Naming contract** — a link/joint's key is its prim's leaf name when that
80
+ * is unique across the robot, else its full prim path (deterministic; see the
81
+ * extractor). Every accessor taking a name equally accepts the full prim path,
82
+ * which is stable regardless of collisions; {@link getLinkObjectsByPath} /
83
+ * {@link getJointObjectsByPath} enumerate the path-keyed tables.
66
84
  */
67
85
  declare class ThreeUsdRobot extends THREE.Object3D {
68
86
  readonly isThreeUsdRobot = true;
@@ -71,6 +89,8 @@ declare class ThreeUsdRobot extends THREE.Object3D {
71
89
  readonly clampJointLimits: boolean;
72
90
  private readonly linkObjects;
73
91
  private readonly jointObjects;
92
+ private readonly linkKeyByPath;
93
+ private readonly jointKeyByPath;
74
94
  private dirty;
75
95
  private readonly helperSize;
76
96
  private _showVisual;
@@ -80,7 +100,7 @@ declare class ThreeUsdRobot extends THREE.Object3D {
80
100
  private jointAxesHelpers;
81
101
  private linkFrameHelpers;
82
102
  constructor(robot: RobotDescription, tree: KinematicTree, options?: ThreeUsdRobotOptions);
83
- /** Orient (Z-upY-up) and scale (metersPerUnit × unitScale) the robot root. */
103
+ /** Orient (authored upAxis target world up) and scale (metersPerUnit × unitScale) the root. */
84
104
  private applyStageNormalization;
85
105
  /** Apply each joint's authored initial value, if any. */
86
106
  private applyInitialPose;
@@ -89,7 +109,14 @@ declare class ThreeUsdRobot extends THREE.Object3D {
89
109
  /** Build `parent → frame0 → motion → frame1⁻¹ → child` for one joint. */
90
110
  private attachJointChain;
91
111
  private attachIsolatedLinks;
92
- /** Set one joint value. Unknown joints are ignored. Returns whether it applied. */
112
+ /** Resolve a link reference key or full prim path to the extractor key. */
113
+ private linkKey;
114
+ /** Resolve a joint reference — key or full prim path — to the extractor key. */
115
+ private jointKey;
116
+ /**
117
+ * Set one joint value, addressed by key or full prim path. Unknown joints
118
+ * are ignored. Returns whether it applied.
119
+ */
93
120
  setJointValue(name: string, value: number): boolean;
94
121
  /** Set several joint values at once (matrix update is coalesced). */
95
122
  setJointValues(values: Record<string, number>): void;
@@ -97,16 +124,33 @@ declare class ThreeUsdRobot extends THREE.Object3D {
97
124
  /** Recompute world matrices. Called lazily by the getters; safe to call directly. */
98
125
  updateKinematics(): void;
99
126
  private ensureUpdated;
127
+ /** World matrix of a link, addressed by key or full prim path. */
100
128
  getLinkWorldMatrix(name: string): THREE.Matrix4;
101
129
  getLinkWorldPosition(name: string): THREE.Vector3;
130
+ /** Link object by key or full prim path. */
102
131
  getLinkObject(name: string): LinkObject | undefined;
132
+ /** Joint object by key or full prim path. */
103
133
  getJointObject(name: string): JointObject | undefined;
134
+ /**
135
+ * Table of link prim path → {@link LinkObject}. Prim paths are the
136
+ * collision-proof way to pin a link (e.g. to attach tools or gizmos).
137
+ */
138
+ getLinkObjectsByPath(): Map<string, LinkObject>;
139
+ /**
140
+ * Table of joint prim path → {@link JointObject}, covering the joints
141
+ * realized in the kinematic tree (loop joints have no motion node).
142
+ */
143
+ getJointObjectsByPath(): Map<string, JointObject>;
104
144
  getJoints(): JointDescription[];
105
145
  getLinks(): LinkDescription[];
106
146
  /** Names of the articulated (controllable) joints. */
107
147
  getJointNames(): string[];
108
148
  getLinkNames(): string[];
109
149
  getKinematicTree(): KinematicTree;
150
+ /** Authored stage up-axis (`"Y"` or `"Z"`) — unaffected by `worldUp` normalization. */
151
+ get upAxis(): "Y" | "Z";
152
+ /** Authored stage scale in meters per unit (already applied to the root). */
153
+ get metersPerUnit(): number;
110
154
  /** Playback rate in time codes per second (from the stage; default 24). */
111
155
  getTimeCodesPerSecond(): number;
112
156
  /** Whether any joint has a time-sampled trajectory. */
@@ -132,4 +176,4 @@ declare class ThreeUsdRobot extends THREE.Object3D {
132
176
  private setKindVisibility;
133
177
  }
134
178
 
135
- export { JointObject as J, LinkObject as L, ThreeUsdRobot as T, type ThreeUsdRobotOptions as a };
179
+ export { JointObject as J, LinkObject as L, ThreeUsdRobot as T, type WorldUpAxis as W, type ThreeUsdRobotOptions as a };
@@ -0,0 +1,92 @@
1
+ import { R as RobotDescription } from './buildKinematicTree-D4R0hEtN.js';
2
+ import { A as AssetResolver, U as UsdSource, B as BinarySource } from './bytes-MOJ2oN-u.js';
3
+ import { W as WorldUpAxis, T as ThreeUsdRobot } from './ThreeUsdRobot-BZ_vlr1R.js';
4
+
5
+ type ThreeUsdRobotLoaderOptions = {
6
+ /** Resolver for references / payloads / sublayers (default {@link DefaultAssetResolver}). */
7
+ assetResolver?: AssetResolver;
8
+ /** Render visual meshes (M6). */
9
+ loadVisuals?: boolean;
10
+ /** Render collision meshes (M6). */
11
+ loadCollisions?: boolean;
12
+ /**
13
+ * Also render gprims that belong to no link — the static scenery of a cell
14
+ * that contains robots (floor, guarding, racking, …). Placed by their
15
+ * authored stage transform. Default `false`; a stage with no articulation at
16
+ * all (a pure static scene) defaults to `true` so it renders out of the box.
17
+ */
18
+ loadSceneGeometry?: boolean;
19
+ /** Load diffuse textures referenced by materials (default `true`). */
20
+ loadTextures?: boolean;
21
+ /**
22
+ * Target world up-axis. Any stage (Y-up or Z-up) is normalized into this
23
+ * convention: `"Y"` for a standard three.js scene (the default behavior),
24
+ * `"Z"` for a robotics-style Z-up world, `"keep"` to leave the authored
25
+ * orientation. Takes precedence over {@link upAxisConversion}.
26
+ */
27
+ worldUp?: WorldUpAxis;
28
+ /**
29
+ * Legacy up-axis correction (M9). Default `"auto"` ≡ `worldUp: "Y"`.
30
+ * @deprecated Use {@link worldUp}.
31
+ */
32
+ upAxisConversion?: "auto" | "Y" | "Z" | "none";
33
+ /** Extra uniform scale multiplied with `metersPerUnit` (M9). */
34
+ unitScale?: number;
35
+ /** Clamp `setJointValue` to authored limits (default `true`). */
36
+ clampJointLimits?: boolean;
37
+ /** Seed joints from drive targets / joint state (M9). */
38
+ applyDriveTargetsAsInitialPose?: boolean;
39
+ /** Override the robot name. */
40
+ robotName?: string;
41
+ /** Receives non-fatal load diagnostics. */
42
+ onWarn?: (message: string) => void;
43
+ };
44
+ /**
45
+ * Loads Isaac Sim / OpenUSD robot assets into a controllable {@link ThreeUsdRobot}.
46
+ *
47
+ * Assets load by URL ({@link loadAsync}) or from in-memory content
48
+ * ({@link parse} — USDA text, `ArrayBuffer`, typed array, or `Blob`/`File`).
49
+ * Composition (references / payloads / sublayers, M8) is resolved through an
50
+ * {@link AssetResolver}. Mesh rendering is M6; unit / up-axis / initial-pose
51
+ * handling is M9; USDC and variants are M10.
52
+ */
53
+ declare class ThreeUsdRobotLoader {
54
+ readonly options: ThreeUsdRobotLoaderOptions;
55
+ constructor(options?: ThreeUsdRobotLoaderOptions);
56
+ private get resolver();
57
+ /**
58
+ * Fetch an asset by URL and build the robot. `.usdz` packages are unzipped and
59
+ * composed from their entries; everything else is sniffed for the zip / crate
60
+ * magic and parsed as USDZ, binary USDC, or USDA text.
61
+ */
62
+ loadAsync(url: string): Promise<ThreeUsdRobot>;
63
+ private fetchRootBytes;
64
+ /**
65
+ * Build a robot from in-memory content — no fetch involved. Accepts USDA
66
+ * source text, or an `ArrayBuffer` / typed array / `Blob` (e.g. a dropped
67
+ * `File`) holding USDA text, a binary crate, or a `.usdz` package; binary
68
+ * input is sniffed for the zip / crate magic. `baseUrl` anchors relative
69
+ * references, payloads, and texture paths of non-package input.
70
+ */
71
+ parse(data: UsdSource, baseUrl?: string): Promise<ThreeUsdRobot>;
72
+ /** Build a robot from a `.usdz` package (bytes, `ArrayBuffer`, or `Blob`). */
73
+ parseUsdz(data: BinarySource): Promise<ThreeUsdRobot>;
74
+ /** Build a robot from a binary crate (`.usdc` / binary `.usd`). */
75
+ parseCrate(data: BinarySource, baseUrl?: string): Promise<ThreeUsdRobot>;
76
+ /**
77
+ * Parse + compose in-memory content (same formats as {@link parse}) into the
78
+ * Three.js-independent robot IR.
79
+ */
80
+ parseRobotDescription(data: UsdSource, baseUrl?: string): Promise<RobotDescription>;
81
+ /** Sniff in-memory content (text / zip / crate) and compose it into a stage. */
82
+ private openSource;
83
+ private openUsdzStage;
84
+ private buildFromStage;
85
+ private composeStage;
86
+ /** Compose a layer from raw bytes, sniffing binary crate vs USDA text. */
87
+ private composeStageFromBytes;
88
+ private robotOptions;
89
+ private extractOptions;
90
+ }
91
+
92
+ export { type ThreeUsdRobotLoaderOptions as T, ThreeUsdRobotLoader as a };
@@ -256,9 +256,9 @@ type LinkDescription = {
256
256
  /** Display name (leaf prim name). */
257
257
  name: string;
258
258
  primPath: string;
259
- /** Mesh prim paths to render. */
259
+ /** Renderable gprim paths (Mesh / Cube / Sphere / Cylinder / Capsule / Cone). */
260
260
  visualPrims: string[];
261
- /** Mesh prim paths flagged with a collision API. */
261
+ /** Gprim paths flagged with a collision API (or a non-visual purpose). */
262
262
  collisionPrims?: string[];
263
263
  /** Mass properties (`UsdPhysicsMassAPI`), if authored (M16). */
264
264
  inertial?: LinkInertialDescription;
@@ -26,4 +26,17 @@ declare function createMemoryResolver(files: Record<string, string | Uint8Array>
26
26
  /** Resolve `rel` against `baseUrl` using posix semantics, normalizing `.`/`..`. */
27
27
  declare function joinPosix(baseUrl: string, rel: string): string;
28
28
 
29
- export { type AssetResolver as A, DefaultAssetResolver as D, createMemoryResolver as c, joinPosix as j };
29
+ /**
30
+ * In-memory input normalization for the loader entry points. Callers hold USD
31
+ * content in many shapes — a `fetch` response's `ArrayBuffer`, a `Uint8Array`
32
+ * (or any typed-array view), a dropped `File` / `Blob` — and every byte-eating
33
+ * API here funnels through {@link toBytes} so all of them are accepted.
34
+ */
35
+ /** Binary USD content: an `ArrayBuffer`, any typed-array view, or a `Blob`/`File`. */
36
+ type BinarySource = ArrayBuffer | ArrayBufferView | Blob;
37
+ /** In-memory USD content: USDA source text, or {@link BinarySource} bytes. */
38
+ type UsdSource = string | BinarySource;
39
+ /** Normalize a {@link BinarySource} to bytes, honoring a view's offset/length. */
40
+ declare function toBytes(data: BinarySource): Promise<Uint8Array>;
41
+
42
+ export { type AssetResolver as A, type BinarySource as B, DefaultAssetResolver as D, type UsdSource as U, createMemoryResolver as c, joinPosix as j, toBytes as t };