three-usd-robot 0.2.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.
package/README.md CHANGED
@@ -8,13 +8,16 @@ Think of it as a **USD version of [`urdf-loader`](https://www.npmjs.com/package/
8
8
  it reads the link / joint / xform / mesh structure out of `UsdPhysics` robot assets
9
9
  and drives forward kinematics on a Three.js `Object3D` hierarchy.
10
10
 
11
- > 🚧 **Status: v0.2 + USDC.** Loads **ASCII `.usda`**, **binary `.usdc` / `.usd`
12
- > (crate)**, and **`.usdz`** robots — including multi-file assets via
13
- > references/payloads/sublayers drives forward kinematics with meshes,
14
- > normalizes up-axis & units, and seeds the initial pose from joint drives. The
15
- > crate reader is a from-scratch TypeScript implementation (no OpenUSD/WASM
16
- > dependency). Not yet: variants, instancing, and time-sampled (animated)
17
- > values (see [`MILESTONES.md`](./MILESTONES.md), M10–M11).
11
+ > 🚧 **Status: v0.3.** Loads **ASCII `.usda`**, **binary `.usdc` / `.usd`
12
+ > (crate)**, and **`.usdz`** robots — including **multi-file assets** via
13
+ > references / payloads / sublayers (resolved across `.usda` *and* binary layers,
14
+ > with relationship-path remapping), **variant selections**, and **instanceable**
15
+ > prims drives forward kinematics with meshes, applies flat **`UsdShade`
16
+ > material colors** (UsdPreviewSurface / OmniPBR constants) and **diffuse
17
+ > textures** (`UsdUVTexture`), normalizes up-axis & units, seeds the initial
18
+ > pose, and **plays back time-sampled joint trajectories**. The crate reader is a
19
+ > from-scratch TypeScript implementation (no OpenUSD/WASM dependency). Not yet:
20
+ > time samples and variant *selection* stored inside binary crate.
18
21
 
19
22
  ```ts
20
23
  // .usda / .usdc / binary .usd / .usdz are all auto-detected:
@@ -23,6 +26,8 @@ const robot = await new ThreeUsdRobotLoader().loadAsync("/assets/robot.usd");
23
26
  const robot = await new ThreeUsdRobotLoader().parseCrate(usdcBytes);
24
27
  ```
25
28
 
29
+ ![demo](assets/anim_demo.gif)
30
+
26
31
  ## Install
27
32
 
28
33
  ```sh
@@ -74,6 +79,20 @@ createJointSliderPanel(robot, new GUI()); // one slider per articulated joint
74
79
  The `extras` panel takes the GUI instance from you, so the library never bundles
75
80
  `lil-gui`. See [`examples/`](./examples) for runnable Vite demos.
76
81
 
82
+ ### Animation playback
83
+
84
+ If the asset has time-sampled joint trajectories (joint-state or drive-target
85
+ time samples), the robot plays them back:
86
+
87
+ ```ts
88
+ if (robot.hasAnimation()) {
89
+ const { start, end } = robot.getTimeRange()!;
90
+ const fps = robot.getTimeCodesPerSecond();
91
+ // in your render loop, advance a time code and sample:
92
+ robot.setTime(t); // interpolates every animated joint and updates FK
93
+ }
94
+ ```
95
+
77
96
  ### Inspect without Three.js
78
97
 
79
98
  ```ts
@@ -1,5 +1,5 @@
1
1
  import * as THREE from 'three';
2
- import { d as JointType, A as Axis, J as JointDescription, L as LinkDescription, R as RobotDescription, e as KinematicTree } from './buildKinematicTree-2fg6ZN8m.js';
2
+ import { J as JointType, A as Axis, a as JointDescription, L as LinkDescription, R as RobotDescription, K as KinematicTree } from './buildKinematicTree-CZjBMA1I.js';
3
3
 
4
4
  /**
5
5
  * The articulated "motion" node of a joint, inserted between the joint's two
@@ -107,6 +107,20 @@ declare class ThreeUsdRobot extends THREE.Object3D {
107
107
  getJointNames(): string[];
108
108
  getLinkNames(): string[];
109
109
  getKinematicTree(): KinematicTree;
110
+ /** Playback rate in time codes per second (from the stage; default 24). */
111
+ getTimeCodesPerSecond(): number;
112
+ /** Whether any joint has a time-sampled trajectory. */
113
+ hasAnimation(): boolean;
114
+ /**
115
+ * Animation range in time codes: the union of authored joint sample ranges,
116
+ * falling back to the stage `startTimeCode`/`endTimeCode`. `null` if neither.
117
+ */
118
+ getTimeRange(): {
119
+ start: number;
120
+ end: number;
121
+ } | null;
122
+ /** Sample every animated joint at time code `t` and apply the values. */
123
+ setTime(t: number): void;
110
124
  get showVisual(): boolean;
111
125
  set showVisual(v: boolean);
112
126
  get showCollision(): boolean;
@@ -80,9 +80,22 @@ type PrimSpec = {
80
80
  metadata: MetadataMap;
81
81
  properties: PropertySpec[];
82
82
  children: PrimSpec[];
83
+ /** Authored variant sets (`variantSet "name" = { ... }`), if any. */
84
+ variantSets?: VariantSetMap;
83
85
  /** 1-based source line of the prim declaration (for diagnostics). */
84
86
  line: number;
85
87
  };
88
+ /** The opinions a single variant contributes when selected. */
89
+ type VariantContent = {
90
+ properties: PropertySpec[];
91
+ children: PrimSpec[];
92
+ };
93
+ /** `variantSetName → variantName → content`. */
94
+ type VariantSetMap = {
95
+ [setName: string]: {
96
+ [variantName: string]: VariantContent;
97
+ };
98
+ };
86
99
  type PropertySpec = AttributeSpec | RelationshipSpec;
87
100
  type AttributeSpec = {
88
101
  kind: "attribute";
@@ -164,6 +177,25 @@ declare function fromUsdMatrix(m: UsdMatrix): Mat4;
164
177
  /** Extract the translation component `[x, y, z]` from a {@link Mat4}. */
165
178
  declare function getTranslation(m: Mat4): Vec3;
166
179
 
180
+ /**
181
+ * Time-sample interpolation for animated values (e.g. joint trajectories).
182
+ *
183
+ * USD time samples are keyed by time code. We linearly interpolate between the
184
+ * two bracketing samples and hold the endpoints outside the authored range
185
+ * (matching USD's held extrapolation).
186
+ */
187
+ /** A sorted time-sampled scalar channel. */
188
+ type SampleChannel = {
189
+ /** Sample times, ascending. */
190
+ times: number[];
191
+ /** Sample values, parallel to {@link times} (SI units). */
192
+ values: number[];
193
+ };
194
+ /** Linearly sample `channel` at time `t` (held outside the range). */
195
+ declare function interpolate(channel: SampleChannel, t: number): number;
196
+ /** Build a sorted {@link SampleChannel} from `(time → value)` pairs via `map`. */
197
+ declare function channelFromSamples(samples: Map<number, number>): SampleChannel;
198
+
167
199
  /**
168
200
  * Robot intermediate representation (IR) — Three.js-independent.
169
201
  *
@@ -192,6 +224,11 @@ type RobotDescription = {
192
224
  upAxis: "Y" | "Z";
193
225
  /** Stage linear unit, for the M9 scale normalization. */
194
226
  metersPerUnit: number;
227
+ /** Playback rate (time codes per second); defaults to 24 when unauthored. */
228
+ timeCodesPerSecond?: number;
229
+ /** Authored animation range (time codes), if any. */
230
+ startTimeCode?: number;
231
+ endTimeCode?: number;
195
232
  /** Non-fatal extraction diagnostics. */
196
233
  warnings?: string[];
197
234
  };
@@ -224,6 +261,8 @@ type JointDescription = {
224
261
  jointFrame1: Mat4;
225
262
  /** Initial joint value (SI) from JointStateAPI or a drive target, if authored. */
226
263
  initialValue?: number;
264
+ /** Time-sampled joint value trajectory (SI), if authored — drives playback. */
265
+ valueSamples?: SampleChannel;
227
266
  drive?: JointDriveDescription;
228
267
  };
229
268
  /** Authored joint drive parameters (`UsdPhysicsDriveAPI`), as read in M3. */
@@ -280,4 +319,4 @@ type BuildTreeOptions = {
280
319
  };
281
320
  declare function buildKinematicTree(robot: RobotDescription, options?: BuildTreeOptions): KinematicTree;
282
321
 
283
- export { type Axis as A, type BuildTreeOptions as B, type CompositionArc as C, DEG2RAD as D, makeRotationZ as E, makeScale as F, makeTranslation as G, multiply as H, multiplyAll as I, type JointDescription as J, type KinematicNode as K, type LinkDescription as L, type Mat4 as M, type PrimSpec as P, Quat as Q, type RobotDescription as R, type SdfPath as S, type TreeEdge as T, type UsdDictionary as U, type Variability as V, AssetPath as a, type AttributeSpec as b, type JointDriveDescription as c, type JointType as d, type KinematicTree as e, type ListOp as f, type MetadataMap as g, type PropertySpec as h, RAD2DEG as i, type RelationshipSpec as j, type Specifier as k, UsdMatrix as l, type UsdValue as m, type UsdaFile as n, type Vec2 as o, type Vec3 as p, type Vec4 as q, buildKinematicTree as r, fromUsdMatrix as s, getTranslation as t, identity4 as u, invert as v, makeEuler as w, makeRotationFromQuat as x, makeRotationX as y, makeRotationY as z };
322
+ export { type Axis as A, type BuildTreeOptions as B, type CompositionArc as C, DEG2RAD as D, makeRotationFromQuat as E, makeRotationX as F, makeRotationY as G, makeRotationZ as H, makeScale as I, type JointType as J, type KinematicTree as K, type LinkDescription as L, type Mat4 as M, makeTranslation as N, multiply as O, type PrimSpec as P, Quat as Q, type RobotDescription as R, type SampleChannel as S, type TreeEdge as T, type UsdDictionary as U, type Vec3 as V, multiplyAll as W, type JointDescription as a, AssetPath as b, type AttributeSpec as c, type JointDriveDescription as d, type KinematicNode as e, type ListOp as f, type MetadataMap as g, type PropertySpec as h, RAD2DEG as i, type RelationshipSpec as j, type SdfPath as k, type Specifier as l, UsdMatrix as m, type UsdValue as n, type UsdaFile as o, type Variability as p, type Vec2 as q, type Vec4 as r, buildKinematicTree as s, channelFromSamples as t, fromUsdMatrix as u, getTranslation as v, identity4 as w, interpolate as x, invert as y, makeEuler as z };