docs: say one paused ROOT timeline, not "timelines must be paused"

`skills/hyperframes-core/SKILL.md` has always been right: "Each composition
registers exactly one gsap.timeline({ paused: true })... Don't manually nest
sub-timelines into the host."

The four compressed copies dropped both halves and said only "GSAP timelines
must be paused and registered on window.__timelines". Plural, with no cap and
no warning against nesting. An author following that writes a paused timeline
per scene and combines them, which is precisely the shape that renders black:
a paused child never advances when the root is seeked, so every frame is the
t=0 state, and lint, check and validate all pass because none looks at pixels.

This is the drift the skill-catalog rule exists to prevent — a compressed copy
asserting something the skill does not.

The runtime now repairs this shape (#3427), so nobody is stuck. This closes the
door on authoring it in the first place.

Both template files kept byte-identical, as required.
This commit is contained in:
Miguel Angel Simon Sierra
2026-08-22 11:59:52 -04:00
parent 59a69a145b
commit d70f00f707
4 changed files with 12 additions and 4 deletions
+1 -1
View File
@@ -80,7 +80,7 @@ skills/ → AI agent skill definitions
- **Package manager**: bun (not pnpm, not npm for workspace operations)
- **Commit format**: Conventional commits (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`)
- **TypeScript**: Avoid `any` and `as T` assertions. Prefer type guards and narrowing.
- **Compositions**: HTML files with `data-*` attributes. Clips need `class="clip"`. GSAP timelines must be paused and registered on `window.__timelines`.
- **Compositions**: HTML files with `data-*` attributes. Clips need `class="clip"`. Each composition registers **exactly one** paused GSAP timeline on `window.__timelines`. Don't nest your own paused sub-timelines into it: a paused child never advances when the root is seeked, so the render comes out blank.
- **Frame Adapters**: Animation runtimes plug in via the seek-by-frame adapter pattern. GSAP is the primary adapter.
- **Deterministic rendering**: No `Date.now()`, no unseeded `Math.random()`, no render-time network fetches.
+1 -1
View File
@@ -111,7 +111,7 @@ skills/ → AI agent skill definitions
- **Package manager**: bun (not pnpm, not npm for workspace operations)
- **Commit format**: Conventional commits (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`)
- **TypeScript**: Avoid `any` and `as T` assertions. Prefer type guards and narrowing.
- **Compositions**: HTML files with `data-*` attributes. Clips need `class="clip"`. GSAP timelines must be paused and registered on `window.__timelines`.
- **Compositions**: HTML files with `data-*` attributes. Clips need `class="clip"`. Each composition registers **exactly one** paused GSAP timeline on `window.__timelines`. Don't nest your own paused sub-timelines into it: a paused child never advances when the root is seeked, so the render comes out blank.
- **Frame Adapters**: Animation runtimes plug in via the seek-by-frame adapter pattern. GSAP is the primary adapter.
- **Deterministic rendering**: No `Date.now()`, no unseeded `Math.random()`, no render-time network fetches.
+5 -1
View File
@@ -90,11 +90,15 @@ Fix all errors before presenting the result. Warnings should be reviewed before
1. Every timed element needs `data-start`, `data-duration`, and `data-track-index`
2. Elements with timing **MUST** have `class="clip"` — the framework uses this for visibility control
3. Timelines must be paused and registered on `window.__timelines`:
3. Register **exactly one** paused timeline per composition on `window.__timelines`:
```js
window.__timelines = window.__timelines || {};
window.__timelines["composition-id"] = gsap.timeline({ paused: true });
```
Only that registered timeline is paused. Don't build scene timelines as
`gsap.timeline({ paused: true })` and `.add()` them into it — a paused child
never advances when the root is seeked, so every frame renders the t=0 state
and the video comes out blank with no warning from lint, check or validate.
4. Videos use `muted` with a separate `<audio>` element for the audio track
5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches
+5 -1
View File
@@ -90,11 +90,15 @@ Fix all errors before presenting the result. Warnings should be reviewed before
1. Every timed element needs `data-start`, `data-duration`, and `data-track-index`
2. Elements with timing **MUST** have `class="clip"` — the framework uses this for visibility control
3. Timelines must be paused and registered on `window.__timelines`:
3. Register **exactly one** paused timeline per composition on `window.__timelines`:
```js
window.__timelines = window.__timelines || {};
window.__timelines["composition-id"] = gsap.timeline({ paused: true });
```
Only that registered timeline is paused. Don't build scene timelines as
`gsap.timeline({ paused: true })` and `.add()` them into it — a paused child
never advances when the root is seeked, so every frame renders the t=0 state
and the video comes out blank with no warning from lint, check or validate.
4. Videos use `muted` with a separate `<audio>` element for the audio track
5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches