feat(script): cinematography agents + hook layering + ssr cache fix#10
Merged
feat(script): cinematography agents + hook layering + ssr cache fix#10
Conversation
added 2 commits
April 25, 2026 22:12
Three things in one PR — the planner stops being template-only and
starts directing cinematography, scenes get a much richer kit of
visual presets to draw on, and a cheap second-pass critic protects
the cold-open.
Asset library:
- Four new atmosphere presets bringing the registry from 5 → 9:
- radial-pulse: concentric ring pulses from canvas centre. Magnetises
the eye for centred hero elements (hook-statreveal).
- cosmic-dust: sparse twinkling stars + two drifting halos. Cosmic
scale feel for hooks/outros.
- geometric-grid: drifting + pulsing isometric grid lines.
Engineering aesthetic for chart-scene and comparison.
- flow-lines: wavy horizontal SVG paths drifting across the canvas.
Audio-waveform vibe for quote scenes and time-series charts.
- New icons/ registry — 20 hand-drawn 24x24 stroke SVGs (lock, network,
bolt, dollar, globe, target, shield, etc). Pure geometric primitives,
no third-party paths. Renders at any size, picks up token colours via
currentColor.
- concept-callout items can now carry an icon that REPLACES the number
badge: { text, icon } per item, mixed with plain strings allowed.
Backwards-compatible with existing scripts that pass plain strings.
Slice 8 — planner cinematography:
- New "Cinematography" section in playbook teaches the AI when to pick
each atmosphere preset, which transition fits which moment, and
which icon belongs on which list item.
- Planner tool schema gains optional background and transition fields
per scene, both as enums of registered ids. Unknown values fall back
to defaults so a hallucination can't break assembly.
- After the first planner pass, schema validation walks every scene
and flags missing required props or chart-scene without chart.type /
chart.props matching the chart's required fields. Issues are sent
back as a corrective system prompt for ONE retry — turns ~90% first-
pass success into ~99% at the cost of one extra round-trip on the
failing case. Lingering issues land in meta.warnings so the UI can
surface them.
Slice 9 — hook composer pass:
- New improveHook(script, opts) that critiques s01 against the hook
quality checklist and either keeps it or proposes a swap with a
stronger sentence later in the script. Cheap (~1k input + 200 output
tokens, ~$0.01/video on Sonnet 4.6).
- Verbatim fidelity skips by contract — strict mode never swaps.
Refine and split-merge run the critic.
- Wired into POST /projects/:id/script/plan as an optional second pass,
default on. Body flag improveHook=false skips. Decision and reasoning
surface in meta.warnings.
- Failures are non-fatal: a failed critic call returns the original
script with a reasoning string instead of bubbling.
Verified: assembled the existing my-first-video with explicit overrides
to props.background = radial-pulse / cosmic-dust / geometric-grid /
flow-lines on different scenes. All four new presets reach the
assembler and render correctly. Concept-callout with mixed string and
{text, icon} items renders icon SVGs inside badges where set, plain
two-digit numbers elsewhere.
Five things in one PR — addresses the regressions and missing pieces the user hit when trying to actually use the framework end-to-end. Hook quality (the user's #1 concern): - Playbook hook section rewritten around the four-layer rubric: STAKE / DATA / CLAIM / WHY. A bare claim is a press release, not a hook. Per-template recipes show which prop carries each layer for hook-bigtext, hook-statreveal, and chart-scene-as-opener. - New optional `subtext` prop on hook-bigtext renders one short line below the title with an accent left-rule, fading in after the letter cascade. Designed for the WHY context the user asked for. - Hook quality checklist expanded to six items including "name the four layers in the reasoning, or the hook is incomplete". - Output section reminds the planner about the new prop. Target duration removed: - Total video length follows the script's natural read time. Removing the target made the planner stop padding/truncating to hit a number; per-scene durationHint still controls visual rhythm. - Studio "Target (s)" input deleted from ScriptTab. - Planner's user-message no longer includes "Target overall duration" constraint; PlanOptions.targetDurationSeconds kept as @deprecated for back-compat with older API clients. SSR module cache invalidation (the silent root cause behind "atmospheres gone after Generate"): - Studio's Vite plugin captured the studio-api module reference once at process start and never invalidated. Source edits to assemble.ts / planner.ts / playbook.ts didn't take effect until the dev server was restarted, which made every PR look broken until restart. - New apiInvalidatedSince() walks the SSR module graph for the studio-api entry; if any transitive dep's lastInvalidationTimestamp is newer than when we built _api, drop the cache so the next request rebuilds with fresh bindings. "Use the assets" doc: - New playbook section: defaults are a floor, not a ceiling. At least 3 of every ~12 scenes should override background or transition with a non-default that earns its place in the reasoning. Concept-callout with 2+ items that map cleanly to the icon library should USE the icons. A great plan reads like a director making choices.
This was referenced Apr 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR fixes five things in one bundle. Two are missing pieces from earlier PRs that didn't actually land on main, three are user-flagged regressions/UX issues that surfaced when running the framework end-to-end on a real project.
1. Cinematography agents + asset library (re-PR of #9)
PR #9 was merged into the wrong base (PR #7's branch instead of main), so its content never reached main. Re-applied here.
radial-pulse,cosmic-dust,geometric-grid,flow-linesconcept-calloutitems support{text, icon}— icon replaces the number badgebackgroundandtransitionfields per scene as enumschart.type, sends a corrective system prompt for one retryimproveHook): cheap second-agent critic that scores s01 against the hook quality checklist and proposes a swap with a stronger sentence later in the script2. Hook layering — stake / data / claim / why
The user's primary feedback: "the hook should have information, data, why, what's at stake."
subtextprop onhook-bigtextrenders one short line below the title with an accent left-rule, fading in after the letter cascade — for the WHY context3. Target duration removed
The user: "having target seconds is wrong. time is based on script."
PlanOptions.targetDurationSecondskept as@deprecatedfor back-compat with older API clients4. SSR module cache invalidation
The silent root cause behind the user's "all the gradient effects are gone after I ran generate again".
studio-apimodule reference once at process start and never invalidated. Edits toassemble.ts/planner.ts/playbook.tsdidn't take effect until restart, which made every PR look broken until someone manually restartedbun run devapiInvalidatedSince()walks the SSR module graph; if any transitive dep'slastInvalidationTimestampis newer than when_apiwas built, the cache drops and the next request rebuilds with fresh bindings5. "Use the assets" doc
The user: "how to use these assets?"
Test plan
#0a0a0a, accent#7c3aed, accent2#06b6d4on the my-first-video project (HyperSpeedrun "Data Drift meets Swiss Pulse" aesthetic)Stack note
The previous "all PRs merged but main is missing #9" issue happened because GitHub's PR-stack base interaction merged #9 into PR #7's branch, not into main. This PR cherry-picks #9's commit fresh against main + adds the new fixes on top. Single PR, single base — no stacking.