# 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](README.md) · [llms.txt](../llms.txt)
