5.10 Animations and follow ​

Contract 2.0.0 · package sha256 a857eca95b35921109faf997094bb4192f12527d9d0fcd4be7e97f06425bad6e · generated from examples/section-5/5.10-animations-and-follow.ts by services/onsite-scripter/scripts/build-contract-docs.mjs; edit the source, not this file.

Imports: values (has, validate, the Holo*Error classes, the pure helpers) from @holostep-configurators/runtime-client, types from @holostep-configurators/runtime-client/contract, /math and /testing names from those entries; boot from the runtime module the root's loadRuntimeAtFloor resolves to. A type your page defines is your app's: declare it there, never import it from the package.

ts
import { mat4 } from '@holostep-configurators/runtime-client/math';
import type { Part, Pose, PoseInput, Session } from '@holostep-configurators/runtime-client/contract';
import type { Mat4 } from '@holostep-configurators/runtime-client/math';
declare const session: Session;
declare const signal: AbortSignal;
declare const pocketFollow: ReadonlyArray<{ source: string; bone: string }>;
declare const pocketId: string;
declare const frameId: string;
declare const mattressId: string;
declare const stretch: number;                                      // the frame's stretch along its lid
declare const lidBones: readonly string[];                          // 'frame', or 'framel' and 'framer' (app code)
declare const closed: ReadonlyMap<string, Pose>;                    // each mattress lid bone's pose, read after animations.reset
declare function lidOnFrame(closed: Pose, frameLid: Mat4, stretch: number): PoseInput;
// exact under the stretch: a lid turned inside a non-uniformly scaled frame is sheared, which no Pose holds
const worldMatrix = (part: Part): Mat4 => {
  const { position, quaternion, scale } = part.parent ? part.pose : part.worldPose;   // a model root's pose is its world pose
  const local = mat4.compose({ position, quaternion, scale });
  return part.parent ? mat4.multiply(worldMatrix(part.parent), local) : local;
};
for (const { source, bone } of pocketFollow)                                    // from the base's attributes
  session.find({ node: pocketId, name: source }).follow({ node: frameId, name: bone }, { offset: 'rest', signal });
session.onFrame((frame) => {
  for (const name of lidBones) {
    const frameLid = session.find({ node: frameId, name }).first();            // this frame's clip pose
    const matLid = session.find({ node: mattressId, name }).first();
    const rest = closed.get(name);
    // a joint's local pose, from the frame's lid and the closed pose: it never compounds on this hook's write
    if (frameLid && matLid && rest) frame.pose(matLid, lidOnFrame(rest, worldMatrix(frameLid), stretch));
  }
}, { phase: 'late', signal });
await session.animations.play(frameId, 'open', { toggle: true });

Back to the examples · llms.txt