Every SKILL.md already declared the new name — name: frames, frames-cli, frames-core, and so on — but the directories were never moved, so the tree carried frames-* in content and hyperframes-* on disk. Everything that resolves a skill by path missed: the core-skill list, the plugin marketplace pin, and the docs the CLI reads at runtime. Eight tests failed on main because the files they open do not exist. The directories now match what the files say they are, and the guide the claude-design contract reads takes the name that contract already used.
4.1 KiB
name, description
| name | description |
|---|---|
| frames-waapi | Web Animations API adapter patterns for Frames. Use when authoring element.animate() motion, Animation currentTime seeking, document.getAnimations(), KeyframeEffect timing, fill modes, or native browser animations that must render deterministically in Frames. |
Web Animations API for Frames
Frames can seek Web Animations API animations through its waapi runtime adapter. WAAPI is useful when you want native browser keyframes with JavaScript-created timing and no GSAP dependency.
Contract
- Create animations synchronously during composition initialization.
- Use
element.animate(...)with finitedurationanditerations. - Use
fill: "both"so seeked states persist. - Pause animations after creation or let the adapter pause them on first seek.
- Avoid callbacks and promises for render-critical state.
The adapter calls document.getAnimations(), sets each animation's currentTime to Frames time in milliseconds, then pauses it.
Basic Pattern
<div id="orb" class="clip orb" data-start="2" data-duration="3" data-track-index="2"></div>
<script>
const orb = document.getElementById("orb");
const animation = orb.animate(
[
{ transform: "translate3d(-160px, 0, 0) scale(0.8)", opacity: 0 },
{ transform: "translate3d(0, 0, 0) scale(1)", opacity: 1, offset: 0.35 },
{ transform: "translate3d(120px, 0, 0) scale(1.08)", opacity: 1 },
],
{
duration: 3000,
delay: 2000,
easing: "cubic-bezier(0.2, 0, 0, 1)",
fill: "both",
iterations: 1,
},
);
animation.pause();
</script>
Stagger Pattern
document.querySelectorAll(".token").forEach((token, index) => {
const animation = token.animate(
[
{ transform: "translateY(24px)", opacity: 0 },
{ transform: "translateY(0)", opacity: 1 },
],
{
duration: 620,
delay: index * 80,
easing: "cubic-bezier(0.2, 0, 0, 1)",
fill: "both",
iterations: 1,
},
);
animation.pause();
});
Good Uses
- Lightweight DOM motion where CSS keyframes are too rigid and GSAP is unnecessary.
- Generated animations from structured data.
- Simple timelines that can be represented as keyframes, delays, and offsets.
Composition Duration
The render engine needs the composition's total length to know how many frames to capture. GSAP timelines report duration automatically; a WAAPI-only composition has no timeline object, so the runtime infers duration from every animation's effect.getComputedTiming().endTime (offset by when the animation was created relative to composition start). data-duration on the root element is optional as long as every element.animate() call uses finite duration and iterations — which the contract above already requires.
Infinite iterations has no finite endTime, so it can't be auto-inferred — that's one more reason to avoid it (see Avoid below). If you must use it, add data-duration="<seconds>" to the root [data-composition-id] element or npx @hanzo/frames lint will error (root_composition_missing_duration_source).
Avoid
- Infinite
iterations. - Depending on
animation.finishedto mutate render-critical DOM. - Running separate clocks with
requestAnimationFrame, timers, orperformance.now(). - Animating layout properties when transforms and opacity can express the motion.
- Assuming clip-local start time is automatic. WAAPI adapter seeks document-level animation time; model clip offsets with
delayor create the animation on an element whose visibility is controlled by Frames timing.
Validation
After editing a WAAPI composition:
npx @hanzo/frames lint
npx @hanzo/frames check
Credits And References
- Frames adapter source:
packages/core/src/runtime/adapters/waapi.ts. - Duration auto-inference:
packages/core/src/runtime/init.ts(resolveAdapterDurationFloorSeconds),getInferredDurationSecondsin the adapter above. - MDN Web Animations API guide: https://developer.mozilla.org/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API
- MDN
Animation.currentTime: https://developer.mozilla.org/en-US/docs/Web/API/Animation/currentTime