--- title: "Timing & Animation" description: "Set clip timing, elastic holds, GSAP tweens, and keyframed animations on composition elements." --- Every clip in a HyperFrames composition has a position on the timeline (`data-start`, `data-duration`) and an optional animation attached to it. The SDK exposes typed helpers for both: the timing API controls *when* an element appears and how long it stays on screen; the animation API controls *how* it moves through that window. ## Clip Timing ### Reading timings `getElementTimings()` returns a `Record` — one entry per element that carries timing data. Values are derived from the live DOM on every call (never cached in the snapshot). Keys are `scopedId`: for top-level elements this equals the bare `id`, but for elements inside a sub-composition it is the scoped form `"hf-HOST/hf-LEAF"`. ```typescript import { openComposition } from "@hyperframes/sdk"; const comp = await openComposition(html); const timings = comp.getElementTimings(); for (const [id, t] of Object.entries(timings)) { console.log(id, t.enterAt, "→", t.exitAt, "labels:", t.labels); } ``` Each `ElementTimingSnapshot` contains: Absolute timeline position (seconds) at which the element enters. Absolute timeline position (seconds) at which the element exits. GSAP timeline label names whose numeric position falls within `[enterAt, exitAt]`. Parsed fresh from the GSAP script on every `getElementTimings()` call — never stale. `getElementTimings()` only includes elements that have `data-start` and either `data-duration` or `data-end` attributes. Untimed elements are omitted. The method prefers `data-duration` over `data-end − data-start` when both exist, matching the behavior of `setTiming`. ### Setting timing on one element ```typescript // Move hf-title to start at 1.0 s, last 2.5 s, on track 0 comp.setTiming("hf-title", { start: 1.0, duration: 2.5, trackIndex: 0 }); ``` All three fields are optional — pass only what you want to change: Clip start time in seconds. Clip duration in seconds. Zero-based track index. ### Updating multiple elements in one batch `setElementTiming(map)` dispatches one `setTiming` op per entry inside a single batch, so the history records one undo step and patch listeners see one event: ```typescript comp.setElementTiming({ "hf-title": { start: 0.5, duration: 2.0 }, "hf-logo": { start: 0.0, duration: 5.0, trackIndex: 1 }, "hf-cta": { start: 3.0, duration: 2.5 }, }); ``` Unknown ids are silently skipped. ### Elastic holds An elastic hold freezes or loops a portion of an element's timeline window. Use it to hold a static frame between two animated segments without changing clip duration. ```typescript comp.setHold("hf-card", { start: 1.5, // hold begins at this time within the composition end: 4.0, // hold ends at this time fill: "freeze", // "freeze" | "loop" }); ``` `ElasticHold` fields: Absolute composition time at which the hold begins. Absolute composition time at which the hold ends. `"freeze"` holds the last frame until `end`; `"loop"` repeats the segment from `start` back to `start`. --- ## GSAP Tweens GSAP tweens are the primary animation primitive. The SDK reads tween IDs from `element.animationIds` (returned by the query API) and writes through `addGsapTween`, `setGsapTween`, and `removeGsapTween`. ### Adding a tween ```typescript const animId = comp.addGsapTween("hf-title", { method: "from", position: 0.5, duration: 0.6, ease: "power3.out", fromProperties: { opacity: 0, y: 40 }, }); // animId is the newly-assigned animation ID — store it for subsequent edits ``` `addGsapTween` returns the newly-assigned animation ID as a `string`. ### GsapTweenSpec fields The GSAP timeline method to call. Timeline position: a number (seconds) or a label-relative string (e.g. `"intro+=0.3"`). Number-only is required for `addWithKeyframes` / `replaceWithKeyframes` — see [Keyframes](#keyframes) below. Tween duration in seconds. GSAP ease string, e.g. `"power2.inOut"`. Starting properties — used with `"from"` and `"fromTo"`. Ending properties — used with `"fromTo"`. Animation target properties — used with `"to"` tweens. Number of repeats (`-1` = infinite). Maps to GSAP's `repeat` option. When `true`, alternates direction on each repeat. GSAP stagger amount (seconds) or a full stagger config object. ### Modifying a tween ```typescript // Change ease and duration — all other fields stay as-is comp.setGsapTween(animId, { ease: "elastic.out(1, 0.5)", duration: 0.9 }); ``` `setGsapTween` takes the animation ID and a `Partial` — only the keys you pass are updated. ### Removing a tween ```typescript comp.removeGsapTween(animId); ``` ### Looking up animation IDs Query the element snapshot to find animation IDs attached to a given element: ```typescript const el = comp.getElement("hf-title"); const [firstAnimId] = el?.animationIds ?? []; if (firstAnimId) { comp.setGsapTween(firstAnimId, { ease: "none" }); } ``` ### Feature-detecting advanced ops Some GSAP operations (such as `setGsapKeyframe`, arc paths, and label ops) require the parser engine, which ships in a later phase. Use `can()` to gate them before dispatching: ```typescript const check = comp.can({ type: "setGsapTween", animationId: firstAnimId, properties: { ease: "power3.inOut" }, }); if (!check.ok) { if (check.code === "E_NO_GSAP_TIMELINE") { // Parser engine not yet available — show a disabled state or skip console.warn("GSAP timeline not available:", check.message); } return; } comp.dispatch({ type: "setGsapTween", animationId: firstAnimId, properties: { ease: "power3.inOut" } }); ``` Stable error codes returned by `can()`: | Code | Meaning | |------|---------| | `E_TARGET_NOT_FOUND` | The target `HfId` does not exist in the document. | | `E_NO_ROOT` | The document has no root element. | | `E_NO_GSAP_TIMELINE` | Op requires the GSAP parser engine, which is not yet available. | | `E_NO_GSAP_SCRIPT` | The composition has no embedded GSAP script. | --- ## Keyframes For keyframe-based animations, use `addWithKeyframes` and `replaceWithKeyframes`. Both operate on the GSAP CSS-keyframes layer and return the minted animation ID. ### Adding a keyframed tween ```typescript const animId = comp.addWithKeyframes( "#hf-badge", // CSS selector targeting the element 1.0, // timeline position in seconds (number only) 0.8, // duration in seconds [ { percentage: 0, properties: { opacity: 0, scale: 0.8 } }, { percentage: 60, properties: { opacity: 1, scale: 1.05 }, ease: "power2.out" }, { percentage: 100, properties: { scale: 1 } }, ], "power2.inOut", // optional overall ease ); ``` Returns the new animation ID string, or `""` if the op was rejected. ### Replacing an existing keyframed tween ```typescript const newAnimId = comp.replaceWithKeyframes( oldAnimId, "#hf-badge", 1.0, 1.2, [ { percentage: 0, properties: { x: -60, opacity: 0 } }, { percentage: 100, properties: { x: 0, opacity: 1 }, ease: "back.out(1.7)" }, ], ); // newAnimId !== oldAnimId — position-derived IDs renumber after the remove ``` `replaceWithKeyframes` is equivalent to `removeGsapTween` + `addWithKeyframes` in one atomic op. Because position-derived tween IDs renumber after the removal step, the returned ID is always a **new** ID and must not be assumed equal to the input `animationId`. Re-query `element.animationIds` after a replace to get the current set. ### KeyframeSpec fields Position within the tween as a percentage (0–100). CSS / GSAP properties at this keyframe. Per-keyframe ease applied *from* this keyframe to the next. GSAP endpoint flag — when `true`, this keyframe picks up the element's current value automatically. ### Lower-level keyframe and label ops For lower-level operations — individual keyframe mutations (`addGsapKeyframe`, `setGsapKeyframe`, `removeGsapKeyframe`), property removal, arc paths, label insertion, and animation splitting — use `dispatch()` directly with the corresponding `EditOp` types. See the [Edit Operations reference](/sdk/reference/edit-operations) for the full op union. --- Full reference for every op type in the `EditOp` union, including lower-level keyframe and arc ops. `GsapTweenSpec`, `KeyframeSpec`, `ElasticHold`, `ElementTimingSnapshot`, and all related types. Authoring GSAP timelines in composition HTML. Keyframe authoring patterns and best practices.