diff --git a/packages/core/src/runtime/adapters/animejs.ts b/packages/core/src/runtime/adapters/animejs.ts
index 5e4986ad25..2d8f6d9e96 100644
--- a/packages/core/src/runtime/adapters/animejs.ts
+++ b/packages/core/src/runtime/adapters/animejs.ts
@@ -8,14 +8,18 @@ import { swallow } from "../diagnostics";
*
* ## Usage in a composition
*
+ * The v4 global `anime` is a namespace object, not a callable — `anime.animate()`,
+ * `anime.createTimeline()`. v3's `anime({ targets })` form does not exist in v4.
+ * (4.1+ also moved the bundles from `lib/` to `dist/bundles/`.)
+ *
* ```html
- *
+ *
*
* ```
*
- * Timelines work the same way:
+ * Timelines work the same way — note `add(targets, params, position)`:
*
* ```html
*
@@ -37,10 +41,11 @@ import { swallow } from "../diagnostics";
*
* Multiple instances are supported — all are seeked in sync.
*
- * ## Auto-discovery
+ * ## Auto-discovery (v3 only — inert on v4)
*
- * The adapter also checks `anime.running` for active instances
- * (useful for compositions that forget to register manually).
+ * `discover()` checks `anime.running`, which v4 no longer exports, so it always
+ * returns empty against a v4 build. Compositions MUST push every instance onto
+ * `window.__hfAnime` themselves; an unregistered instance is never seeked.
*/
export function createAnimeJsAdapter(): RuntimeDeterministicAdapter {
return {
diff --git a/skills-manifest.json b/skills-manifest.json
index cb7dbe3e27..71cb77d671 100644
--- a/skills-manifest.json
+++ b/skills-manifest.json
@@ -22,7 +22,7 @@
"files": 17
},
"hyperframes-animation": {
- "hash": "5bc2ce098387a547",
+ "hash": "2ce5ca7dbf361e27",
"files": 121
},
"hyperframes-cli": {
@@ -38,7 +38,7 @@
"files": 78
},
"hyperframes-keyframes": {
- "hash": "a568c05c01b27461",
+ "hash": "d00744ff0e669624",
"files": 3
},
"hyperframes-registry": {
diff --git a/skills/hyperframes-animation/adapters/animejs.md b/skills/hyperframes-animation/adapters/animejs.md
index 5d108f94ab..1f1b8f9793 100644
--- a/skills/hyperframes-animation/adapters/animejs.md
+++ b/skills/hyperframes-animation/adapters/animejs.md
@@ -7,28 +7,39 @@ description: Anime.js adapter patterns for HyperFrames. Use when writing Anime.j
HyperFrames can seek Anime.js instances through its `animejs` runtime adapter. The composition owns the animation objects; HyperFrames owns the clock.
+**This page targets v4 (examples pinned to 4.5.0, MIT).** v4 is a hard break from v3 — there is no callable `anime()`, `easing:` is now `ease:`, and ease names lost their `ease` prefix. Writing v3 from memory produces a composition that throws or silently animates nothing.
+
+The repo's own producer fixtures pin `animejs@4.0.2/lib/anime.iife.min.js`, which still resolves — but that build predates `splitText` / `scrambleText` / `createSeededRandom` / `createLayout` used below, and 4.1+ moved the bundles to `dist/bundles/`, so a version bump needs the path changed too.
+
## Contract
- Create animations or timelines synchronously during composition initialization.
- Set `autoplay: false` so Anime.js does not advance on its own clock.
-- Register every returned animation or timeline on `window.__hfAnime`.
+- Register every returned animation or timeline on `window.__hfAnime` — **explicitly. There is no working auto-discovery on v4** (see Avoid).
- Use finite durations and loop counts.
- Avoid callbacks that mutate DOM based on wall-clock time, network state, or unseeded randomness.
-The adapter seeks every registered instance with `instance.seek(timeMs)`, where `timeMs` is HyperFrames time in milliseconds.
+The adapter seeks every registered instance with `instance.seek(timeMs)`, where `timeMs` is HyperFrames time **in milliseconds** (`ctx.time` seconds × 1000). It also calls `pause()` and `play()` on each instance; anything exposing those three methods works, whatever created it.
+
+## Loading v4
+
+```html
+
+
+```
+
+`anime.animate(...)`, `anime.createTimeline(...)`, `anime.utils.*`, `anime.svg.*`, `anime.stagger(...)`. **Calling `anime(...)` is a TypeError** — every v4 build (UMD and IIFE alike) assigns a namespace object to the global, so v3's `anime({ targets })` form cannot work no matter which v4 file you load.
## Basic Pattern
```html
-
```
+Position accepts a number, a label, `"+=250"` / `"-=100"`, `"<"` (previous **end**) and `"<<"` (previous **start**).
+
## Module Builds
-If you use an ES module build, the adapter does not care how the instance was created. It only needs the returned object to expose `seek()`, `pause()`, and preferably `play()`:
+The adapter does not care how the instance was created — only that it exposes `seek()`, `pause()`, and `play()`:
```html
```
+## Determinism
+
+v4 ships `createSeededRandom(seed)` — use it instead of `Math.random()` when a composition needs scatter/jitter, so the same frame renders the same on every pass:
+
+```js
+const rnd = anime.createSeededRandom(1337);
+anime.animate(".dot", { y: () => -40 * rnd(), duration: 800, autoplay: false });
+```
+
+`anime.utils.random()` / `randomPick()` / `shuffle()` are **not** seeded — they break frame-to-frame reproducibility.
+
## Good Uses
- Small SVG and DOM flourishes where Anime.js syntax is compact.
-- Imported Anime.js examples that can be made seek-driven.
+- Free `splitText` / `scrambleText` (Motion puts these behind Motion+; GSAP SplitText is the other free option).
+- `svg.createDrawable` / `svg.morphTo` / `svg.createMotionPath` line-draw and path work.
- Multiple independent micro-animations pushed into the same registry.
Use GSAP for complex scene sequencing unless the user specifically asks for Anime.js. GSAP is still the primary HyperFrames authoring path.
@@ -95,8 +107,11 @@ Use GSAP for complex scene sequencing unless the user specifically asks for Anim
## Avoid
- Leaving `autoplay` at the Anime.js default.
-- Depending on `anime.running` auto-discovery instead of explicit `window.__hfAnime.push(...)`.
-- Infinite loops. Compute a finite repeat count from the composition duration.
+- **Relying on the adapter's `anime.running` auto-discovery — it cannot work on v4.** `running` is not among v4.5.0's exports (verified against the published bundle), so `discover()` returns immediately and any instance you did not `push()` is never seeked. Explicit registration is mandatory, not a nicety.
+- `autoplay: onScroll(...)` — there is no scroll in a headless seek render, so the animation would never advance. Drive it off composition time instead.
+- `waapi.animate()` for anything the adapter must seek — the adapter seeks via `.seek()`, and whether WAAPI-backed instances honor it is **unverified**. Use the JS engine (`animate`) for rendered compositions; `waapi` is an off-main-thread optimization for live pages.
+- `createDraggable`, and any pointer-driven `createAnimatable` loop — input does not exist at render time.
+- Infinite loops. Compute a finite repeat count from the composition duration (v4 `loop` counts **repeats**: `loop: 1` plays twice).
- Building animations in timers, promises, event handlers, or after async asset loads.
## Validation
@@ -105,10 +120,11 @@ After editing a composition that uses Anime.js:
```bash
npx hyperframes lint
-npx hyperframes check
+npx hyperframes validate
```
## Credits And References
- HyperFrames adapter source: `packages/core/src/runtime/adapters/animejs.ts`.
-- Anime.js documentation for `autoplay`, `pause()`, and `seek()`: https://animejs.com/documentation/
+- Anime.js v4 docs: https://animejs.com/documentation/
+- v3 → v4 migration (not on animejs.com): https://github.com/juliangarnier/anime/wiki/Migrating-from-v3-to-v4
diff --git a/skills/hyperframes-keyframes/references/keyframe-patterns.md b/skills/hyperframes-keyframes/references/keyframe-patterns.md
index 3c3211d1c6..5770721d01 100644
--- a/skills/hyperframes-keyframes/references/keyframe-patterns.md
+++ b/skills/hyperframes-keyframes/references/keyframe-patterns.md
@@ -42,8 +42,10 @@ CSS:
Anime.js:
```js
-const animation = anime.timeline({ autoplay: false });
-animation.add({ targets: "" /* derived channels */ });
+const animation = anime.createTimeline({ autoplay: false });
+animation.add("", {
+ /* derived channels */
+});
window.__hfAnime = window.__hfAnime || [];
window.__hfAnime.push(animation);
```