Skip to content

feat(skills): pre-plan persistent-subject choreography (Addition C)#551

Open
vanceingalls wants to merge 1 commit intovance/04-28-content-culturefrom
vance/04-28-persistent-choreography
Open

feat(skills): pre-plan persistent-subject choreography (Addition C)#551
vanceingalls wants to merge 1 commit intovance/04-28-content-culturefrom
vance/04-28-persistent-choreography

Conversation

@vanceingalls
Copy link
Copy Markdown
Collaborator

What

Brief description of the change.

Why

Why is this change needed?

How

How was this implemented? Any notable design decisions?

Test plan

How was this tested?

  • Unit tests added/updated
  • Manual testing performed
  • Documentation updated (if applicable)

User feedback from eval 5 exposed a real R4 failure mode:

- p2 Thread: Maya's card persisted across scenes (good) but often
  landed in positions that didn't fit the scene's content
  hierarchy (bad). Semantic-mismatch.
- p3 Vermeer: painting zoomed to 2.1x in scene 2, blocking the
  right-column metadata the scene subagent had authored. Size-
  collision.

Root cause: expansion identifies the subject, scene subagents
author their scenes INDEPENDENTLY (picking their own layouts),
and the scaffold tweens the subject's position/scale across
transitions as an afterthought. Scene subagents don't know how
big the subject will be in THEIR scene, so they place their
chrome wherever, and then the scaffold's tween scales the subject
up or moves it into regions already filled.

Fix: expansion pre-plans the choreography BEFORE the per-scene
detailed breakdown. Per-scene block specifies:
- position (center x, y)
- scale
- size_envelope (actual on-screen footprint in this scene)
- role (focal / background anchor / data-point / glyph-slot / ...)
- reserved_region (rectangle scene subagent must leave empty)
- scene_must_avoid (short instruction)

Orchestrator (multi-scene.md) passes each scene subagent its
scene's choreography block plus the contract:
- The scaffold owns the subject's DOM + timeline.
- Your scene layout MUST respect the reserved region.
- Design your scene chrome around the element's role in this scene.
- Do NOT animate the persistent subject in your timeline.

Invariants:
- Size envelope reflects the SETTLED state (if the subject scales
  up during the scene, reserve for the larger size).
- Scene-to-scene positions trace a visually-coherent path, not
  leapfrogs.
- Role changes drive reserved-region size.

Branch worktree only. Not synced to installed main skill path.
Copy link
Copy Markdown
Collaborator Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link
Copy Markdown
Collaborator

@jrusso1020 jrusso1020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Staff review

TL;DR: references/multi-scene.md is the strongest piece of this stack — the Scene Fragment Spec (3 markers, ID prefix, prohibited patterns) is exactly the kind of explicit guardrail that converts implicit failure modes into checkable rules. The persistent-subject choreography YAML is a good fix for a real problem (subject scaling up into reserved region collides with content). But there's a runtime claim that doesn't match the codebase, R4 is still undefined, and the "Phase 2b" / "Step 0a" pattern continues the accreted-edit numbering smell.


Blocking

1. @hyperframes/core/assemble doesn't exist. Phase 3's example code:

const { assembleScenes } = await import("@hyperframes/core/assemble");

will throw Cannot find module. I checked packages/core/package.json — the subpath exports are ./lint, ./compiler, ./runtime, ./studio-api, ./text, ./registry. There is no ./assemble, and no assemble* source file under packages/core/src/. Either ship the assembler in this PR (add packages/core/src/assemble/index.ts + the export) and write tests against it, or change Phase 3 to a documented procedure that doesn't depend on a nonexistent module.

2. R4 still not defined. Grepped the cumulative state at the top of the stack — R4 (persistent-element continuity morph) is referenced in #550 and used as the gating condition here ("When R4 applies...") but never has a definition anywhere. If this PR introduces the persistent-overlay rule, define R4 explicitly (one-liner is fine: "R4 — when a named real-world subject persists across 2+ scenes, render it in a shared overlay layer outside .scene containers and migrate it across transitions"). Otherwise readers can't tell when the rule fires.

3. Phase 2b without Phase 2a is the same accreted-edit smell as #549's 0a/0b. Renumber: "Phase 1: Scaffold + Scene subagents" / "Phase 2: Streaming evaluation" / "Phase 3: Assembly" reads cleanly.


Significant

4. 1920×1080 is hard-coded into the choreography YAML. The example uses { x: 1380, y: 540 }, { w: 540, h: 680 }, etc. Hyperframes supports any dimension declared via data-width/data-height (square, 1080×1920, etc.). Either generalize the YAML (percentages, or "relative to the composition's declared dimensions"), or label the example explicitly as "for a 1920×1080 composition; scale to your data-width/data-height."

5. multi-scene.md is 188 lines and has multiple self-contained sub-specs. The Scene Fragment Spec alone is dense and consumed by both the assembler code and the orchestrator. Worth extracting to references/scene-fragment-spec.md so the assembler can link it independently. Trade-off accepted if you'd rather keep one file — but note that 188 lines is at the upper end of "reference loaded just-in-time."

6. Density target is unmotivated. "15+ animated elements? 3 parallax layers?" appears in Phase 2b's content validation as a checkable target with no source or rationale. Where do these numbers come from? Are they enforced anywhere? Either link to the rule's origin (house-style.md? a benchmark?) or drop.

7. Persistent-subject scaffold contract is incomplete. The text says "the scaffold owns the subject's DOM + timeline" and "the scaffold authors the subject's tweens between choreography positions" — but the scaffold-author's instructions don't show how the choreography YAML translates to scaffold tweens (which .to() calls, with what eases, on what timeline). If the scaffold is supposed to consume the YAML, give it an example. If a separate "scaffold scaffolder" handles this, name it.

8. Stacks on #549's design.md schema gap. Scene subagents receive "the design.md (or its values summarized)" — but the schema isn't pinned down in #549, so "summarized" can mean anything.


Smaller things

  • Contrast section wording: "Small text (under 24px) has no large-text exemption" reads as an exception to a rule that wasn't stated. WCAG AA is 4.5:1 for normal text, 3:1 for large text (24px+ regular / 19px+ bold). If the policy is "always 4.5:1, no exceptions" just say that — it's clearer.
  • "Maximum 2 retries per scene — if a scene fails 3 times...": 2 retries = 3 attempts total. Fine, but worth confirming the orchestrator counts the same way (some implementations would call this "3 retries").
  • Visibility kills: tl.set("#sceneN", { visibility: "hidden" }, exitEndTime)tl is referenced before the scaffold's gsap.timeline({ paused: true }) line is shown. Reorder or add a one-line "the scaffold's timeline variable is tl" so the example is self-contained.
  • "Run npx hyperframes lint" / "Run npx hyperframes validate if available": both commands exist in packages/cli/src/commands/ (verified). Drop "if available" on validate.
  • Empty PR template + no test plan, same as #549/#550.

What this PR gets right

  • Scene Fragment Spec is excellent. The explicit prohibited-patterns list (<!DOCTYPE, <script>/</script> tags wrapping the GSAP section, tl.from, gsap.timeline(, bare class names without s{N}- prefix, CSS transform on GSAP-animated elements) is exactly the kind of guardrail that converts past failures into checkable rules. The "Why this prohibition exists" comments inline are the difference between "rule" and "rule that future Claude actually follows."
  • "Who runs this pipeline" section is great defensive design. Explicitly handling the nested-subagent case (no Agent/Task tool available → build serially, note the constraint in your final report) prevents the silent-broken-pipeline failure mode.
  • Persistent-subject contract addresses a real failure: scenes authored without knowing the subject's bounding box at its FINAL state, then the scaffold scales it up into reserved region. The YAML format with position, scale, size_envelope, role, reserved_region, scene_must_avoid is well-thought-out. The Vermeer example with three scenes at 1.0x → 2.1x → 0.85x is concrete enough to copy.
  • Streaming Phase 2b (evaluate as scenes finish, don't batch) matches modern subagent orchestration best practices.

Recommended path

Block on (1) — either ship the assembler module or change Phase 3 to not depend on it. Block on (2) — define R4 inline. Renumber Phase 2b → Phase 2 (3). Generalize the YAML coordinates (4). De-block on (8) once #549 lands. The Scene Fragment Spec, "Who runs this pipeline" section, and choreography YAML format are keepers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants