agents/openai.yaml
interface:
display_name: "AI UI UX Motion Engine"
short_description: "Build substantial cinematic journeys without shortcuts"
default_prompt: "Use $ai-ui-ux-motion-engine to lock the requested flagship intent, reject camera-only substitutes, prefer programmatic media generation, and require separate creative and technical acceptance."
assets/cinematic-brief.example.json
{
"project": "Private product-film proof",
"truthMode": "identity-locked",
"intent": {
"requestSummary": "Create a full-screen scroll-controlled homepage flagship with an intricate product journey rather than a simple camera move",
"impact": "flagship",
"fullScreen": true,
"scrollControlled": true,
"signatureMoment": "the product opens and its eight rigid modules separate into a readable engineered arrangement",
"progression": [
"establish the real product",
"open and reveal the system",
"separate and inspect the modules",
"resolve to the complete commissioned product"
],
"payoff": "the complete product returns with its existing status lights active",
"requiredEffects": [
"opening",
"exploded-view",
"assembly"
],
"prohibitedSubstitutes": [
"camera-only",
"css-like-parallax",
"generic-orbit",
"rotation-only",
"zoom-only"
],
"requiresMeaningfulStateChange": true,
"requiresUnseenGeometry": true,
"requiresExactMechanics": false
},
"workflow": {
"profile": "lean-scalable",
"accuracyPriority": "accuracy-first",
"targetMinutes": 60,
"escalationMinutes": 75,
"parallelism": "safe-when-supported",
"frameInspection": "automated-overview-dense-on-risk"
},
"experience": {
"placement": "homepage flagship",
"tier": "flagship",
"scrollControlled": true,
"durationSeconds": 12,
"aspectRatio": "16:9",
"resolution": "1280x720",
"frameRate": 24
},
"production": {
"technique": "multi-shot-generation"
},
"sourceCoverage": {
"authorityType": "multi-view",
"supportsUnseenGeometry": true,
"supportsExactMechanics": false,
"limitations": [
"the exploded arrangement is an identity-locked visualisation, not assembly evidence"
]
},
"provider": {
"name": "approved image-to-video provider",
"requiredCapability": "multi-reference multi-shot video",
"connected": true,
"termsApproved": true,
"accessMethod": "cli",
"programmaticPreflightComplete": true,
"creditsApproved": 90,
"attemptLimit": 1
},
"identity": {
"authorityReference": "01-product-exterior.png",
"description": "one exact unbranded dark-metal technical product",
"immutableDetails": [
"overall proportions",
"panel and vent geometry",
"fasteners and ports",
"material and colour"
],
"exactCounts": [
{
"name": "removable modules",
"count": 8
}
]
},
"references": [
{
"file": "01-product-exterior.png",
"purpose": "identity authority"
},
{
"file": "02-product-open.png",
"purpose": "open-state constraint"
},
{
"file": "03-modules-aligned.png",
"purpose": "count and spacing constraint"
}
],
"look": {
"background": "controlled black engineering studio",
"lighting": "cold-white inspection key with restrained coloured rim",
"camera": "physically stabilised product cinematography"
},
"shots": [
{
"name": "authority",
"purpose": "authority",
"subjectChange": "none",
"startSeconds": 0,
"endSeconds": 2.5,
"reference": "01-product-exterior.png",
"action": "hold the complete product still",
"camera": "slow straight dolly-in",
"endState": "complete exterior with a half-second still hold"
},
{
"name": "access",
"purpose": "transformation",
"subjectChange": "physical",
"startSeconds": 2.5,
"endSeconds": 5,
"reference": "02-product-open.png",
"action": "open one rigid panel on its authorised straight axis",
"camera": "locked camera with a restrained push",
"endState": "stable authorised open state"
},
{
"name": "assembly",
"purpose": "inspection",
"subjectChange": "physical",
"startSeconds": 5,
"endSeconds": 9,
"reference": "03-modules-aligned.png",
"action": "separate all eight rigid modules vertically into an exploded-view arrangement, then assemble them at equal speed",
"camera": "slow straight overhead dolly",
"endState": "exactly eight evenly seated modules with a still hold"
},
{
"name": "resolve",
"purpose": "payoff",
"subjectChange": "visualized-system",
"startSeconds": 9,
"endSeconds": 12,
"reference": "01-product-exterior.png",
"action": "activate only the existing status lights",
"camera": "slow straight pull-back",
"endState": "opening exterior identity with a half-second still hold"
}
],
"forbidden": [
"morphing",
"duplicated or missing parts",
"changed object count or spacing",
"invented text or branding",
"camera shake",
"generated audio"
],
"delivery": {
"silent": true,
"scrollMaster": "all-intra-video",
"fallback": "approved poster"
}
}
assets/cinematic-scroll-controller.js
export function attachCinematicScroll(root) {
const video = root.querySelector("[data-cinematic-video]");
if (!video) return () => {};
const reduceMotion = matchMedia("(prefers-reduced-motion: reduce)");
const saveData = navigator.connection?.saveData === true;
let frame = 0;
let pendingProgress = 0;
let pendingTime = 0;
let seekInFlight = false;
let hasDecodedFrame = false;
let active = false;
const revealDecodedFrame = () => {
if (hasDecodedFrame || video.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) return;
hasDecodedFrame = true;
root.dataset.cinematicReady = "true";
};
const seekLatest = () => {
if (
!active ||
seekInFlight ||
!Number.isFinite(video.duration) ||
video.duration <= 0
) {
return;
}
const threshold = 1 / 30;
if (Math.abs(video.currentTime - pendingTime) <= threshold) return;
seekInFlight = true;
video.currentTime = pendingTime;
};
const update = () => {
frame = 0;
if (!active || !video.duration || reduceMotion.matches || saveData) return;
const maxScroll = Math.max(1, root.offsetHeight - innerHeight);
const top = root.getBoundingClientRect().top;
pendingProgress = Math.min(1, Math.max(0, -top / maxScroll));
pendingTime = pendingProgress * Math.max(0, video.duration - 0.001);
seekLatest();
root.style.setProperty("--cinematic-progress", String(pendingProgress));
};
const requestUpdate = () => {
if (!frame) frame = requestAnimationFrame(update);
};
const handleSeeked = () => {
seekInFlight = false;
revealDecodedFrame();
seekLatest();
};
const handleError = () => {
root.dataset.cinematicFailed = "true";
};
const observer = new IntersectionObserver(([entry]) => {
active = entry.isIntersecting;
if (entry.isIntersecting) {
addEventListener("scroll", requestUpdate, { passive: true });
addEventListener("resize", requestUpdate, { passive: true });
requestUpdate();
} else {
removeEventListener("scroll", requestUpdate);
removeEventListener("resize", requestUpdate);
}
});
video.pause();
video.addEventListener("loadedmetadata", requestUpdate);
video.addEventListener("loadeddata", revealDecodedFrame);
video.addEventListener("canplay", revealDecodedFrame);
video.addEventListener("seeked", handleSeeked);
video.addEventListener("error", handleError);
reduceMotion.addEventListener?.("change", requestUpdate);
observer.observe(root);
return () => {
observer.disconnect();
removeEventListener("scroll", requestUpdate);
removeEventListener("resize", requestUpdate);
video.removeEventListener("loadedmetadata", requestUpdate);
video.removeEventListener("loadeddata", revealDecodedFrame);
video.removeEventListener("canplay", revealDecodedFrame);
video.removeEventListener("seeked", handleSeeked);
video.removeEventListener("error", handleError);
reduceMotion.removeEventListener?.("change", requestUpdate);
if (frame) cancelAnimationFrame(frame);
};
}
assets/creative-acceptance-placeholder.txt
Regression fixture placeholder. Creative validation checks workflow evidence and file presence; technical media validation is handled separately by validate-scroll-media.mjs.
assets/creative-acceptance.example.json
{
"brief": "cinematic-brief.example.json",
"asset": "creative-acceptance-placeholder.txt",
"decision": "approved",
"ownerApproved": true,
"creative": {
"openingMatches": true,
"progressionMatches": true,
"payoffMatches": true,
"meaningfulStateChange": true,
"cameraOnlySubstitute": false,
"tierSubstantial": true,
"identityContinuity": true,
"truthfulnessDisclosed": true,
"observedEffects": [
"opening",
"exploded-view",
"assembly"
],
"missingMoments": [],
"evidenceNotes": "Saved fixture representing an owner-approved flagship with a visible opening, engineered separation, inspection progression and resolved payoff."
}
}
assets/regressions/camera-only-homepage-failure.json
{
"project": "Regression: camera-only homepage downgrade",
"truthMode": "evidence-accurate",
"intent": {
"requestSummary": "Create a full-screen beautiful scroll video with a meaningful intricate journey and burst-style impact",
"impact": "flagship",
"fullScreen": true,
"scrollControlled": true,
"signatureMoment": "the real product progresses through a detailed commissioning journey",
"progression": [
"specified",
"tested",
"documented",
"handed over"
],
"payoff": "the fully commissioned product is handed over",
"requiredEffects": [
"burst"
],
"prohibitedSubstitutes": [
"camera-only",
"css-like-parallax",
"generic-orbit",
"rotation-only",
"zoom-only"
],
"requiresMeaningfulStateChange": true,
"requiresUnseenGeometry": true,
"requiresExactMechanics": false
},
"workflow": {
"profile": "lean-scalable",
"accuracyPriority": "accuracy-first",
"targetMinutes": 30,
"escalationMinutes": 60,
"parallelism": "off",
"frameInspection": "automated-overview-dense-on-risk"
},
"experience": {
"placement": "homepage lower-page full-screen commissioning chapter",
"tier": "supporting",
"scrollControlled": true,
"durationSeconds": 5,
"aspectRatio": "16:9",
"resolution": "4K",
"frameRate": 24
},
"production": {
"technique": "multi-shot-generation"
},
"sourceCoverage": {
"authorityType": "single-view",
"supportsUnseenGeometry": false,
"supportsExactMechanics": false,
"limitations": [
"only one straight-on rear photograph exists"
]
},
"provider": {
"name": "Higgsfield",
"requiredCapability": "single-reference image-to-video",
"connected": true,
"termsApproved": true,
"accessMethod": "browser",
"programmaticPreflightComplete": false,
"browserFallbackReason": "",
"creditsApproved": 150,
"attemptLimit": 1
},
"identity": {
"authorityReference": "server-rear.png",
"description": "one exact real rack server rear view",
"immutableDetails": [
"chassis",
"ports",
"cables"
],
"exactCounts": [
{
"name": "power modules",
"count": 4
}
]
},
"references": [
{
"file": "server-rear.png",
"purpose": "single rear identity authority"
}
],
"look": {
"background": "black",
"lighting": "retain source",
"camera": "slow lateral dolly"
},
"shots": [
{
"name": "inspection",
"purpose": "authority",
"subjectChange": "none",
"startSeconds": 0,
"endSeconds": 5,
"reference": "server-rear.png",
"action": "hold the product completely still",
"camera": "slow lateral dolly to the right",
"endState": "the same static rear view"
}
],
"forbidden": [
"morphing",
"moving components",
"invented geometry"
],
"delivery": {
"silent": true,
"scrollMaster": "all-intra-video",
"fallback": "exact first-frame poster"
}
}
references/accessibility-performance.md
# Accessibility, responsive and performance gates
## Motion safety
- Honour `prefers-reduced-motion`.
- Provide pause/stop controls for non-essential motion that runs longer than five seconds.
- Avoid flashes, rapid scale pulses and large unexpected viewport movement.
- Keep focus visible and stationary enough to follow.
- Never require drag, hover or precise pointer movement as the only path.
- Do not animate error messages away before they can be read.
## Keyboard and semantics
- Use native links, buttons, disclosures and form controls.
- Preserve logical DOM and focus order through visual rearrangement.
- Label icon-only controls.
- Announce carousel/card position only when it changes through user action.
- Test at 200% zoom and with keyboard only.
## Responsive gates
Use the project’s required viewports. If none exist, check at least:
- 360 × 800;
- 768 × 1024;
- 1440 × 900.
Check landscape mobile, long unbroken text, enlarged text and coarse pointer input when relevant.
## Performance budgets
Use the project budget when present. Otherwise:
- avoid adding a client framework to a static page;
- keep route JavaScript proportional to interaction value;
- lazy-load below-fold media;
- preload only the single strongest LCP candidate;
- keep video out of the critical path unless the hero requires it;
- measure rather than claim Core Web Vitals.
## Manual evidence
Automated tools do not prove usability or WCAG conformance. Record:
- keyboard path;
- focus behaviour;
- reduced-motion result;
- touch/drag alternative;
- representative mobile and desktop screenshots;
- console errors;
- any checks not run.
references/cinematic-case-study.md
# Cinematic production lessons
This case study records reusable evidence from an identity-locked technical
product film. It is not a provider guarantee.
## What failed
- Crossfading stills and CSS zooms did not create a cinematic product journey.
- A coherent orbit was visually stable but lacked explanatory progression.
- Short generated transformations invented internal hardware.
- An eight-part installation clip rotated, reshaped and respaced rigid parts.
- A five-second lid action was usable source material but too slight for a
flagship hero.
- An edit made from individually plausible clips still felt discontinuous.
- Ordinary long-GOP H.264 showed visible jitter when scrubbed directly.
- A short-GOP crossfade montage still exposed stale or poster-like frames under
rapid seeking; normal playback and settled checkpoints had hidden the fault.
- A separately selected poster had the right dimensions but a tighter crop, so
the product visibly changed scale when the first video frame replaced it.
## What worked
- One identity-authority exterior plus ordered shot-specific references.
- A clearly timed multi-shot film with hard cuts and immutable count/geometry
instructions.
- One authorised paid attempt on a model capable of multi-reference,
multi-shot generation.
- Dense frame inspection around the most mechanically difficult movement.
- Honest acceptance of a missing requested shot rather than claiming parity.
- A silent all-intra H.264 derivative for direct seeking.
- A poster generated from the exact shipping derivative and machine-compared
with its first decoded frame before browser integration.
- A seek-serialising controller that retained only the newest target and
latched the decoded video visible instead of re-exposing the poster.
- An isolated private route, six sampled scroll positions and responsive,
reduced-motion validation before any public integration.
- Adversarial full-speed forward, reverse and direction-change tests with zero
poster exposure.
## General lesson
Start with the film and its truth constraints. Prove the signature experience
privately, then build the page around the approved asset. Supporting shots
should remain short and single-action. Reuse one flagship film across several
chapters before commissioning additional flagship films.
Treat a scrubber as an adversarial random-access system, not as ordinary video
playback. Validate the exact shipping bytes, serialize seeks and fail over to a
canvas sequence or poster when the stress gate does not pass. Matching width
and height do not prove a seamless handoff: validate first-frame similarity and
identical browser geometry too.
references/cinematic-intake.md
# Cinematic intake and stop rules
Use this gate before page implementation whenever the requested impact depends
on photographic camera movement, product transformation, burst/exploded motion
or scroll-controlled film.
## Ask only what is missing
1. **Target:** Which page areas need a flagship sequence, a supporting shot or
code-native motion?
2. **Reference:** What should the visitor see happen? Use an attached example,
storyboard or short scene list. For a video, inspect keyframes, transcript,
prompt pack and description links rather than relying on a summary.
3. **Truth mode:** May the media be illustrative, must one concept identity stay
stable, or must every visible product detail be evidence-accurate?
4. **Source:** Which photographs, approved keyframes, CAD renders or existing
clips are authoritative?
5. **Provider:** Is a capable image/video provider connected and signed in?
6. **Authority:** What credit cap and maximum attempts are approved? Has the
user authorised uploads and provider terms?
7. **Delivery:** Which browsers/devices matter, and is a static mobile or
reduced-motion fallback acceptable?
Do not burden the user with implementation choices that the skill can make.
## Immediate response contract
If provider access, source assets or authority are missing, say:
> The requested effect needs pre-rendered cinematic motion; CSS alone cannot
> produce the changing camera view or product mechanics. I need the accuracy
> level, source references, required scenes/placements, media-provider access
> and a credit cap. I will first make one private proof and will not alter the
> page or substitute basic image reveals until it passes.
Continue independently when these answers already exist.
Keep the request to five decisions: accuracy target, source readiness,
provider/spend authority, desired placements and delivery/time budget. Do not
ask the user to choose implementation mechanics.
“First time” means the correct media route, questions, proof and stop rules are
used from the beginning. Generated video remains probabilistic.
## Accuracy-first routing
Use the fastest route that can meet the stated accuracy. For real products with
authoritative sources, default to evidence-accurate. Never substitute an
illustrative spectacular result silently. State before generation when exact
mechanics require CAD, compositing or real footage.
Use these target timeboxes:
- 15–30 minutes: private proof with ready sources and provider;
- 30–60 minutes: approved flagship plus scroll delivery;
- 5–10 minutes: derivative or supporting integration;
- 75–120 minutes: only for new/inconsistent sources, evidence-critical
mechanics, CAD or compositing.
If a target is exceeded, report why and obtain approval before continuing.
## Three production tiers
### Flagship
- Use for the homepage or a key product-family journey.
- Usually 10–15 seconds with an authored beginning, progression and payoff.
- Treat full-screen, homepage, signature, intricate, burst, exploded and
immersive scroll requests as flagship. Do not downgrade them to supporting
merely because only one source image or a cheaper model is available.
- Use a provider/model that supports the necessary reference count, duration
and multi-shot control.
- Allow one paid attempt and at most one explicitly approved retry.
- Reuse chapters of one approved film before generating more flagship films.
### Supporting cinematic shot
- Use for macros, controlled camera pushes, cooling, connector detail,
power-on or one mechanically simple action.
- Keep one action, one camera instruction and one or two consistent references.
- Usually 3–5 seconds.
- Use lower-cost or unlimited generation only when its result passes QC.
### Code-native motion
- Use CSS, SVG, canvas or an existing motion library for diagrams, airflow,
data paths, masks, typography and interface transitions.
- Do not spend generation credits when photographic state change is unnecessary.
## Truth-mode routing
### Illustrative
Permit creative transformation but still reject visible defects, unwanted text
and incoherent motion.
### Identity-locked
Use one identity-authority frame and keep proportions, material, lighting and
recognisable features stable. Reject identity drift.
### Evidence-accurate
Record immutable counts, geometry, labels, ports and permitted mechanical axes.
Use consistent photography, CAD or approved keyframes. If the generator cannot
hold these details after the approved attempts, simplify the motion or route to
CAD/compositing/real footage. Never prompt harder indefinitely.
## Proof-before-page rule
The first deliverable is:
1. the validated cinematic brief with the user's intent, progression, payoff,
source coverage and prohibited substitutes recorded;
2. the prepared reference pack;
3. one generated proof;
4. automated technical checks, an overview contact sheet and risk-led dense QC;
5. an isolated scroll prototype with poster and reduced-motion fallback.
Run the semantic brief regression gate before upload or spend:
```bash
node scripts/validate-cinematic-brief.mjs cinematic-brief.json --check-files
```
After generation, run `validate-creative-acceptance.mjs --stage review`.
Technical media validation is a separate gate and cannot prove creative
success.
Do not redesign, publish or populate multiple routes until the user approves
that proof.
## Rejection and stop rules
Reject without trying to hide:
- changing product identity, count, spacing, ports or labels;
- rotating, bending, merging, duplicating or disappearing rigid parts;
- implausible insertion axes or clipping;
- texture crawl, false seams, invented branding or unreadable pseudo-text;
- a camera move that replaces the requested product story;
- a clip too short or slight to fulfil its assigned chapter;
- a collection of unrelated shots presented as one continuous journey;
- visible scrub jitter or incorrect reverse/forward mapping.
After the attempt cap, report the evidence and recommend one bounded change:
simpler action, better references, stronger model, CAD/compositing/filming, or
an explicitly illustrative concept.
references/cinematic-prompts.md
# Cinematic prompt contracts
Generate prompts from a validated cinematic brief with:
```bash
node scripts/render-cinematic-prompt.mjs <brief.json> --mode flagship
```
Use `--mode single` for one supporting action and `--mode illustrative` for a
creative transformation. Provider upload tokens may replace reference names
after the files are attached.
## Prompt-writing rules
- Give one reference the role of identity authority.
- State immutable geometry and exact counts positively before exclusions.
- Use one physically legible action per supporting clip.
- For a flagship film, use explicit shot boundaries, durations and hard cuts.
- Specify permitted camera movement separately from object movement.
- End every mechanical shot with a short still hold for QC and scroll cues.
- Keep generated audio off and put readable text in the DOM.
- Do not assume a longer negative prompt can repair inconsistent references.
## Exact single-action contract
```text
Create a silent premium product-engineering shot of the exact subject in
[IDENTITY REFERENCE].
IDENTITY LOCK
Preserve [IMMUTABLE DETAILS AND COUNTS]. Rigid objects remain rigid and retain
their size, shape, order and spacing.
ACTION
Perform only [ONE ACTION] along [PERMITTED PHYSICAL AXIS]. Begin at [START
STATE], finish at [END STATE], then hold completely still for [HOLD].
CAMERA AND LIGHT
Use only [ONE CAMERA MOVE] with [LENS/FRAMING]. Preserve [LIGHT/BACKGROUND].
REJECTED CHANGES
No morphing, rotation unless explicitly requested, duplication, disappearing
parts, clipping, altered geometry, invented text, logos, labels, people,
hands, tools, particles, smoke, holograms, camera shake or generated audio.
DELIVERY
[DURATION], [ASPECT], [RESOLUTION], clean first and final frames.
```
## Exact multi-shot flagship contract
```text
Create one silent [DURATION] premium product film with [SHOT COUNT] distinct
hard-cut shots. Every reference depicts the same product. [IDENTITY REFERENCE]
is the authority for identity; other references constrain only their named
shots.
SUBJECT AND CONTINUITY LOCK
Preserve [IMMUTABLE DETAILS]. Exactly [COUNTS] remain present in the same order
and spacing. Rigid parts never bend, stretch, merge, duplicate, disappear,
change design or trade places. Mechanical motion occurs only on the stated
physical axes.
SETTING AND LIGHT
[BACKGROUND, MATERIAL, KEY LIGHT, RIM LIGHT, COLOUR GRADE]. Keep these
continuous across every shot.
SHOT 1 — [NAME] — [START-END]
[REFERENCE]. [START STATE]. [ONE ACTION]. [CAMERA]. [END STATE AND STILL HOLD].
[REPEAT ONE BLOCK PER SHOT]
EDITING
Use only the stated hard cuts. No morphs, dissolves, orbit, turntable, digital
zoom, handheld shake, jitter, texture crawl, flicker or motion smear.
EXCLUSIONS
[PROJECT-SPECIFIC EXCLUSIONS]. No added or missing parts, invented seams,
labels, logos, watermarks, people, hands, tools, loose cables, sparks, smoke,
particles, holograms or generated audio.
DELIVERY
[ASPECT], [RESOLUTION], [FRAME RATE], silent, stable first frame and final
[HOLD] still hold.
```
## Illustrative burst/exploded-view contract
```text
Create a silent cinematic exploded-view sequence using [REFERENCE] as the
identity anchor. The complete subject separates into [NAMED GROUPS] along
clean radial or linear paths, pauses in a readable layered arrangement, then
returns exactly to the opening silhouette. Keep every group recognisable and
preserve the total part count. Use [CAMERA MOVE], [LIGHT] and [BACKGROUND].
No liquid morphing, random fragments, duplicate parts, text, logos, people,
camera shake or generated audio. End on a clean still frame.
```
This route permits stylised mechanics. Do not use it to imply an exact real
product assembly unless every visible state is independently verified.
For a reference-style scroll sequence, use the same approved anchor separately
for an orbit/dolly prompt, the burst/exploded prompt and a macro/detail prompt.
Do not ask one generation to perform all three. Reverse the accepted separation
clip for reassembly only after checking every reversed frame.
## Prompt failure diagnosis
- Identity drift: improve or reduce references; do not add adjectives.
- Incorrect count: make the count visible in both start/end references and
simplify occlusion.
- Mechanical morphing: split the action into a separate short clip or use CAD.
- Missing shot: reduce shot count or accept and disclose the omission; never
claim it appeared.
- Boring result: improve shot design, framing and payoff—not CSS decoration.
references/framework-recipes.md
# Framework recipes
## Astro and static HTML
- Preserve server/static rendering and content collections.
- Keep crawlable content and primary navigation in HTML.
- Use CSS and small module scripts before adding a client framework island.
- Scope scripts to a component data attribute and clean up observers/listeners.
- Use `astro:assets` or the project’s image component.
- Do not add React solely to implement motion.
- For a generated product scrubber, server-render the poster, copy and actions,
then attach one data-attribute-scoped video or canvas controller. Read
`generated-product-scrubber.md`.
## React and Next.js
- Keep hooks at component top level.
- Isolate browser-only motion in the smallest client component.
- Avoid random values and layout-dependent values during server render.
- Use stable keys and typed interaction data.
- Keep semantic content in the server-rendered tree.
- Test hydration with reduced motion enabled.
- For generated video/frame scrubbing, isolate seeking in the smallest client
component while keeping the poster and commercial content server rendered.
## Vue and Nuxt
- Put browser-only timeline setup in `onMounted` and clean it in `onBeforeUnmount`.
- Prefer template semantics and CSS transitions for ordinary state.
- Keep SSR output deterministic.
## Svelte and SvelteKit
- Use built-in transitions for local state.
- Start observers/timelines in `onMount` and return cleanup.
- Keep actions reusable and destroy listeners.
## Library decision
Reuse an installed motion library when it is healthy and matches the requirement. Before adding one, record:
- effects that native CSS/DOM cannot express cleanly;
- added client bytes and hydration cost;
- reduced-motion behaviour;
- server-rendering compatibility;
- maintenance owner.
Reject the dependency if the case is only “nicer animation.”
references/generated-product-scrubber.md
# Cinematic generated-product scrubber
Use this route when the experience depends on an authored photographic camera
path, product reveal, assembly/disassembly, burst/exploded view, macro inspection
or object state controlled by scrolling.
The deliverable is a pre-rendered film or frame sequence plus semantic DOM
content. It is not real-time 3D.
## Golden path
1. Run the cinematic-intent gate before editing the page.
2. Classify truth mode and production tier.
3. Verify provider capability, access, terms, cost and attempt authority.
4. Record the user's requested signature moment, progression, payoff, required
effects and prohibited substitutes; create and validate the cinematic brief.
5. Prepare one identity authority and only the shot-specific references needed.
6. Render the prompt from the brief; do not improvise a different production
method.
7. Generate one private proof through CLI, MCP or API where available; use
browser control only as a recorded capability-specific fallback.
8. Inspect the overview contact sheet and sample risky transitions densely only
where identity or mechanical drift could occur.
9. Convert accepted media to an all-intra scrub master and frame sequence.
10. Generate the poster from the exact shipping master and validate both
together with `validate-scroll-media.mjs`.
11. Prove forward/backward scroll and rapid direction changes on an isolated
private route.
12. Run the creative-acceptance validator, obtain approval, then rerun it for
integration before changing the page.
13. Reuse the approved film and component across chapters where appropriate.
## Route by truth mode
### Illustrative
The object may transform creatively, but its silhouette and designed visual
identity should remain coherent. Use this for fictional products, abstract
materials, paint/liquid bursts and explicitly conceptual visuals.
### Identity-locked
Use one authority image for the product identity. Other references constrain
individual shots and must not be averaged into a new product. Reject changes to
recognisable proportions, materials, panels, ports or count.
### Evidence-accurate
Use authoritative photography, CAD or approved keyframes. Record exact counts,
geometry, labels, ports, fasteners and permitted axes. If generation cannot
preserve them within the attempt cap, simplify the action or use CAD,
compositing or real footage. Never imply that generated media proves the
delivered product.
## Route by production tier
### Flagship film
- 10–15 seconds is normally sufficient.
- Use an authored progression: authority, access/change, inspection and payoff.
- Choose a model that supports the required multi-reference and multi-shot
controls.
- One paid attempt by default; one additional attempt only with explicit
approval.
- A missing shot is a disclosed exception, not a silent success.
- A rotation, dolly, zoom, parallax or static product with moving camera is
supporting footage, never a substitute for a requested flagship.
### Supporting shot
- 3–5 seconds.
- One action and one camera instruction.
- One or two consistent references.
- Use for cooling, connectors, materials, controlled pushes and simple physical
movement.
- Do not stretch a small action into a flagship hero.
### Code-native motion
Use CSS, SVG, canvas or an existing motion library when the effect explains
data, airflow, state or typography and does not need photographic state change.
## One-anchor burst preset
For a fictional product, abstract material or illustrative reference-style
experience:
1. approve one strong anchor image;
2. reuse that same anchor for each independent clip;
3. generate three simple movements rather than one overloaded film—typically a
controlled orbit/dolly, one exploded or burst action, and one macro/detail
move;
4. keep each clip to one action and one camera instruction;
5. reverse an accepted separation clip for reassembly when that reads cleanly;
6. extract a consistent numbered frame sequence from every accepted segment;
7. preload the opening frames and map the sequence to a pinned canvas;
8. keep chapter text and controls in the DOM.
Do not use this illustrative preset for evidence-accurate mechanics.
## Provider preflight
Before upload or generation, record:
- current provider and model capability;
- authenticated connection and upload availability;
- accepted reference count and ordering;
- duration, ratio, resolution, bitrate and audio controls;
- current displayed cost;
- user authority for uploads, terms and credits;
- raw-download method;
- attempt cap.
Provider interfaces, models and prices change. Verify them live. Do not hard-code
an obsolete model name merely because it worked previously.
## Reference pack
1. Select the identity-authority image.
2. Remove or obtain permission for visible brands and accidental text.
3. Match aspect ratio, orientation, crop, colour and lighting.
4. Ensure different views can plausibly depict one object.
5. Keep exact counts visible and unoccluded where they matter.
6. Order references to follow the shot plan.
7. Give each non-authority reference one named purpose.
8. Reject inconsistent references before generation.
More references do not automatically create more control. Inconsistent
references create averaged or invented geometry.
## Brief and prompt
Copy `assets/cinematic-brief.example.json`, replace the example values, then run:
```bash
node scripts/validate-cinematic-brief.mjs cinematic-brief.json --check-files
node scripts/render-cinematic-prompt.mjs cinematic-brief.json --mode flagship \
> cinematic-prompt.txt
```
Use `--mode single` for a supporting shot and `--mode illustrative` for a burst
or fictional transformation. Read [cinematic-prompts.md](cinematic-prompts.md)
before changing the rendered structure.
## Prompt discipline
- State identity and positive immutable constraints first.
- State exactly one action per supporting clip.
- Use timed shot blocks and hard cuts for a multi-shot film.
- Separate object motion from camera motion.
- Require a clean still hold at useful cue points.
- Keep readable text and labels outside generated pixels.
- Reject a generic orbit when the brief requires a product story.
- Do not add endless exclusions after bad output; diagnose references, action
complexity or model capability.
## Attempt discipline
For each attempt:
1. save provider ID, model/settings, prompt and cost;
2. download the raw result;
3. produce a 30-frame overview sheet;
4. sample difficult mechanical moments densely;
5. decide pass, supporting-only, disclosed exception or reject;
6. do not integrate rejected media.
After the approved cap, change one material condition—references, model,
complexity or technique. Do not keep rewriting synonyms.
## Scrub delivery
Run:
```bash
bash scripts/prepare-scroll-media.sh accepted-film.mp4 ./scroll-media \
--frames 150 --width 1600
```
This produces:
- a silent all-intra H.264 master for responsive seeking;
- a numbered JPEG sequence for exact canvas mapping;
- a poster;
- a contact sheet;
- source metadata.
Before integration run:
```bash
node scripts/validate-scroll-media.mjs \
./scroll-media/scroll-master.mp4 \
--poster ./scroll-media/poster.jpg \
--json ./scroll-media/delivery-validation.json
```
The command must report every decoded frame as an independent keyframe, zero
audio streams, H.264/yuv420p delivery, a fast-start atom order and a file size
inside the explicit page budget. It must also prove matching poster/video aspect
ratio and at least 0.99 structural similarity between the poster and exact
first decoded frame. A filename containing `all-intra`, `scroll` or `master`
is not evidence.
### Use all-intra video when
- the encoded size fits the page budget;
- seeking is smooth in the required browsers;
- the film is the easiest responsive source;
- direct testing proves forward and backward scroll.
Do not scrub an ordinary long-GOP delivery file merely because it plays
normally. Long distances between keyframes can cause jumps.
Do not accept a short-GOP file either. Any P- or B-frame means the shipping
video failed the direct-seek contract, even if manual forward scrolling appears
acceptable once.
### Use a canvas sequence when
- exact frame selection matters;
- video seeking remains unreliable;
- a flagship experience justifies controlled frame requests and memory;
- frames can be sized near their rendered dimensions.
For canvas, show the poster first, fetch ahead in bounded windows, evict decoded
frames outside the active window and retain all labels/actions in the DOM.
## Scroll integration
Use `assets/cinematic-scroll-controller.js` as the framework-neutral baseline.
Adapt it to project conventions rather than rewriting the seek loop casually.
- Use a sticky stage inside a normal document-height wrapper.
- Map bounded wrapper progress to `0..duration`.
- Coalesce seeks with `requestAnimationFrame`.
- Permit only one seek in flight and retain only the newest pending target.
- Latch the video visible after its first `loadeddata`/decoded frame; never
reveal the poster again merely because `readyState` drops during a seek.
- Use the validated first-frame poster in the same CSS box with identical
`object-fit`, `object-position`, transform, filter and mask rules.
- Ignore tiny deltas.
- Pause work off screen.
- Never hijack native scrolling.
- Trigger DOM chapters from the same progress value.
- Test reverse as well as forward scroll.
- Stress at least one full-speed forward pass, one full-speed reverse pass and
three rapid direction changes while recording current time, seeking state,
video visibility and poster exposure.
- Keep the full product inside a protected responsive crop.
For Astro/static, render semantic content and poster server-side and add one
small scoped module. For React/Next, isolate seeking in the smallest client
component and keep the rest server-rendered.
## Scaling across a site
Do not generate a new flagship film for every section.
1. Use one flagship per major journey.
2. Divide it into reusable DOM-labelled chapters.
3. Add short supporting shots only where they explain a different product fact.
4. Use code-native motion for diagrams, typography and interface state.
5. Load one active cinematic asset per viewport.
6. Lazy-load below-fold media and keep posters for mobile, reduced motion and
Save-Data.
## Acceptance gate
Reject if the result is only still-image crossfades, CSS zoom/parallax, an
unrelated background video, an unsynchronised film, a slight single action
mislabelled as a flagship, or a visibly jittery scrub.
Require both:
```bash
node scripts/validate-creative-acceptance.mjs creative-review.json --stage review
node scripts/validate-scroll-media.mjs scroll-master.mp4 --poster poster.jpg
```
Run the creative validator again with `--stage integration` only after the
owner approves the exact proof. Neither command substitutes for the other.
Six correct screenshots at settled positions do not prove the scrubber. Reject
if the video layer ever becomes hidden after first decode, the poster is
exposed during travel, seeks overlap, time settles against an obsolete target,
rapid reverse/forward input leaves a blank or stale stage, or the first decoded
frame changes crop, scale, position, filter or mask from the poster.
Require:
- the requested beginning, progression and payoff;
- continuous identity and required counts/geometry;
- clean cue frames and truthful disclosed exceptions;
- smooth forward/backward progress;
- protected crops at target viewports;
- semantic DOM content and native scrolling;
- poster, reduced-motion, Save-Data, no-JavaScript and media-error fallbacks;
- browser, console, performance and full-project evidence;
- private approval before production integration.
Read [cinematic-case-study.md](cinematic-case-study.md) for failure patterns
and the production choices that proved reliable.
references/media-pipeline.md
# Reference and cinematic media pipeline
## Capture references responsibly
When the user controls or may legally analyse the reference:
1. record the target viewport without browser chrome where possible;
2. use a steady scroll and pause around meaningful triggers;
3. capture pointer, hover, drag, menu and disclosure states separately;
4. note viewport, frame rate, page URL and source status;
5. retain the recording as analysis evidence, not a shipping asset.
Do not reproduce identity-specific copy, logos, illustrations, photography or
source code.
## Extract reference evidence
Run:
```bash
bash scripts/extract-reference-frames.sh <video> <output-directory>
```
Inspect evenly sampled and scene-change frames as a sequence. A still cannot
prove easing, pinning, continuity or input behaviour.
## Prepare generated-media references
Before generation:
- choose one identity authority;
- normalise aspect, orientation, crop, resolution, colour and lighting;
- remove or obtain permission for brands and accidental text;
- confirm every view can depict the same product;
- record immutable counts, geometry and permitted mechanical axes;
- assign one purpose to each supporting reference;
- create a contact sheet and reject inconsistent inputs.
Do not ask a video model to reconcile contradictory stills.
## Generate in bounded tiers
- Flagship: one authored 10–15 second journey using a capable controlled model.
- Supporting: one 3–5 second action from one or two references.
- Code-native: no generated film when CSS/SVG/canvas explains the relationship.
Approve a private signature proof before generating the remaining library.
## Convert accepted media
Run:
```bash
bash scripts/prepare-scroll-media.sh accepted-film.mp4 ./scroll-media
```
The script creates a silent all-intra scrub master, 150 JPEG frames at 1600px
by default, poster, contact sheet, ffprobe metadata and a machine-readable
delivery-validation report. The script fails if its own master is not genuinely
all-intra, silent and fast-start.
Validate any renamed, recompressed or CDN-produced shipping derivative again:
```bash
node scripts/validate-scroll-media.mjs shipping.mp4 \
--poster shipping-poster.jpg \
--json delivery-validation.json
```
Generate the poster from the exact shipping MP4, not a raw source, storyboard
still or separately cropped frame. The validator requires matching aspect ratio
and at least 0.99 SSIM against the decoded first frame. Render poster and video
with identical fit, position, transform, filter and mask rules.
Use all-intra video only after target-browser seeking passes. Use the frame
sequence when exact frame mapping or device reliability requires it. Never
silently fall back to ordinary long-GOP scrubbing after visible jitter.
Normal playback is not a scrub test. A held opening image, crossfade montage or
short-GOP encode can look clean when played from start to finish and still fail
random forward/reverse seeking.
## Quality-control evidence
For every attempt retain:
- provider asset ID, model/settings, prompt and cost;
- raw download and metadata;
- evenly sampled overview contact sheet;
- dense samples around complicated mechanics;
- pass/reject decision and disclosed scope exceptions.
Do not trim around identity or geometry drift and reuse the remainder as if the
whole action passed.
Automate technical validation and create an overview contact sheet by default.
Sample difficult transitions densely. Inspect every frame only after a detected
defect or when the brief explicitly marks the mechanics evidence-critical; do
not make exhaustive manual frame review the routine path.
## Delivery requirements
- Declare dimensions or aspect ratio.
- Keep text, labels and calls to action in semantic HTML.
- Use one active cinematic media element per viewport.
- Lazy-load below-fold films and stop work off screen.
- Avoid multiple large LCP candidates.
- Use silent output and strip generated audio.
- Provide posters for no-JavaScript, reduced motion, Save-Data and errors.
- Disclose generated media when it could imply documentary product evidence.
- Verify responsive crops and forward/backward scroll before integration.
references/motion-patterns.md
# Motion patterns
## Selection matrix
| Need | Preferred mechanism | Avoid |
|---|---|---|
| Hover/focus feedback | CSS transition | JavaScript timeline |
| One-shot entrance | Intersection Observer + class | scroll listener per element |
| Reading progress | CSS scroll timeline or one passive listener | layout reads on every scroll |
| Sticky narrative | CSS sticky + bounded container | pinning the whole document |
| Coordinated timeline | GSAP/established project library | adding a library for one fade |
| Photographic 3D illusion | encoded video scrub | heavy real-time WebGL |
| Precise cross-device seeking | canvas frame sequence | unthrottled `currentTime` writes |
| Manipulable 3D object | WebGL/Spline/Three.js | prerecorded video pretending to be interactive |
## Karaoke text
Keep readable text in the DOM. The inactive state must still meet contrast requirements or expose an ordinary paragraph to reduced-motion users.
In React, never call `useTransform` inside `.map()`. Put each word in a child component and call hooks at the child’s top level:
```tsx
function Word({ progress, start, end, children }) {
const opacity = useTransform(progress, [start, end], [0.35, 1]);
return <motion.span style={{ opacity }}>{children} </motion.span>;
}
function KaraokeText({ value }) {
const ref = useRef(null);
const { scrollYProgress } = useScroll({ target: ref });
const words = value.split(/\s+/);
return (
<p ref={ref}>
{words.map((word, index) => (
<Word
key={`${word}-${index}`}
progress={scrollYProgress}
start={index / words.length}
end={(index + 1) / words.length}
>
{word}
</Word>
))}
</p>
);
}
```
For Astro/static sites, prefer a CSS-highlight treatment driven by one small module script. Restore the complete static paragraph under reduced motion or without JavaScript.
## Sticky horizontal track
- Use a vertical wrapper whose height represents the required scroll distance.
- Keep the track sticky for only the narrative section.
- Calculate travel from actual `scrollWidth - clientWidth`; do not hard-code `-66.6%`.
- Do not trap wheel, touch or keyboard scrolling.
- On narrow screens, switch to an ordinary vertical list or native horizontal overflow with visible controls.
- Keep focus order in reading order.
## Video scrubber
- Treat prompt/reference-image generation as a first-class source for authored
product camera moves. CAD or a GLB model is not required when the visitor
follows one pre-rendered path.
- Read `generated-product-scrubber.md` before producing or integrating the
media.
- Use `preload="metadata"` by default and provide a poster.
- Wait for metadata before seeking.
- Coalesce updates with `requestAnimationFrame`.
- Avoid seeking when the requested time differs by less than a small threshold.
- Pause work when the section is outside the viewport.
- Supply a static poster or short ordinary video for reduced motion, data saving and unsupported devices.
- Test iOS Safari before choosing `<video>` seeking over a frame sequence.
## Infinite card deck
Drag must never be the only control. Include labelled Previous/Next or Dismiss buttons and announce the active card. Preserve a stable DOM reading order where possible. Requeue only after an exit animation completes; guard empty and one-card states.
## FAQ and disclosure
Use native `<details>/<summary>` unless product requirements demand an application-style accordion. Animate only the decorative indicator or a measured content wrapper. Keep the answer accessible without animation.
## Hover depth and parallax
Apply hover motion only to devices that support hover. Keep transforms small, avoid moving the hit target away from the pointer and match the same emphasis with `:focus-visible`.
## Reduced motion
```css
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
scroll-behavior: auto !important;
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
```
Use a targeted override when global suppression would hide required state changes.
references/prompts.md
# Reusable user requests
The user does not need to know the production tool or say “wow”. The skill must
infer cinematic intent from the desired experience or reference.
## Cinematic product experience
```text
Use $ai-ui-ux-motion-engine to create an impressive cinematic,
scroll-controlled product experience from these references.
Show:
Pages/placements:
Accuracy required:
Source images/CAD/clips:
Target devices:
Before changing the page, tell me whether cinematic media generation, 3D or
compositing is required. Confirm provider access and cost, prepare one private
signature proof, reject identity or geometry drift, and get approval before
generating the remaining library or integrating it.
```
## Reference-led project
```text
Use $ai-ui-ux-motion-engine.
Goal:
Audience:
Primary action:
Routes/components:
Evidence rules:
References:
Target devices:
Framework/constraints:
Required interactions:
Release boundary:
Inspect project instructions and current changes. Infer whether the references
depend on generated/filmed motion and run the cinematic-intent gate when they
do. Implement one approved bounded component at a time and run the full
baseline.
```
## Reference mashup
```text
Use $ai-ui-ux-motion-engine to combine these references without cloning.
Extract page rhythm from reference A and interaction/camera language from
reference B. Keep branding, copy, evidence, information architecture and
shipping assets native to this project. Identify any required media provider
before implementation.
```
## Hero alternatives
```text
Use $ai-ui-ux-motion-engine to prepare exactly three hero directions.
Hold content, palette and viewport constant. Vary only composition and the
signature interaction. State whether each requires generated film, 3D or only
code-native motion, including proof cost and implementation risk. Do not change
production files until a direction and any cinematic proof are approved.
```
## Motion audit
```text
Use $ai-ui-ux-motion-engine in audit-only mode. Report whether the intended
cinematic impact is present, whether the chosen media/tool can produce it,
motion purpose, input parity, reduced motion, mobile fallback, performance
risk and implementation defects. Do not edit files.
```
## Micro refinement
```text
Use $ai-ui-ux-motion-engine for this bounded component only. Preserve the
approved direction and media. Improve hierarchy, spacing and
pointer/keyboard/touch states, then run focused checks. Do not introduce a new
visual motif, provider or dependency.
```
references/research-and-extraction.md
# Research and design extraction
## Competitor study
Use a reproducible sample rather than labelling unknown businesses “winners” and “losers.”
1. Define market, geography, query set and observation date.
2. Select competitors using disclosed signals such as search visibility, review volume, public revenue evidence or market recognition.
3. Record unknown performance instead of inferring it from visual quality.
4. Capture page anatomy, offer clarity, proof, friction, accessibility, performance and CTA patterns.
5. Separate observed features from hypotheses about conversion.
6. Preserve URLs and evidence dates.
Suggested scorecard:
| Dimension | Weight | Evidence |
|---|---:|---|
| Offer and audience clarity | 20 | First viewport and navigation |
| Evidence and trust | 20 | Named proof, dates, sources |
| Decision support | 15 | Comparisons, calculators, FAQs |
| Conversion path | 15 | CTA relevance and friction |
| Accessibility | 10 | Keyboard, semantics, contrast |
| Performance | 10 | Field/lab evidence |
| Distinctiveness | 10 | Brand-specific visual system |
Do not claim exact CTA wording “produces conversions” without analytics or controlled testing.
## Design-system extraction
Extract roles, not just values:
- display, heading, body, label and data typography;
- background, surface, border, text, accent, success and warning colours;
- spacing rhythm and container widths;
- shape language, borders, shadows and texture;
- media aspect ratios and crop behaviour;
- interaction states and motion timing;
- responsive changes.
Create a new target-specific system. Do not copy a distinctive combination wholesale.
## Reference mashup
Write a provenance decision before implementation:
```text
Structure: target project architecture
Page rhythm: reference A
Motion language: reference B
Typography: target brand research
Content and claims: target source documents
Signature differentiator: original project concept
```
This prevents accidental cloning and incoherent effect stacking.
references/source-coverage.md
# Source coverage and provenance
## Evidence status
The skill was rebuilt from the saved Gemini conversation dated 26 July 2026, which contains Gemini’s summaries of four videos but not complete transcripts. YouTube exposed no captions for the first source during independent review. Therefore this file does not claim word-for-word or 100% transcript coverage.
The package treats the videos as inspiration and strengthens their techniques with current platform documentation, React rules, accessibility, responsive, performance and release controls.
## Coverage ledger
| Source | Technique recorded in saved conversation | Implemented in |
|---|---|---|
| Made by Sourasith, GPT-5.6/Codex site build | reference recording, video-to-layout extraction | `media-pipeline.md`, `workflow.md`, extraction script |
| Same | multi-reference mashup without cloning | `research-and-extraction.md`, `prompts.md` |
| Same | architecture versus rapid micro-iteration routing | `workflow.md` capability routing |
| Same | sticky tracks, karaoke reveal, looping card deck | `motion-patterns.md` |
| Same | FAQ and testimonial hover refinement | `motion-patterns.md` disclosure and hover sections |
| Mikey Website, Claude Design refinement | first pass as raw material; macro before micro | `SKILL.md`, `workflow.md` |
| Same | goal/layout/voice/audience brief | `SKILL.md`, `prompts.md` |
| Same | key offer high in page; hero alternatives | `SKILL.md`, `prompts.md` |
| Same | targeted component comments and preview workaround | bounded component workflow; platform-neutral browser verification |
| Zubair Trabzada, cinematic site workflow | prompt/reference-image product films, scroll-linked video and canvas frame sequence without mandatory CAD | `generated-product-scrubber.md`, `motion-patterns.md`, `media-pipeline.md` |
| Same | sequential end-frame chaining | `generated-product-scrubber.md`, `media-pipeline.md` with honest continuity limit |
| Same | external media connector and local frame processing | `tool-connections.md`, extraction script |
| Same | local preview and delivery validation | `verification.md` |
| Jack Roberts, seven-level website workflow | references, design skills, media, components, research and design extraction | core workflow plus all reference modules |
| Same | Firecrawl competitor research | `research-and-extraction.md`, `tool-connections.md` |
| Same | component registry adaptation | `tool-connections.md` |
| Same | seamless product loops | `media-pipeline.md` |
## Production-learning coverage
A later identity-locked technical-product implementation exposed gaps that
video summaries alone could not reveal. Version 1.6 adds these evidence-led
corrections:
- cinematic intent must be inferred before page implementation;
- media-provider access, source quality, terms, credits and attempt limits are
first-class dependencies;
- one private signature proof precedes page redesign or library generation;
- flagship and supporting films require different models and shot complexity;
- exact-product, identity-locked and illustrative routes require different
tolerance for generated detail;
- inconsistent reference packs and multi-action prompts cause avoidable drift;
- ordinary long-GOP video can visibly jump during direct scroll seeking;
- accepted footage needs all-intra/frame-sequence preparation, automated
technical checks and risk-led visual QC;
- a missing requested shot is a disclosed exception, not parity;
- weak proofs must never be wired into a hero as an experiment.
These are documented in `cinematic-intake.md`,
`cinematic-case-study.md`, `cinematic-prompts.md`,
`generated-product-scrubber.md` and executable scripts.
## Deliberate corrections
- No “100% continuity” guarantee.
- No inference that attractive competitors are commercially successful.
- No unsupported `/skill add` command or nonexistent repository.
- No unverified Higgsfield npm package or committed API key.
- No React hooks inside loops.
- No drag-, hover- or motion-only interaction.
- No framework migration to React/Next.js by default.
references/tool-connections.md
# External tools and cinematic-provider preflight
Provider interfaces, models, pricing and authentication change. Verify current
capabilities and displayed cost before configuration or spend.
## Cinematic provider requirement
When the desired experience requires photographic camera movement, unseen
angles, assembly/disassembly or a physical burst:
- use a capable image/video provider, controlled 3D/CAD, compositing or footage;
- state this dependency before page implementation;
- if unavailable, stop the cinematic asset work and offer only an honest static
fallback;
- do not substitute photo fades, CSS zooms, generic stock video or a background
loop and claim equivalent output.
## Provider preflight
Complete before upload:
1. provider is connected and authenticated;
2. upload controls work in the available tool/browser;
3. user owns or may upload the references;
4. any provider terms requiring acceptance are shown to the user;
5. selected model supports the required references, duration, ratio,
resolution, shot control and silent output;
6. displayed cost and attempt cap are recorded and approved;
7. prompt entry and reference ordering can be verified;
8. raw output can be downloaded;
9. no generation begins while any item above is unknown.
Use this mandatory route order:
1. native CLI for coding agents such as Codex when the provider recommends it;
2. native MCP connector when the client exposes it;
3. supported direct API;
4. browser control only when a required capability is absent from every
programmatic route.
Record `provider.accessMethod`, `provider.programmaticPreflightComplete` and,
for browser fallback, `provider.browserFallbackReason` in the cinematic brief.
Do not spend credits merely to test browser automation.
## Higgsfield
Higgsfield currently documents both CLI and MCP access. For Codex, prefer the
CLI. Install and authenticate it using the current official instructions:
```text
npm i -g @higgsfield/cli
higgsfield auth login
```
Then run the bundled non-spending connection check:
```bash
node scripts/higgsfield-preflight.mjs --json higgsfield-preflight.json
```
If a global install is unavailable and the user authorises npm package
download, use `--allow-npx`. The script runs the official CLI account-status
command, records the access route and available credits, and does not submit a
generation.
For clients with native MCP support, the provider has documented:
```text
https://mcp.higgsfield.ai/mcp
```
Verify both routes against current official provider documentation before use.
Authentication is provider-hosted; do not commit credentials or preflight
reports containing account identifiers. Treat individual model names and
command schemas as current capabilities rather than permanent requirements.
Use a multi-reference/multi-shot capable model for a flagship when the brief
requires it. Use a simpler image-to-video model only for one bounded action.
Unlimited or low-cost access does not make a model appropriate for exact
mechanical continuity.
Never use a single-reference image-to-video job for a requested multi-chapter
flagship merely because it is cheaper or immediately available. If the
required real views, CAD or verified keyframes are missing, stop before spend
and report the source gap.
## Local processing
Require `ffmpeg` and `ffprobe` for cinematic delivery. Use:
- `scripts/prepare-scroll-media.sh` for all-intra video, frames, poster and QC;
- `scripts/validate-cinematic-brief.mjs` before generation;
- `scripts/render-cinematic-prompt.mjs` for repeatable prompt structure.
## Browser and visual inspection
Use browser inspection for provider form verification, private-route scroll,
responsive crops, reduced motion, console evidence and screenshots. Sample
forward and backward progress, not only playback.
## Image generation
Use image generation to create missing original references only after art
direction and truth mode are fixed. Check text, hands, hardware geometry, logos,
counts and evidence implications. Generated stills that disagree are not a
valid continuity pack.
## Research and component sources
Use research connectors only when they materially improve evidence. Treat
component registries and inspiration galleries as sources to evaluate for
licence, accessibility, compatibility, maintenance and visual fit—not as
permission to paste code or identity.
references/verification.md
# Verification contract
## Package validation
Run from the repository root:
```bash
node skills/ai-ui-ux-motion-engine/scripts/validate-package.mjs
node skills/ai-ui-ux-motion-engine/scripts/validate-cinematic-brief.mjs \
skills/ai-ui-ux-motion-engine/assets/cinematic-brief.example.json
node skills/ai-ui-ux-motion-engine/scripts/render-cinematic-prompt.mjs \
skills/ai-ui-ux-motion-engine/assets/cinematic-brief.example.json \
--mode flagship
node skills/ai-ui-ux-motion-engine/scripts/test-cinematic-regressions.mjs
node skills/ai-ui-ux-motion-engine/scripts/validate-creative-acceptance.mjs \
skills/ai-ui-ux-motion-engine/assets/creative-acceptance.example.json \
--stage integration
node skills/ai-ui-ux-motion-engine/scripts/validate-scroll-media.mjs \
<exact-shipping-scroll-master.mp4> \
--poster <exact-shipping-poster.jpg> \
--json <delivery-validation.json>
```
Run the media-preparation script against a short synthetic or approved video
and confirm the all-intra master, exact frame count, poster, contact sheet and
metadata.
The shipping MP4 must independently pass the validator after every rename,
recompression, optimisation or CDN transformation. Do not infer that the
shipping asset matches an earlier validated working file.
The shipping poster must come from that exact MP4 and pass the validator's
aspect-ratio and 0.99 first-frame SSIM threshold. In the browser, record poster
and video bounding boxes plus computed fit, position, transform, filter and
mask; any handoff change fails.
## Cinematic asset gate
Before integration:
1. rerun the brief validator and confirm the generated prompt came from that
exact passing brief;
2. inspect the opening, end and evenly sampled contact sheet;
3. inspect difficult mechanical actions densely;
4. verify identity, counts, spacing, geometry, ports, labels and permitted axes;
5. verify every requested shot, progression stage, effect and payoff;
6. reject morphing, duplication, clipping and unexplained transitions;
7. reject camera-only rotation, zoom, dolly or parallax when a flagship journey
was requested;
8. verify the asset is substantial enough for its flagship/supporting tier;
9. record provider/model/settings, programmatic access route, attempts, cost
and generation status;
10. run `validate-creative-acceptance.mjs --stage review`;
11. obtain owner approval for the exact private proof;
12. run `validate-creative-acceptance.mjs --stage integration`.
Technical delivery validation and creative acceptance are separate mandatory
gates. Passing H.264, keyframe, poster, size or scroll tests cannot satisfy the
creative gate.
## Scroll-experience gate
On the isolated private route:
- test at least six forward scroll positions;
- test at least six backward positions;
- perform one rapid full forward pass, one rapid full reverse pass and at least
three direction changes;
- verify the expected cue/DOM chapter at each sample;
- check for long-GOP jumps, stale frames and blank stages;
- record that the video remains visible and poster exposure stays zero after
the first decoded frame, including while `readyState` temporarily drops;
- compare the poster immediately before replacement with the first decoded
frame and reject any crop, scale, position, filter or mask jump;
- confirm only one seek is active and the final decoded time follows the newest
target rather than an obsolete scroll position;
- inspect protected crops on mobile, tablet and desktop;
- confirm poster, reduced-motion, Save-Data, no-JavaScript and media-error paths;
- confirm native keyboard/touch scrolling remains authoritative;
- check console, requests, layout overflow and long tasks.
Do not move the asset to a public hero before this gate passes.
Six settled checkpoint screenshots alone do not pass this gate.
## Project validation
Run focused component checks, motion-safety audit and the full documented
build/lint/typecheck/test baseline. Exercise primary interactions and direct
route loading in a normal preview.
## Claim language
Use:
- “generation passed private visual review” only with saved QC evidence;
- “identity-locked” only when the recorded identity checks pass;
- “evidence-accurate” only against authoritative product evidence;
- “smooth scroll seeking on [browsers]” only after forward/backward testing;
- “scope exception” for omitted requested shots;
- “private preview” or “production deployed” only after platform confirmation.
Continuity can be improved, never guaranteed. Generated visualisation is not
evidence of a delivered build, specification, stock or measured result.
## Handoff
List truth mode, tier, provider/model/settings, references, attempts/credits,
prompt/brief paths, media formats, QC evidence, browser/viewports, fallbacks,
scope exceptions, changed components, unresolved issues and release boundary.
references/workflow.md
# Production workflow
## Phase outputs
### A. Intake and baseline
Produce a short implementation contract:
- bounded target;
- user goal and primary action;
- current framework and constraints;
- authoritative project documents;
- existing uncommitted changes and ownership;
- representative routes and viewports;
- current build/test result;
- acceptance criteria.
Stop when the requested change would overwrite unexplained user work, require a framework migration, introduce a paid service, or materially expand scope.
If the request or reference implies cinematic product motion, a burst/exploded
view, changing photographic viewpoint or scroll-controlled film, run
`cinematic-intake.md` before the normal design phases. Do not code a substitute
effect while the required media route is unresolved.
### B. Reference decomposition
Create a table with one row per scene or section:
| Scene | Geometry | Content role | Motion/input | Trigger/duration | Mobile/reduced equivalent |
|---|---|---|---|---|---|
For multiple references, add a provenance column. Select principles independently:
- reference A may provide page rhythm;
- reference B may provide motion language;
- the target project supplies brand, content and conversion logic.
Do not combine every observed effect. Choose the smallest coherent set.
### C. Direction lock
Write the seven-line direction required by `SKILL.md`. Check that:
- typography choices have a role;
- palette choices establish hierarchy;
- motion explains a relationship;
- the signature differentiator appears in the first viewport or key journey;
- the direction is compatible with the project’s evidence and performance rules.
For cinematic work, also lock the truth mode, production tier, identity
authority, shot progression, provider capability, attempt/credit cap and
private-proof gate.
### D. Implementation passes
Work on one bounded component at a time:
1. cinematic media proof when the experience depends on it;
2. semantic static baseline;
3. layout and visual hierarchy;
4. pointer/keyboard/touch states;
5. approved motion integration;
6. reduced-motion and no-JavaScript behaviour;
7. narrow test.
Commit or checkpoint only after the component passes. Then continue to the next component.
Use the lean path: one flagship per major journey, reuse valid chapters/crops/
reversals, use 3–5 second supporting media only for a new fact and keep other
motion code-native. Prove media before page work. Perform source/provider
research once per run. Do not create multiple redesigns or documentation passes
before proof. Run focused component validation first and the full regression
once after final integration. Capture metadata, contact sheets and reports
automatically.
### E. Regression and handoff
Run the full project baseline after the final component. Compare against the intake record and report:
- requirements met;
- requirements deliberately rejected and why;
- checks passed;
- checks not run;
- changed release status;
- remaining external dependencies.
## Model and agent routing
Use capability-based routing instead of hard-coding product names:
- high-reasoning agent: architecture, multi-reference synthesis, debugging complex scroll timelines and final review;
- fast iteration agent: isolated spacing, copy, hover and responsive adjustments after direction lock;
- vision-capable agent: screenshot/video decomposition and visual comparison;
- browser-capable agent: live interaction, responsive and console verification.
The project’s current model policy overrides this heuristic.
When the client/model supports subagents, default to parallel execution when
two or more independent streams exist and delegation saves time. Use a
high-capability multimodal lead for reference interpretation, truth mode,
creative direction, spend and acceptance. Use faster capable models for
bounded source inventory, provider/cost checks, brief validation, media
preparation, technical QC, browser checks and documentation. Do not assign
visual QC to a model without image/video inspection. Assign file ownership;
never allow concurrent edits to the same files. Do not parallelise paid
generations, approvals or dependent steps. Rejoin before decisions.
scripts/audit-motion-safety.mjs
#!/usr/bin/env node
import { readdir, readFile, stat } from "node:fs/promises";
import { extname, join, resolve } from "node:path";
const root = resolve(process.argv[2] ?? ".");
const strict = process.argv.includes("--strict");
const ignored = new Set([".git", "node_modules", "dist", "build", ".next", ".astro"]);
const extensions = new Set([".astro", ".css", ".html", ".js", ".jsx", ".mjs", ".ts", ".tsx", ".vue", ".svelte"]);
const findings = [];
async function walk(directory) {
for (const entry of await readdir(directory, { withFileTypes: true })) {
if (ignored.has(entry.name)) continue;
const path = join(directory, entry.name);
if (entry.isDirectory()) await walk(path);
else if (extensions.has(extname(entry.name))) await inspect(path);
}
}
async function inspect(path) {
if (path.endsWith("audit-motion-safety.mjs")) return;
const source = await readFile(path, "utf8");
const hasMotion = /@keyframes|animation\s*:|transition\s*:|useScroll|ScrollTrigger|requestAnimationFrame|IntersectionObserver/.test(source);
if (hasMotion && !/prefers-reduced-motion|useReducedMotion/.test(source)) {
findings.push({ path, level: "warning", rule: "motion-without-local-reduced-motion-signal" });
}
for (const match of source.matchAll(/<video\b[^>]*>/gi)) {
const tag = match[0];
if (/\bautoplay\b/i.test(tag) && (!/\bmuted\b/i.test(tag) || !/\bplaysinline\b/i.test(tag))) {
findings.push({ path, level: "error", rule: "autoplay-video-must-be-muted-and-playsinline" });
}
if (!/\bposter\s*=/i.test(tag)) {
findings.push({ path, level: "warning", rule: "video-without-poster" });
}
}
if (/\.addEventListener\(\s*["']scroll["']/.test(source) &&
!/requestAnimationFrame|passive\s*:\s*true/.test(source)) {
findings.push({ path, level: "warning", rule: "scroll-listener-without-throttle-or-passive-signal" });
}
if (/\bdrag(?:=|\s)|onDragEnd/.test(source) &&
!/onKeyDown|Previous|Next|Dismiss|button/i.test(source)) {
findings.push({ path, level: "warning", rule: "drag-interaction-without-visible-alternative-signal" });
}
}
const target = await stat(root).catch(() => null);
if (!target?.isDirectory()) {
console.error(`Project directory not found: ${root}`);
process.exit(2);
}
await walk(root);
if (findings.length === 0) {
console.log("Motion safety audit: no heuristic findings.");
process.exit(0);
}
console.log(`Motion safety audit: ${findings.length} heuristic finding(s).`);
for (const finding of findings) {
console.log(`${finding.level.toUpperCase()} ${finding.rule} ${finding.path}`);
}
console.log("Review findings manually; absence of findings is not a conformance claim.");
if (strict && findings.some((finding) => finding.level === "error")) process.exit(1);
scripts/extract-reference-frames.sh
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -lt 2 || $# -gt 3 ]]; then
echo "Usage: $0 <input-video> <output-directory> [interval-seconds]" >&2
exit 2
fi
input_video=$1
output_dir=$2
interval_seconds=${3:-2}
if [[ ! -f "$input_video" ]]; then
echo "Input video not found: $input_video" >&2
exit 2
fi
if ! command -v ffmpeg >/dev/null 2>&1 || ! command -v ffprobe >/dev/null 2>&1; then
echo "ffmpeg and ffprobe are required." >&2
exit 3
fi
if ! [[ "$interval_seconds" =~ ^[0-9]+([.][0-9]+)?$ ]] || [[ "$interval_seconds" == "0" ]]; then
echo "Interval must be a positive number of seconds." >&2
exit 2
fi
mkdir -p "$output_dir/even" "$output_dir/scenes"
ffprobe -v quiet -print_format json -show_format -show_streams \
"$input_video" > "$output_dir/ffprobe.json"
ffmpeg -hide_banner -loglevel error -y -i "$input_video" \
-vf "fps=1/${interval_seconds},scale='min(1600,iw)':-2" \
-q:v 2 "$output_dir/even/frame-%05d.jpg"
ffmpeg -hide_banner -loglevel error -y -i "$input_video" \
-vf "select='gt(scene,0.22)',scale='min(1600,iw)':-2" \
-fps_mode vfr -pix_fmt yuvj420p -q:v 2 "$output_dir/scenes/scene-%05d.jpg"
even_count=$(find "$output_dir/even" -type f -name '*.jpg' | wc -l | tr -d ' ')
scene_count=$(find "$output_dir/scenes" -type f -name '*.jpg' | wc -l | tr -d ' ')
echo "Extracted $even_count interval frames and $scene_count scene-change frames."
echo "Metadata: $output_dir/ffprobe.json"
scripts/higgsfield-preflight.mjs
#!/usr/bin/env node
import { spawnSync } from "node:child_process";
import { writeFile } from "node:fs/promises";
import { resolve } from "node:path";
const args = process.argv.slice(2);
const allowNpxIndex = args.indexOf("--allow-npx");
const allowNpx = allowNpxIndex !== -1;
if (allowNpx) args.splice(allowNpxIndex, 1);
const jsonIndex = args.indexOf("--json");
const jsonPath = jsonIndex === -1 ? "" : args[jsonIndex + 1];
if (jsonIndex !== -1) args.splice(jsonIndex, 2);
if (args.length > 0) {
console.error("Usage: higgsfield-preflight.mjs [--allow-npx] [--json REPORT.json]");
process.exit(2);
}
const candidates = [
{
label: "installed-cli",
command: "higgsfield",
prefix: [],
},
];
if (allowNpx) {
candidates.push({
label: "npm-exec-cli",
command: "npm",
prefix: ["exec", "--yes", "--package=@higgsfield/cli", "--", "higgsfield"],
});
}
let selected = null;
let result = null;
for (const candidate of candidates) {
const attempt = spawnSync(
candidate.command,
[...candidate.prefix, "account", "status", "--json"],
{ encoding: "utf8", maxBuffer: 8 * 1024 * 1024 },
);
if (attempt.status === 0) {
selected = candidate;
result = attempt;
break;
}
}
if (!selected) {
console.error(
"Higgsfield CLI preflight failed. Install with `npm i -g @higgsfield/cli`, run `higgsfield auth login`, then retry. Use --allow-npx only with authority to download the package.",
);
process.exit(1);
}
let account;
try {
account = JSON.parse(result.stdout);
} catch {
console.error("Higgsfield returned an unreadable account-status response.");
process.exit(1);
}
const report = {
passed: true,
provider: "Higgsfield",
accessMethod: "cli",
route: selected.label,
authenticated: Boolean(account.email),
workspacePlan: account.subscription_plan_type ?? null,
creditsAvailable: account.credits ?? null,
checkedAt: new Date().toISOString(),
browserRequired: false,
};
if (!report.authenticated) {
console.error("Higgsfield CLI is available but not authenticated.");
process.exit(1);
}
if (jsonPath) await writeFile(resolve(jsonPath), `${JSON.stringify(report, null, 2)}\n`);
console.log(
`Higgsfield CLI preflight passed via ${selected.label}: authenticated, ${String(report.creditsAvailable)} credits available.`,
);
scripts/prepare-scroll-media.sh
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage: prepare-scroll-media.sh INPUT.mp4 OUTPUT_DIR [--frames COUNT] [--width PX]
Creates:
scroll-master.mp4 silent all-intra H.264 for responsive direct seeking
delivery-validation.json machine-readable proof of the scrub master
poster.jpg first-frame fallback
frames/*.jpg exact scroll sequence
contact-sheet.jpg evenly sampled QC overview
ffprobe.json source metadata
EOF
}
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
usage
exit 0
fi
[[ $# -ge 2 ]] || { usage >&2; exit 2; }
input="$1"
output_dir="$2"
shift 2
frame_count=150
width=1600
while [[ $# -gt 0 ]]; do
case "$1" in
--frames) frame_count="${2:-}"; shift 2 ;;
--width) width="${2:-}"; shift 2 ;;
*) echo "Unknown argument: $1" >&2; usage >&2; exit 2 ;;
esac
done
[[ -f "$input" ]] || { echo "Input does not exist: $input" >&2; exit 2; }
[[ "$frame_count" =~ ^[1-9][0-9]*$ ]] || { echo "--frames must be a positive integer" >&2; exit 2; }
[[ "$width" =~ ^[1-9][0-9]*$ ]] || { echo "--width must be a positive integer" >&2; exit 2; }
command -v ffmpeg >/dev/null || { echo "ffmpeg is required" >&2; exit 3; }
command -v ffprobe >/dev/null || { echo "ffprobe is required" >&2; exit 3; }
mkdir -p "$output_dir/frames"
duration="$(ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 "$input")"
rate="$(awk -v frames="$frame_count" -v seconds="$duration" 'BEGIN { printf "%.8f", frames / seconds }')"
sheet_rate="$(awk -v seconds="$duration" 'BEGIN { printf "%.8f", 30 / seconds }')"
ffprobe -v error -show_format -show_streams -of json "$input" > "$output_dir/ffprobe.json"
ffmpeg -hide_banner -loglevel error -y -i "$input" \
-map 0:v:0 -an -c:v libx264 -preset medium -crf 18 \
-g 1 -keyint_min 1 -sc_threshold 0 -pix_fmt yuv420p \
-movflags +faststart "$output_dir/scroll-master.mp4"
ffmpeg -hide_banner -loglevel error -y -i "$output_dir/scroll-master.mp4" \
-frames:v 1 -vf "scale=${width}:-2:flags=lanczos" -q:v 2 \
"$output_dir/poster.jpg"
node "$(dirname "$0")/validate-scroll-media.mjs" \
"$output_dir/scroll-master.mp4" \
--poster "$output_dir/poster.jpg" \
--json "$output_dir/delivery-validation.json"
ffmpeg -hide_banner -loglevel error -y -i "$input" \
-vf "fps=${rate},scale=${width}:-2:flags=lanczos" -frames:v "$frame_count" \
-q:v 3 "$output_dir/frames/frame_%04d.jpg"
ffmpeg -hide_banner -loglevel error -y -i "$input" \
-vf "fps=${sheet_rate},scale=240:-2:flags=lanczos,tile=5x6" \
-frames:v 1 -q:v 3 "$output_dir/contact-sheet.jpg"
actual_frames="$(find "$output_dir/frames" -type f -name 'frame_*.jpg' | wc -l | tr -d ' ')"
[[ "$actual_frames" -eq "$frame_count" ]] || {
echo "Expected $frame_count frames, created $actual_frames" >&2
exit 4
}
printf 'Prepared scroll media: %s frames at %spx in %s\n' "$actual_frames" "$width" "$output_dir"
scripts/render-cinematic-prompt.mjs
#!/usr/bin/env node
import { readFile } from "node:fs/promises";
import { resolve } from "node:path";
const args = process.argv.slice(2);
const modeIndex = args.indexOf("--mode");
const mode = modeIndex === -1 ? "flagship" : args[modeIndex + 1];
if (modeIndex !== -1) args.splice(modeIndex, 2);
if (args.length !== 1 || !["flagship", "single", "illustrative"].includes(mode)) {
console.error("Usage: render-cinematic-prompt.mjs <brief.json> --mode flagship|single|illustrative");
process.exit(2);
}
const brief = JSON.parse(await readFile(resolve(args[0]), "utf8"));
if (brief.experience?.tier === "flagship" && mode !== "flagship") {
console.error(
"A flagship brief must use --mode flagship. It cannot be downgraded to a single supporting action or illustrative shortcut.",
);
process.exit(1);
}
if (mode === "flagship" && brief.experience?.tier !== "flagship") {
console.error("--mode flagship requires experience.tier=flagship.");
process.exit(1);
}
const counts = (brief.identity?.exactCounts ?? [])
.map(({ name, count }) => `exactly ${count} ${name}`)
.join(", ");
const immutable = (brief.identity?.immutableDetails ?? []).join(", ");
const look = [brief.look?.background, brief.look?.lighting, brief.look?.camera]
.filter(Boolean)
.join(". ");
const exclusions = (brief.forbidden ?? []).join(", ");
const delivery = brief.experience ?? {};
const intent = brief.intent ?? {};
const header = `Create a silent ${delivery.durationSeconds}-second ${delivery.aspectRatio} ${delivery.resolution} premium product film of ${brief.identity.description}. ${brief.identity.authorityReference} is the identity authority.`;
const lock = `IDENTITY LOCK: Preserve ${immutable || "the exact visible identity"}.${counts ? ` Maintain ${counts} in the same order and spacing.` : ""} Rigid parts remain rigid and keep their size, shape and material.`;
const finish = `EXCLUSIONS: No ${exclusions}. Keep clean first and final frames and no generated audio.`;
const plannedActions = (brief.shots ?? []).map((shot) => shot.action).join("; ");
const intentContract = `INTENT CONTRACT: ${intent.requestSummary}. Signature moment: ${intent.signatureMoment}. Required progression: ${(intent.progression ?? []).join(" -> ")}. Required payoff: ${intent.payoff}. Do not substitute ${(intent.prohibitedSubstitutes ?? []).join(", ")}.`;
if (mode === "single") {
const shot = brief.shots[0];
console.log(`${header}
${lock}
${intentContract}
ACTION: Using ${shot.reference}, perform only ${shot.action}. Camera: ${shot.camera}. Finish at ${shot.endState}.
LOOK: ${look}.
${finish}`);
} else if (mode === "illustrative") {
console.log(`${header}
Use the reference as the recognisable identity anchor. Create a controlled exploded or burst composition whose named groups separate on clean readable paths, pause, and return exactly to the opening silhouette. Preserve total part count and recognisable materials.
${intentContract}
PLANNED ACTION LANGUAGE: ${plannedActions}.
LOOK: ${look}.
${finish}`);
} else {
const shotList = brief.shots
.map(
(shot, index) =>
`SHOT ${index + 1} — ${shot.name.toUpperCase()} — ${shot.startSeconds.toFixed(2)}-${shot.endSeconds.toFixed(2)}s
Purpose: ${shot.purpose}. Subject change: ${shot.subjectChange}. Reference: ${shot.reference}. Action: ${shot.action}. Camera: ${shot.camera}. End: ${shot.endState}.`,
)
.join("\n\n");
console.log(`${header}
Every attached reference depicts the same product. Other references constrain only their named shots.
${lock}
${intentContract}
LOOK: ${look}. Preserve it across every hard cut.
${shotList}
EDITING: Use distinct hard cuts only. Do not replace a requested mechanical action with a generic orbit or transition.
${finish}`);
}
scripts/test-cinematic-regressions.mjs
#!/usr/bin/env node
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { spawnSync } from "node:child_process";
const scriptsDir = dirname(fileURLToPath(import.meta.url));
const skillRoot = resolve(scriptsDir, "..");
const validator = join(scriptsDir, "validate-cinematic-brief.mjs");
const renderer = join(scriptsDir, "render-cinematic-prompt.mjs");
const creativeValidator = join(scriptsDir, "validate-creative-acceptance.mjs");
const validBrief = join(skillRoot, "assets/cinematic-brief.example.json");
const failedBrief = join(
skillRoot,
"assets/regressions/camera-only-homepage-failure.json",
);
const creativeReview = join(skillRoot, "assets/creative-acceptance.example.json");
function run(script, args) {
return spawnSync(process.execPath, [script, ...args], {
encoding: "utf8",
maxBuffer: 8 * 1024 * 1024,
});
}
const valid = run(validator, [validBrief]);
if (valid.status !== 0) {
console.error(valid.stderr || valid.stdout);
process.exit(1);
}
const failed = run(validator, [failedBrief]);
if (failed.status === 0) {
console.error("The camera-only homepage regression fixture unexpectedly passed.");
process.exit(1);
}
for (const code of [
"FLAGSHIP_INTENT_CANNOT_BE_DOWNGRADED",
"FULLSCREEN_SCROLL_REQUIRES_FLAGSHIP",
"UNSEEN_GEOMETRY_SOURCE_GAP",
"PROGRAMMATIC_PREFLIGHT_REQUIRED",
"REQUESTED_BURST_OR_TRANSFORMATION_IS_MISSING",
]) {
if (!failed.stderr.includes(code)) {
console.error(`Regression fixture did not prove required failure: ${code}`);
process.exit(1);
}
}
const wrongMode = run(renderer, [validBrief, "--mode", "single"]);
if (wrongMode.status === 0 || !wrongMode.stderr.includes("must use --mode flagship")) {
console.error("A flagship brief was incorrectly allowed through single-shot prompt mode.");
process.exit(1);
}
const prompt = run(renderer, [validBrief, "--mode", "flagship"]);
if (
prompt.status !== 0 ||
!prompt.stdout.includes("INTENT CONTRACT") ||
!prompt.stdout.includes("SHOT 4") ||
!prompt.stdout.includes("Required payoff")
) {
console.error(prompt.stderr || "The flagship prompt omitted its intent contract.");
process.exit(1);
}
const creativeReviewResult = run(creativeValidator, [
creativeReview,
"--stage",
"integration",
]);
if (creativeReviewResult.status !== 0) {
console.error(creativeReviewResult.stderr || creativeReviewResult.stdout);
process.exit(1);
}
console.log(
"Cinematic regression tests passed: valid flagship accepted; camera-only downgrade, missing source coverage and non-programmatic preflight rejected; creative integration gate accepted only with owner approval.",
);
scripts/validate-cinematic-brief.mjs
#!/usr/bin/env node
import { access, readFile } from "node:fs/promises";
import { dirname, resolve } from "node:path";
const args = process.argv.slice(2);
const checkFilesIndex = args.indexOf("--check-files");
const checkFiles = checkFilesIndex !== -1;
if (checkFiles) args.splice(checkFilesIndex, 1);
if (args.length !== 1 || args[0] === "--help") {
console.log("Usage: validate-cinematic-brief.mjs <brief.json> [--check-files]");
process.exit(args[0] === "--help" ? 0 : 2);
}
const briefPath = resolve(args[0]);
const brief = JSON.parse(await readFile(briefPath, "utf8"));
const failures = [];
const truthModes = new Set(["illustrative", "identity-locked", "evidence-accurate"]);
const tiers = new Set(["flagship", "supporting", "code-native"]);
const workflowProfiles = new Set(["lean-scalable"]);
const accuracyPriorities = new Set(["accuracy-first"]);
const parallelismModes = new Set(["safe-when-supported", "off"]);
const frameInspectionModes = new Set(["automated-overview-dense-on-risk"]);
const impactLevels = new Set(["flagship", "supporting", "ambient"]);
const shotPurposes = new Set(["authority", "progression", "transformation", "inspection", "payoff"]);
const subjectChanges = new Set(["none", "physical", "visualized-system", "environment", "edit"]);
const authorityTypes = new Set(["single-view", "multi-view", "cad", "footage", "generated-concept"]);
const productionTechniques = new Set([
"multi-shot-generation",
"illustrative-burst",
"cad",
"compositing",
"real-footage",
"code-native",
]);
const providerAccessMethods = new Set(["cli", "mcp", "api", "browser", "none"]);
const transformationEffects = new Set([
"assembly",
"disassembly",
"burst",
"explosion",
"exploded-view",
"opening",
"transformation",
]);
const cameraOnlySubstitutes = new Set([
"camera-only",
"css-like-parallax",
"generic-orbit",
"rotation-only",
"zoom-only",
]);
const fail = (code, message) => failures.push(`${code}: ${message}`);
const requireValue = (value, label, code = "REQUIRED_FIELD_MISSING") => {
if (value === undefined || value === null || value === "") {
fail(code, `${label} is required.`);
}
};
requireValue(brief.project, "project");
if (!truthModes.has(brief.truthMode)) fail("INVALID_TRUTH_MODE", "truthMode is invalid.");
if (!workflowProfiles.has(brief.workflow?.profile)) {
fail("INVALID_WORKFLOW_PROFILE", "workflow.profile is invalid.");
}
if (!accuracyPriorities.has(brief.workflow?.accuracyPriority)) {
fail("INVALID_ACCURACY_PRIORITY", "workflow.accuracyPriority must be accuracy-first.");
}
if (!Number.isInteger(brief.workflow?.targetMinutes) || brief.workflow.targetMinutes < 5) {
fail("INVALID_TARGET_TIME", "workflow.targetMinutes must be an integer of at least 5.");
}
if (
!Number.isInteger(brief.workflow?.escalationMinutes) ||
brief.workflow.escalationMinutes < brief.workflow?.targetMinutes
) {
fail(
"INVALID_ESCALATION_TIME",
"workflow.escalationMinutes must be an integer no lower than targetMinutes.",
);
}
if (!parallelismModes.has(brief.workflow?.parallelism)) {
fail("INVALID_PARALLELISM", "workflow.parallelism is invalid.");
}
if (!frameInspectionModes.has(brief.workflow?.frameInspection)) {
fail("INVALID_FRAME_INSPECTION", "workflow.frameInspection is invalid.");
}
requireValue(brief.intent?.requestSummary, "intent.requestSummary");
if (!impactLevels.has(brief.intent?.impact)) {
fail("INVALID_IMPACT_LEVEL", "intent.impact must be flagship, supporting or ambient.");
}
requireValue(brief.intent?.signatureMoment, "intent.signatureMoment");
if (!Array.isArray(brief.intent?.progression) || brief.intent.progression.length === 0) {
fail("PROGRESSION_MISSING", "intent.progression must record the requested authored journey.");
}
requireValue(brief.intent?.payoff, "intent.payoff");
if (!Array.isArray(brief.intent?.requiredEffects)) {
fail("REQUIRED_EFFECTS_MISSING", "intent.requiredEffects must be an array, including an empty one.");
}
if (!Array.isArray(brief.intent?.prohibitedSubstitutes)) {
fail(
"PROHIBITED_SUBSTITUTES_MISSING",
"intent.prohibitedSubstitutes must explicitly record unacceptable shortcuts.",
);
}
if (typeof brief.intent?.requiresMeaningfulStateChange !== "boolean") {
fail(
"MEANINGFUL_CHANGE_UNDECLARED",
"intent.requiresMeaningfulStateChange must be true or false.",
);
}
if (typeof brief.intent?.requiresUnseenGeometry !== "boolean") {
fail("UNSEEN_GEOMETRY_UNDECLARED", "intent.requiresUnseenGeometry must be true or false.");
}
if (typeof brief.intent?.requiresExactMechanics !== "boolean") {
fail("EXACT_MECHANICS_UNDECLARED", "intent.requiresExactMechanics must be true or false.");
}
if (!tiers.has(brief.experience?.tier)) fail("INVALID_TIER", "experience.tier is invalid.");
requireValue(brief.experience?.placement, "experience.placement");
requireValue(brief.experience?.durationSeconds, "experience.durationSeconds");
requireValue(brief.experience?.aspectRatio, "experience.aspectRatio");
if (typeof brief.experience?.scrollControlled !== "boolean") {
fail("SCROLL_CONTROL_UNDECLARED", "experience.scrollControlled must be true or false.");
}
if (brief.intent?.impact === "flagship" && brief.experience?.tier !== "flagship") {
fail(
"FLAGSHIP_INTENT_CANNOT_BE_DOWNGRADED",
"A requested flagship experience cannot be recorded as supporting or code-native.",
);
}
if (
brief.intent?.fullScreen === true &&
brief.intent?.scrollControlled === true &&
brief.experience?.tier !== "flagship"
) {
fail(
"FULLSCREEN_SCROLL_REQUIRES_FLAGSHIP",
"A requested full-screen scroll-controlled cinematic moment must use the flagship tier.",
);
}
if (brief.intent?.scrollControlled !== brief.experience?.scrollControlled) {
fail(
"SCROLL_INTENT_MISMATCH",
"experience.scrollControlled must match intent.scrollControlled.",
);
}
requireValue(brief.production?.technique, "production.technique");
if (
brief.production?.technique &&
!productionTechniques.has(brief.production.technique)
) {
fail("INVALID_PRODUCTION_TECHNIQUE", "production.technique is invalid.");
}
if (!authorityTypes.has(brief.sourceCoverage?.authorityType)) {
fail("INVALID_AUTHORITY_TYPE", "sourceCoverage.authorityType is invalid.");
}
if (typeof brief.sourceCoverage?.supportsUnseenGeometry !== "boolean") {
fail(
"SOURCE_GEOMETRY_COVERAGE_UNDECLARED",
"sourceCoverage.supportsUnseenGeometry must be true or false.",
);
}
if (typeof brief.sourceCoverage?.supportsExactMechanics !== "boolean") {
fail(
"SOURCE_MECHANICS_COVERAGE_UNDECLARED",
"sourceCoverage.supportsExactMechanics must be true or false.",
);
}
if (!Array.isArray(brief.sourceCoverage?.limitations)) {
fail("SOURCE_LIMITATIONS_MISSING", "sourceCoverage.limitations must be an array.");
}
if (
brief.sourceCoverage?.authorityType === "single-view" &&
brief.sourceCoverage?.supportsUnseenGeometry === true
) {
fail(
"SINGLE_VIEW_CANNOT_PROVE_UNSEEN_GEOMETRY",
"A single-view authority cannot claim coverage of unseen geometry.",
);
}
if (
brief.intent?.requiresUnseenGeometry === true &&
brief.sourceCoverage?.supportsUnseenGeometry !== true
) {
fail(
"UNSEEN_GEOMETRY_SOURCE_GAP",
"The requested journey needs unseen geometry but the source pack does not prove it. Use multi-view evidence, CAD, compositing, real footage or an explicitly illustrative route.",
);
}
if (
brief.intent?.requiresExactMechanics === true &&
brief.sourceCoverage?.supportsExactMechanics !== true
) {
fail(
"EXACT_MECHANICS_SOURCE_GAP",
"The requested exact mechanics are not supported by the source pack. Use CAD, verified keyframes or real footage.",
);
}
requireValue(brief.identity?.authorityReference, "identity.authorityReference");
requireValue(brief.identity?.description, "identity.description");
if (!Array.isArray(brief.references) || brief.references.length === 0) {
fail("REFERENCES_MISSING", "At least one reference is required.");
}
if (!Array.isArray(brief.shots) || brief.shots.length === 0) {
fail("SHOTS_MISSING", "At least one shot is required.");
}
if (!Array.isArray(brief.forbidden) || brief.forbidden.length === 0) {
fail("FORBIDDEN_CHANGES_MISSING", "At least one forbidden change is required.");
}
const referenceFiles = new Set((brief.references ?? []).map((reference) => reference.file));
if (!referenceFiles.has(brief.identity?.authorityReference)) {
fail(
"IDENTITY_REFERENCE_MISSING",
"identity.authorityReference must appear in references.",
);
}
if (brief.experience?.tier !== "code-native") {
requireValue(brief.provider?.name, "provider.name");
requireValue(brief.provider?.requiredCapability, "provider.requiredCapability");
if (brief.provider?.connected !== true) {
fail("PROVIDER_NOT_CONNECTED", "provider.connected must be true.");
}
if (brief.provider?.termsApproved !== true) {
fail("PROVIDER_TERMS_NOT_APPROVED", "provider.termsApproved must be true.");
}
if (!(brief.provider?.creditsApproved >= 0)) {
fail("CREDIT_AUTHORITY_MISSING", "provider.creditsApproved must be zero or more.");
}
if (![1, 2].includes(brief.provider?.attemptLimit)) {
fail("INVALID_ATTEMPT_LIMIT", "provider.attemptLimit must be 1 or 2.");
}
if (!providerAccessMethods.has(brief.provider?.accessMethod)) {
fail(
"PROGRAMMATIC_PROVIDER_ROUTE_MISSING",
"provider.accessMethod must be cli, mcp, api or a justified browser fallback.",
);
}
if (brief.provider?.programmaticPreflightComplete !== true) {
fail(
"PROGRAMMATIC_PREFLIGHT_REQUIRED",
"Record a successful CLI, MCP or API preflight before generation.",
);
}
if (
brief.provider?.accessMethod === "browser" &&
!String(brief.provider?.browserFallbackReason ?? "").trim()
) {
fail(
"BROWSER_FALLBACK_UNJUSTIFIED",
"Browser control is last resort and requires the missing CLI/MCP/API capability to be recorded.",
);
}
}
let previousEnd = 0;
for (const [index, shot] of (brief.shots ?? []).entries()) {
const prefix = `shots[${index}]`;
for (const field of ["name", "purpose", "subjectChange", "reference", "action", "camera", "endState"]) {
requireValue(shot[field], `${prefix}.${field}`);
}
if (shot.purpose && !shotPurposes.has(shot.purpose)) {
fail("INVALID_SHOT_PURPOSE", `${prefix}.purpose is invalid.`);
}
if (shot.subjectChange && !subjectChanges.has(shot.subjectChange)) {
fail("INVALID_SUBJECT_CHANGE", `${prefix}.subjectChange is invalid.`);
}
if (shot.reference && !referenceFiles.has(shot.reference)) {
fail("SHOT_REFERENCE_MISSING", `${prefix}.reference is not present in references.`);
}
if (!(shot.startSeconds >= 0) || !(shot.endSeconds > shot.startSeconds)) {
fail("INVALID_SHOT_TIMING", `${prefix} has invalid timing.`);
}
if (index > 0 && Math.abs(shot.startSeconds - previousEnd) > 0.01) {
fail("SHOT_TIMELINE_GAP", `${prefix} does not start where the previous shot ends.`);
}
previousEnd = shot.endSeconds;
}
if (
brief.shots?.length &&
Math.abs(previousEnd - brief.experience.durationSeconds) > 0.01
) {
fail("SHOT_TIMELINE_INCOMPLETE", "Final shot does not end at experience.durationSeconds.");
}
if (brief.experience?.tier === "flagship") {
if (!(brief.experience.durationSeconds >= 10 && brief.experience.durationSeconds <= 15)) {
fail(
"FLAGSHIP_DURATION_OUT_OF_RANGE",
"A flagship film must be 10–15 seconds unless the user explicitly requests a different tier.",
);
}
if ((brief.shots?.length ?? 0) < 3) {
fail(
"FLAGSHIP_REQUIRES_MULTIPLE_CHAPTERS",
"A flagship requires at least three authored shots or chapters.",
);
}
if ((brief.intent?.progression?.length ?? 0) < 3) {
fail(
"FLAGSHIP_REQUIRES_BEGINNING_PROGRESSION_PAYOFF",
"Record at least three requested narrative stages.",
);
}
if (brief.intent?.requiresMeaningfulStateChange !== true) {
fail(
"FLAGSHIP_REQUIRES_MEANINGFUL_CHANGE",
"A flagship cannot be defined as camera movement around a static subject.",
);
}
const purposes = new Set((brief.shots ?? []).map((shot) => shot.purpose));
if (!purposes.has("authority") || !purposes.has("payoff") || purposes.size < 3) {
fail(
"FLAGSHIP_NARRATIVE_STRUCTURE_MISSING",
"Flagship shots must establish authority, progress through a distinct middle state and finish with a payoff.",
);
}
if (!(brief.shots ?? []).some((shot) => shot.subjectChange !== "none")) {
fail(
"CAMERA_ONLY_MOTION_CANNOT_SATISFY_PRODUCT_JOURNEY",
"At least one flagship shot must change the subject, visualized system, environment or edit state.",
);
}
const prohibited = new Set(brief.intent?.prohibitedSubstitutes ?? []);
if (![...cameraOnlySubstitutes].some((item) => prohibited.has(item))) {
fail(
"CAMERA_ONLY_SUBSTITUTE_NOT_PROHIBITED",
"A flagship brief must explicitly prohibit camera-only or CSS-like substitutes.",
);
}
}
const requestedTransformations = (brief.intent?.requiredEffects ?? []).filter((effect) =>
transformationEffects.has(effect),
);
if (requestedTransformations.length > 0) {
const hasTransformationShot = (brief.shots ?? []).some(
(shot) =>
shot.purpose === "transformation" &&
shot.subjectChange !== "none" &&
/\b(assembl|disassembl|burst|explod|separat|open|transform)/i.test(shot.action ?? ""),
);
if (!hasTransformationShot) {
fail(
"REQUESTED_BURST_OR_TRANSFORMATION_IS_MISSING",
`The shot plan does not visibly perform the requested effect(s): ${requestedTransformations.join(", ")}.`,
);
}
}
if (brief.truthMode === "evidence-accurate") {
if (!brief.identity?.immutableDetails?.length) {
fail(
"EVIDENCE_IMMUTABLE_DETAILS_MISSING",
"Evidence-accurate mode requires identity.immutableDetails.",
);
}
if (!brief.identity?.exactCounts?.length) {
fail(
"EVIDENCE_EXACT_COUNTS_MISSING",
"Evidence-accurate mode requires identity.exactCounts.",
);
}
}
for (const [index, exactCount] of (brief.identity?.exactCounts ?? []).entries()) {
if (!exactCount.name || !Number.isInteger(exactCount.count) || exactCount.count < 1) {
fail(
"INVALID_EXACT_COUNT",
`identity.exactCounts[${index}] must have a name and positive integer count.`,
);
}
}
if (checkFiles) {
const base = dirname(briefPath);
for (const reference of brief.references ?? []) {
await access(resolve(base, reference.file)).catch(() =>
fail("REFERENCE_FILE_MISSING", `Reference file does not exist: ${reference.file}`),
);
}
}
if (failures.length) {
console.error(`Cinematic brief validation failed (${failures.length}):`);
failures.forEach((failure) => console.error(`- ${failure}`));
process.exit(1);
}
console.log(
`Cinematic brief passed: ${brief.experience.tier}, ${brief.truthMode}, ${brief.shots.length} shots, ${brief.provider?.accessMethod ?? "n/a"} provider route, ${brief.provider?.attemptLimit ?? 0} attempt(s).`,
);
scripts/validate-creative-acceptance.mjs
#!/usr/bin/env node
import { access, readFile } from "node:fs/promises";
import { dirname, resolve } from "node:path";
const args = process.argv.slice(2);
const stageIndex = args.indexOf("--stage");
const stage = stageIndex === -1 ? "review" : args[stageIndex + 1];
if (stageIndex !== -1) args.splice(stageIndex, 2);
if (args.length !== 1 || !["review", "integration"].includes(stage)) {
console.error(
"Usage: validate-creative-acceptance.mjs REVIEW.json [--stage review|integration]",
);
process.exit(2);
}
const reviewPath = resolve(args[0]);
const review = JSON.parse(await readFile(reviewPath, "utf8"));
const base = dirname(reviewPath);
const briefPath = resolve(base, review.brief ?? "");
const assetPath = resolve(base, review.asset ?? "");
const failures = [];
const fail = (code, message) => failures.push(`${code}: ${message}`);
await access(briefPath).catch(() => fail("BRIEF_FILE_MISSING", "review.brief does not exist."));
await access(assetPath).catch(() => fail("ASSET_FILE_MISSING", "review.asset does not exist."));
let brief = null;
try {
brief = JSON.parse(await readFile(briefPath, "utf8"));
} catch {
fail("BRIEF_UNREADABLE", "The referenced cinematic brief could not be read.");
}
for (const [field, message] of [
["openingMatches", "The requested opening was not confirmed."],
["progressionMatches", "The requested progression was not confirmed."],
["payoffMatches", "The requested payoff was not confirmed."],
["meaningfulStateChange", "No meaningful subject or scene-state change was confirmed."],
["tierSubstantial", "The film is not substantial enough for its assigned tier."],
["identityContinuity", "Product identity continuity was not confirmed."],
["truthfulnessDisclosed", "Generated inference and truth limitations were not disclosed."],
]) {
if (review.creative?.[field] !== true) fail("CREATIVE_ACCEPTANCE_FAILED", message);
}
if (review.creative?.cameraOnlySubstitute !== false) {
fail(
"CAMERA_ONLY_SUBSTITUTE_REJECTED",
"A camera-only rotation, zoom, dolly or parallax cannot pass creative acceptance.",
);
}
if (!Array.isArray(review.creative?.observedEffects)) {
fail("OBSERVED_EFFECTS_MISSING", "creative.observedEffects must be an array.");
}
if (!String(review.creative?.evidenceNotes ?? "").trim()) {
fail("CREATIVE_EVIDENCE_MISSING", "Record concise visual evidence for the decision.");
}
if (!Array.isArray(review.creative?.missingMoments)) {
fail("MISSING_MOMENTS_UNDECLARED", "creative.missingMoments must be an array.");
} else if (review.creative.missingMoments.length > 0) {
fail(
"REQUESTED_MOMENTS_MISSING",
`The film omits requested moment(s): ${review.creative.missingMoments.join(", ")}.`,
);
}
const requiredEffects = new Set(brief?.intent?.requiredEffects ?? []);
const observedEffects = new Set(review.creative?.observedEffects ?? []);
const missingEffects = [...requiredEffects].filter((effect) => !observedEffects.has(effect));
if (missingEffects.length > 0) {
fail(
"REQUESTED_EFFECTS_NOT_OBSERVED",
`The film does not show required effect(s): ${missingEffects.join(", ")}.`,
);
}
if (!["ready-for-owner-review", "approved", "rejected"].includes(review.decision)) {
fail("INVALID_REVIEW_DECISION", "decision is invalid.");
}
if (review.decision === "rejected") {
fail("CREATIVE_REVIEW_REJECTED", "Rejected media cannot pass the creative gate.");
}
if (stage === "integration") {
if (review.decision !== "approved" || review.ownerApproved !== true) {
fail(
"OWNER_APPROVAL_REQUIRED",
"Integration requires decision=approved and ownerApproved=true.",
);
}
}
if (failures.length) {
console.error(`Creative acceptance failed (${failures.length}):`);
failures.forEach((failure) => console.error(`- ${failure}`));
process.exit(1);
}
console.log(
`Creative acceptance passed for ${stage}: ${review.decision}, ${requiredEffects.size} required effect(s) observed.`,
);
scripts/validate-package.mjs
#!/usr/bin/env node
import { access, readFile, readdir } from "node:fs/promises";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const scriptsDir = dirname(fileURLToPath(import.meta.url));
const skillRoot = resolve(scriptsDir, "..");
const pluginRoot = resolve(skillRoot, "../..");
const failures = [];
const required = [
join(pluginRoot, ".codex-plugin/plugin.json"),
join(pluginRoot, ".claude-plugin/plugin.json"),
join(pluginRoot, ".github/workflows/validate.yml"),
join(pluginRoot, ".github/ISSUE_TEMPLATE/bug-report.yml"),
join(pluginRoot, ".github/ISSUE_TEMPLATE/feature-request.yml"),
join(pluginRoot, ".github/ISSUE_TEMPLATE/config.yml"),
join(pluginRoot, ".github/PULL_REQUEST_TEMPLATE.md"),
join(pluginRoot, ".github/SUPPORT.md"),
join(pluginRoot, "README.md"),
join(pluginRoot, "CHANGELOG.md"),
join(pluginRoot, "CODE_OF_CONDUCT.md"),
join(pluginRoot, "LICENSE"),
join(pluginRoot, "scripts/install-skill.sh"),
join(pluginRoot, "scripts/install-skill.ps1"),
join(pluginRoot, "GITHUB-PUBLISHING.md"),
join(pluginRoot, "platforms/README.md"),
join(pluginRoot, "platforms/platforms.json"),
join(pluginRoot, "platforms/openai-anthropic.md"),
join(pluginRoot, "platforms/editors-and-agents.md"),
join(pluginRoot, "platforms/google-and-open-standard.md"),
join(pluginRoot, "assets/social-preview.svg"),
join(pluginRoot, "assets/social-preview.png"),
join(skillRoot, "SKILL.md"),
join(skillRoot, "agents/openai.yaml"),
join(skillRoot, "assets/cinematic-brief.example.json"),
join(skillRoot, "assets/creative-acceptance.example.json"),
join(skillRoot, "assets/creative-acceptance-placeholder.txt"),
join(skillRoot, "assets/regressions/camera-only-homepage-failure.json"),
join(skillRoot, "assets/cinematic-scroll-controller.js"),
join(skillRoot, "references/workflow.md"),
join(skillRoot, "references/motion-patterns.md"),
join(skillRoot, "references/media-pipeline.md"),
join(skillRoot, "references/generated-product-scrubber.md"),
join(skillRoot, "references/cinematic-intake.md"),
join(skillRoot, "references/cinematic-prompts.md"),
join(skillRoot, "references/cinematic-case-study.md"),
join(skillRoot, "references/tool-connections.md"),
join(skillRoot, "references/accessibility-performance.md"),
join(skillRoot, "references/source-coverage.md"),
join(skillRoot, "references/verification.md"),
join(skillRoot, "scripts/validate-cinematic-brief.mjs"),
join(skillRoot, "scripts/validate-creative-acceptance.mjs"),
join(skillRoot, "scripts/higgsfield-preflight.mjs"),
join(skillRoot, "scripts/test-cinematic-regressions.mjs"),
join(skillRoot, "scripts/render-cinematic-prompt.mjs"),
join(skillRoot, "scripts/prepare-scroll-media.sh"),
join(skillRoot, "scripts/validate-scroll-media.mjs"),
];
for (const path of required) {
await access(path).catch(() => failures.push(`Missing required file: ${path}`));
}
const skill = await readFile(join(skillRoot, "SKILL.md"), "utf8");
if (!/^---\nname: ai-ui-ux-motion-engine\ndescription: .+\n---/s.test(skill)) {
failures.push("SKILL.md frontmatter is missing or invalid.");
}
for (const phrase of [
"Mandatory cinematic-intent gate",
"The user does not need to use a trigger word",
"Produce one isolated private proof",
"Never put a weak proof into a live hero",
"Never downgrade a requested full-screen",
"Executable flagship gate",
"Programmatic provider rule",
"validate-creative-acceptance.mjs",
"fastest route that can meet the accuracy target",
"Target 15–30 minutes",
"inspect every frame only",
"default to parallel execution",
]) {
if (!skill.includes(phrase)) failures.push(`SKILL.md is missing cinematic guardrail: ${phrase}`);
}
for (const match of skill.matchAll(/\]\((references\/[^)]+)\)/g)) {
const path = join(skillRoot, match[1]);
await access(path).catch(() => failures.push(`Broken SKILL.md reference: ${match[1]}`));
}
const plugin = JSON.parse(await readFile(join(pluginRoot, ".codex-plugin/plugin.json"), "utf8"));
if (plugin.name !== "ai-ui-ux-motion-engine") failures.push("Plugin name does not match skill.");
if (!/^\d+\.\d+\.\d+(?:[-+].+)?$/.test(plugin.version ?? "")) failures.push("Plugin version is not semver.");
if (plugin.version.split("+")[0] !== "1.7.0") failures.push("Plugin base version is not 1.7.0.");
if (plugin.homepage !== "https://opace.agency/services/web-design/") {
failures.push("Codex plugin homepage does not point to Opace web design.");
}
if (
plugin.repository !==
"https://github.com/OpaceDigitalAgency/ai-ui-ux-motion-engine"
) {
failures.push("Codex plugin repository URL is incorrect.");
}
const claudePlugin = JSON.parse(await readFile(join(pluginRoot, ".claude-plugin/plugin.json"), "utf8"));
if (claudePlugin.name !== plugin.name) failures.push("Claude and Codex plugin names differ.");
if (claudePlugin.version.split("+")[0] !== plugin.version.split("+")[0]) {
failures.push("Claude and Codex plugin base versions differ.");
}
if (claudePlugin.skills !== "./skills/") failures.push("Claude plugin does not expose the canonical skills directory.");
if (claudePlugin.homepage !== "https://opace.agency/services/web-design/") {
failures.push("Claude plugin homepage does not point to Opace web design.");
}
if (
claudePlugin.repository !==
"https://github.com/OpaceDigitalAgency/ai-ui-ux-motion-engine"
) {
failures.push("Claude plugin repository URL is incorrect.");
}
const readme = await readFile(join(pluginRoot, "README.md"), "utf8");
if (!readme.includes("[Opace Digital Agency](https://opace.agency/services/web-design/)")) {
failures.push("README is missing the contextual Opace web-design link.");
}
for (const phrase of [
"cinematic scroll reveals",
"provider access and spend",
"one private signature sequence",
"all-intra video",
"cannot silently become a five-second supporting rotation",
"Higgsfield",
]) {
if (!readme.includes(phrase)) failures.push(`README is missing current guidance: ${phrase}`);
}
const cinematicBrief = JSON.parse(
await readFile(join(skillRoot, "assets/cinematic-brief.example.json"), "utf8"),
);
if (cinematicBrief.experience?.tier !== "flagship") {
failures.push("Cinematic example does not exercise the flagship route.");
}
if (cinematicBrief.provider?.attemptLimit !== 1) {
failures.push("Cinematic example does not enforce a one-attempt first proof.");
}
if (cinematicBrief.intent?.impact !== "flagship") {
failures.push("Cinematic example does not lock flagship intent.");
}
if (cinematicBrief.provider?.accessMethod !== "cli") {
failures.push("Cinematic example does not exercise programmatic provider access.");
}
if ((cinematicBrief.intent?.progression?.length ?? 0) < 3) {
failures.push("Cinematic example does not contain an authored progression.");
}
const generatedScrubber = await readFile(
join(skillRoot, "references/generated-product-scrubber.md"),
"utf8",
);
for (const phrase of [
"Golden path",
"One-anchor burst preset",
"Provider preflight",
"Attempt discipline",
"ordinary long-GOP",
"short-GOP",
"Six correct screenshots",
"Scaling across a site",
]) {
if (!generatedScrubber.includes(phrase)) {
failures.push(`Generated scrubber is missing required section: ${phrase}`);
}
}
const workflow = await readFile(join(pluginRoot, ".github/workflows/validate.yml"), "utf8");
for (const phrase of [
"bash -n skills/ai-ui-ux-motion-engine/scripts/prepare-scroll-media.sh",
"validate-scroll-media.mjs",
"silent all-intra H.264",
"prepare-scroll-media.sh",
"validate-cinematic-brief.mjs",
"test-cinematic-regressions.mjs",
"validate-creative-acceptance.mjs",
]) {
if (!workflow.includes(phrase)) failures.push(`Hosted validation is missing: ${phrase}`);
}
if (!readme.includes("https://github.com/OpaceDigitalAgency/ai-ui-ux-motion-engine")) {
failures.push("README is missing the standalone AI UI/UX Motion Engine repository.");
}
const scrollController = await readFile(
join(skillRoot, "assets/cinematic-scroll-controller.js"),
"utf8",
);
for (const phrase of [
"seekInFlight",
"pendingTime",
"loadeddata",
"cinematicReady",
"seekLatest",
]) {
if (!scrollController.includes(phrase)) {
failures.push(`Scroll controller is missing seek-safety contract: ${phrase}`);
}
}
const scrollValidator = await readFile(
join(skillRoot, "scripts/validate-scroll-media.mjs"),
"utf8",
);
for (const phrase of [
"nonIntraFrames",
"audioStreams",
"Fast-start requirement failed",
"--poster",
"posterFirstFrameSsim",
"Poster/first-frame mismatch",
"moov",
"mdat",
]) {
if (!scrollValidator.includes(phrase)) {
failures.push(`Scroll-media validator is missing delivery check: ${phrase}`);
}
}
const briefValidator = await readFile(
join(skillRoot, "scripts/validate-cinematic-brief.mjs"),
"utf8",
);
for (const phrase of [
"FLAGSHIP_INTENT_CANNOT_BE_DOWNGRADED",
"FULLSCREEN_SCROLL_REQUIRES_FLAGSHIP",
"CAMERA_ONLY_MOTION_CANNOT_SATISFY_PRODUCT_JOURNEY",
"REQUESTED_BURST_OR_TRANSFORMATION_IS_MISSING",
"UNSEEN_GEOMETRY_SOURCE_GAP",
"PROGRAMMATIC_PREFLIGHT_REQUIRED",
]) {
if (!briefValidator.includes(phrase)) {
failures.push(`Cinematic brief validator is missing semantic gate: ${phrase}`);
}
}
const creativeValidator = await readFile(
join(skillRoot, "scripts/validate-creative-acceptance.mjs"),
"utf8",
);
for (const phrase of [
"CAMERA_ONLY_SUBSTITUTE_REJECTED",
"REQUESTED_EFFECTS_NOT_OBSERVED",
"OWNER_APPROVAL_REQUIRED",
]) {
if (!creativeValidator.includes(phrase)) {
failures.push(`Creative acceptance validator is missing gate: ${phrase}`);
}
}
const toolConnections = await readFile(
join(skillRoot, "references/tool-connections.md"),
"utf8",
);
for (const phrase of [
"native CLI for coding agents such as Codex",
"higgsfield-preflight.mjs",
"browserFallbackReason",
]) {
if (!toolConnections.includes(phrase)) {
failures.push(`Tool connection guidance is missing programmatic route: ${phrase}`);
}
}
for (const phrase of [
"accuracy-first",
"lean-scalable",
"safe-when-supported",
"automated-overview-dense-on-risk",
]) {
if (!JSON.stringify(cinematicBrief).includes(phrase)) {
failures.push(`Cinematic brief is missing workflow guardrail: ${phrase}`);
}
}
for (const entry of await readdir(join(pluginRoot, "skills"), {
withFileTypes: true,
})) {
if (!entry.isDirectory()) continue;
await access(join(pluginRoot, "skills", entry.name, "README.md"))
.then(() =>
failures.push(
`Canonical skill folder contains auxiliary README.md: ${entry.name}`,
),
)
.catch(() => {});
}
const readmeOpening = readme.slice(0, 2600).replace(/\s+/g, " ");
for (const term of [
"Codex skill",
"Claude Code skill",
"Cursor skill",
"Antigravity skill",
"Gemini CLI skill",
"GitHub Copilot skill",
"Windsurf skill",
"Cline skill",
"Roo Code skill",
"OpenCode skill",
"AI website",
"motion graphics",
"UI design",
"UX design",
]) {
if (!readmeOpening.includes(term)) {
failures.push(`README opening does not clearly identify ${term} support.`);
}
}
const platformRegistry = JSON.parse(
await readFile(join(pluginRoot, "platforms/platforms.json"), "utf8"),
);
const requiredTargetIds = [
"codex",
"claude",
"cursor",
"antigravity",
"antigravity-cli",
"gemini",
"copilot",
"cline",
"roo",
"opencode",
"windsurf",
"amp",
"zed",
"goose",
"agents",
];
const targetIds = new Set(platformRegistry.targets?.map((target) => target.id));
for (const target of requiredTargetIds) {
if (!targetIds.has(target)) failures.push(`Platform registry is missing target: ${target}`);
}
const shellInstaller = await readFile(join(pluginRoot, "scripts/install-skill.sh"), "utf8");
const powershellInstaller = await readFile(join(pluginRoot, "scripts/install-skill.ps1"), "utf8");
for (const target of requiredTargetIds) {
if (!shellInstaller.includes(target)) failures.push(`Shell installer is missing target: ${target}`);
if (!powershellInstaller.includes(`"${target}"`)) {
failures.push(`PowerShell installer is missing target: ${target}`);
}
}
async function validateLocalMarkdownLinks(path) {
const text = await readFile(path, "utf8");
for (const match of text.matchAll(/\]\(([^)]+)\)/g)) {
const href = match[1].trim();
if (
!href ||
href.startsWith("#") ||
/^[a-z][a-z0-9+.-]*:/i.test(href)
) {
continue;
}
const filePart = href.split("#", 1)[0];
await access(resolve(dirname(path), filePart)).catch(() =>
failures.push(`Broken local Markdown link in ${path}: ${href}`),
);
}
}
await validateLocalMarkdownLinks(join(pluginRoot, "README.md"));
await validateLocalMarkdownLinks(join(pluginRoot, "GITHUB-PUBLISHING.md"));
for (const file of await readdir(join(pluginRoot, "platforms"))) {
if (file.endsWith(".md")) {
await validateLocalMarkdownLinks(join(pluginRoot, "platforms", file));
}
}
async function scan(directory) {
for (const entry of await readdir(directory, { withFileTypes: true })) {
if (entry.name === ".git") continue;
const path = join(directory, entry.name);
if (entry.isDirectory()) await scan(path);
else if (/\.(?:md|json|ya?ml|mjs|sh|ps1)$/.test(entry.name)) {
if (path === fileURLToPath(import.meta.url)) continue;
const text = await readFile(path, "utf8");
if (/\[TODO:|yourusername|YOUR_HIGGSFIELD_API_KEY_HERE/.test(text)) {
failures.push(`Placeholder remains in ${path}`);
}
}
}
}
await scan(pluginRoot);
if (failures.length) {
console.error(`Package validation failed (${failures.length}):`);
failures.forEach((failure) => console.error(`- ${failure}`));
process.exit(1);
}
console.log("Package validation passed.");
scripts/validate-scroll-media.mjs
#!/usr/bin/env node
import { readFile, stat, writeFile } from "node:fs/promises";
import { spawnSync } from "node:child_process";
import { resolve } from "node:path";
const args = process.argv.slice(2);
const input = args[0];
let jsonPath = "";
let posterPath = "";
let maxSizeMb = 25;
let minPosterSsim = 0.99;
for (let index = 1; index < args.length; index += 1) {
if (args[index] === "--json") {
jsonPath = args[index + 1] ?? "";
index += 1;
} else if (args[index] === "--poster") {
posterPath = args[index + 1] ?? "";
index += 1;
} else if (args[index] === "--max-size-mb") {
maxSizeMb = Number(args[index + 1]);
index += 1;
} else if (args[index] === "--min-poster-ssim") {
minPosterSsim = Number(args[index + 1]);
index += 1;
} else {
console.error(`Unknown argument: ${args[index]}`);
process.exit(2);
}
}
if (!input) {
console.error(
"Usage: validate-scroll-media.mjs INPUT.mp4 --poster POSTER.jpg [--json REPORT.json] [--max-size-mb 25] [--min-poster-ssim 0.99]",
);
process.exit(2);
}
if (!posterPath) {
console.error("--poster is required so the fallback can be compared with the decoded first frame.");
process.exit(2);
}
if (!Number.isFinite(maxSizeMb) || maxSizeMb <= 0) {
console.error("--max-size-mb must be a positive number.");
process.exit(2);
}
if (!Number.isFinite(minPosterSsim) || minPosterSsim <= 0 || minPosterSsim > 1) {
console.error("--min-poster-ssim must be greater than 0 and no more than 1.");
process.exit(2);
}
const absoluteInput = resolve(input);
const absolutePoster = resolve(posterPath);
const failures = [];
function runFfprobe(probeArgs) {
const result = spawnSync("ffprobe", probeArgs, {
encoding: "utf8",
maxBuffer: 128 * 1024 * 1024,
});
if (result.error?.code === "ENOENT") {
console.error("ffprobe is required to validate scroll media.");
process.exit(3);
}
if (result.status !== 0) {
console.error(result.stderr || "ffprobe failed.");
process.exit(3);
}
return JSON.parse(result.stdout);
}
const metadata = runFfprobe([
"-v",
"error",
"-show_streams",
"-show_format",
"-of",
"json",
absoluteInput,
]);
const frameData = runFfprobe([
"-v",
"error",
"-select_streams",
"v:0",
"-show_entries",
"frame=key_frame,pict_type",
"-of",
"json",
absoluteInput,
]);
const posterMetadata = runFfprobe([
"-v",
"error",
"-show_streams",
"-of",
"json",
absolutePoster,
]);
const streams = metadata.streams ?? [];
const videoStreams = streams.filter((stream) => stream.codec_type === "video");
const audioStreams = streams.filter((stream) => stream.codec_type === "audio");
const video = videoStreams[0];
const poster = (posterMetadata.streams ?? []).find((stream) => stream.codec_type === "video");
const frames = frameData.frames ?? [];
const fileStats = await stat(absoluteInput);
const sizeMb = fileStats.size / 1024 / 1024;
if (videoStreams.length !== 1) failures.push(`Expected one video stream, found ${videoStreams.length}.`);
if (audioStreams.length !== 0) failures.push(`Expected silent media, found ${audioStreams.length} audio stream(s).`);
if (!video) {
failures.push("No primary video stream was found.");
} else {
if (video.codec_name !== "h264") failures.push(`Expected H.264, found ${video.codec_name ?? "unknown"}.`);
if (video.pix_fmt !== "yuv420p") failures.push(`Expected yuv420p, found ${video.pix_fmt ?? "unknown"}.`);
if (!Number.isFinite(Number(video.duration ?? metadata.format?.duration))) {
failures.push("Duration is missing or invalid.");
}
if (!Number.isInteger(video.width) || !Number.isInteger(video.height)) {
failures.push("Video dimensions are missing.");
} else if (video.width % 2 !== 0 || video.height % 2 !== 0) {
failures.push(`Dimensions must be even, found ${video.width}x${video.height}.`);
}
}
if (!poster || !Number.isInteger(poster.width) || !Number.isInteger(poster.height)) {
failures.push("Poster dimensions are missing or invalid.");
} else if (
video &&
Number.isInteger(video.width) &&
Number.isInteger(video.height) &&
video.width * poster.height !== video.height * poster.width
) {
failures.push(
`Poster aspect ratio ${poster.width}x${poster.height} does not match video ${video.width}x${video.height}.`,
);
}
if (frames.length < 2) failures.push(`Expected multiple decoded frames, found ${frames.length}.`);
const nonIntraFrames = frames.filter(
(frame) => frame.key_frame !== 1 || frame.pict_type !== "I",
);
if (nonIntraFrames.length > 0) {
failures.push(
`All-intra requirement failed: ${nonIntraFrames.length} of ${frames.length} frames depend on other frames.`,
);
}
if (sizeMb > maxSizeMb) {
failures.push(
`File is ${sizeMb.toFixed(2)}MB, above the configured ${maxSizeMb.toFixed(2)}MB budget.`,
);
}
const fileBuffer = await readFile(absoluteInput);
const topLevelAtoms = [];
let offset = 0;
while (offset + 8 <= fileBuffer.length) {
let atomSize = fileBuffer.readUInt32BE(offset);
const atomType = fileBuffer.toString("ascii", offset + 4, offset + 8);
let headerSize = 8;
if (atomSize === 1 && offset + 16 <= fileBuffer.length) {
atomSize = Number(fileBuffer.readBigUInt64BE(offset + 8));
headerSize = 16;
} else if (atomSize === 0) {
atomSize = fileBuffer.length - offset;
}
if (atomSize < headerSize || offset + atomSize > fileBuffer.length) break;
topLevelAtoms.push(atomType);
offset += atomSize;
}
const moovIndex = topLevelAtoms.indexOf("moov");
const mdatIndex = topLevelAtoms.indexOf("mdat");
if (moovIndex < 0 || mdatIndex < 0 || moovIndex > mdatIndex) {
failures.push("Fast-start requirement failed: the moov atom must precede mdat.");
}
let posterSsim = null;
if (poster && Number.isInteger(poster.width) && Number.isInteger(poster.height)) {
const comparison = spawnSync(
"ffmpeg",
[
"-hide_banner",
"-i",
absoluteInput,
"-i",
absolutePoster,
"-filter_complex",
`[0:v]select='eq(n,0)',scale=${poster.width}:${poster.height}:flags=lanczos[first];[first][1:v]ssim`,
"-frames:v",
"1",
"-f",
"null",
"-",
],
{ encoding: "utf8", maxBuffer: 32 * 1024 * 1024 },
);
if (comparison.error?.code === "ENOENT") {
console.error("ffmpeg is required to compare the poster with the first decoded frame.");
process.exit(3);
}
if (comparison.status !== 0) {
console.error(comparison.stderr || "ffmpeg poster comparison failed.");
process.exit(3);
}
const match = comparison.stderr.match(/\bAll:([0-9.]+)/);
posterSsim = match ? Number(match[1]) : null;
if (!Number.isFinite(posterSsim)) {
failures.push("Poster comparison did not produce an SSIM score.");
} else if (posterSsim < minPosterSsim) {
failures.push(
`Poster/first-frame mismatch: SSIM ${posterSsim.toFixed(6)} is below ${minPosterSsim.toFixed(6)}. Regenerate the poster from the exact shipping video.`,
);
}
}
const report = {
input: absoluteInput,
poster: absolutePoster,
passed: failures.length === 0,
codec: video?.codec_name ?? null,
pixelFormat: video?.pix_fmt ?? null,
dimensions: video ? `${video.width}x${video.height}` : null,
durationSeconds: Number(video?.duration ?? metadata.format?.duration ?? 0),
frameCount: frames.length,
keyframeCount: frames.filter((frame) => frame.key_frame === 1).length,
nonIntraFrameCount: nonIntraFrames.length,
audioStreamCount: audioStreams.length,
posterDimensions: poster ? `${poster.width}x${poster.height}` : null,
posterFirstFrameSsim: posterSsim,
minPosterSsim,
sizeMb: Number(sizeMb.toFixed(3)),
maxSizeMb,
topLevelAtoms,
failures,
};
if (jsonPath) {
await writeFile(resolve(jsonPath), `${JSON.stringify(report, null, 2)}\n`);
}
if (failures.length > 0) {
console.error(`Scroll-media validation failed (${failures.length}):`);
failures.forEach((failure) => console.error(`- ${failure}`));
process.exit(1);
}
console.log(
`Scroll-media validation passed: ${frames.length}/${frames.length} independent I-frames, silent H.264, fast-start, poster SSIM ${posterSsim.toFixed(6)}, ${sizeMb.toFixed(2)}MB.`,
);
SKILL.md
---
name: ai-ui-ux-motion-engine
description: Design, redesign, build, audit and validate distinctive production websites with cinematic scroll reveals, product films, burst or exploded-view effects, reference-led design systems, purposeful motion and multi-pass refinement. Use for landing pages, product sites, portfolios, interactive storytelling, premium or immersive web experiences, scroll-controlled product inspection, assembly or disassembly sequences, camera moves, image/video-led recreation, hero refinement, motion graphics, and anti-generic visual polish in Astro, React, Next.js, Vue, Svelte or static HTML/CSS. Infer cinematic intent from the requested experience or reference; the user does not need to say "wow" or name a tool.
---
# AI UI/UX Motion Engine
Create a project-specific experience from evidence. Treat references as
structural, visual and interaction inputs, never as permission to clone
branding, copy, code or protected assets.
## Non-negotiable rules
- Read applicable `AGENTS.md`, source-of-truth documents, design systems and
current working-tree changes before editing.
- Define the bounded target, acceptance criteria, dependencies, spend and
validation plan.
- Use the fastest route that can meet the accuracy target. For real products,
default to `evidence-accurate` when authoritative sources exist; never trade
accuracy silently for spectacle. State early when CAD, compositing or real
footage is required.
- Preserve the existing stack unless the user explicitly authorises a change.
- Label observations, facts, proposals, generated visualisations and unknowns.
- Keep content and actions usable without motion, JavaScript or unrestricted
data use.
- Never claim cinematic parity, product accuracy, accessibility, performance
or release readiness without direct evidence.
- Never configure a paid service, accept provider terms or spend credits
without user authority.
- Never downgrade a requested full-screen, homepage or signature cinematic
journey to a supporting shot. A camera rotation, dolly, zoom, parallax or
static-image reveal is not a flagship.
## Mandatory cinematic-intent gate
Activate this gate whenever the request or reference implies any of:
- a cinematic, premium or immersive scroll experience;
- a product opening, assembling, exploding, bursting or transforming;
- a camera orbit, dolly, macro inspection or authored product journey;
- photographic motion controlled by scrolling;
- a reference whose impact comes from changing viewpoint or object state.
The user does not need to use a trigger word or know which tool is required.
Before editing the page:
1. Copy the user's requested outcome into `intent.requestSummary`; record the
signature moment, progression, payoff, required effects and unacceptable
substitutes. Do not rewrite the request around the easiest available asset.
2. Classify truth mode:
- `illustrative`: invented details are acceptable;
- `identity-locked`: the same fictional or concept product must stay stable;
- `evidence-accurate`: visible counts, geometry, labels and mechanics must
match authoritative product evidence.
3. Confirm the reference or desired scenes, available source images or CAD,
number and placement of flagship/supporting moments, target devices, media
provider access and permitted credit/attempt cap.
If the reference is a video, inspect keyframes plus any available transcript,
prompt pack and description links; do not reconstruct its workflow from a
summary or isolated screenshot.
4. State the dependency plainly. Photographic camera movement or physical
transformation requires suitable source media plus an image/video
generation, 3D or compositing route. CSS cannot invent unseen product views.
5. If the required provider or source material is unavailable, stop the
cinematic asset work. Offer the static layout/fallback honestly; never
substitute fades, zooms or stock background video and call it equivalent.
6. Create a cinematic brief from
`assets/cinematic-brief.example.json`, validate it with
`scripts/validate-cinematic-brief.mjs`, and obtain spend/terms authority
before generation. Do not upload or spend after a failed validation.
7. Produce one isolated private proof of the signature moment before redesigning
the page or generating the full library.
8. Reject drift with automated technical checks and an overview contact sheet.
Sample only risky transitions densely; inspect every frame only for a
detected defect or evidence-critical mechanics. Use at most the approved
attempts; then simplify the action, change technique or report the blocker.
9. Create a creative-review JSON from
`assets/creative-acceptance.example.json` and run
`scripts/validate-creative-acceptance.mjs`. Technical media validation does
not prove narrative, impact or creative acceptance.
10. Integrate only an owner-approved asset after the creative validator passes
with `--stage integration`. Never put a weak proof into a live hero to
see whether surrounding UI rescues it.
### Executable flagship gate
Treat a requested full-screen, homepage, hero, signature, immersive, intricate,
burst, exploded or authored scroll journey as `flagship` unless the user
explicitly requests a smaller supporting shot. Before any paid generation run:
```bash
node scripts/validate-cinematic-brief.mjs cinematic-brief.json --check-files
node scripts/render-cinematic-prompt.mjs cinematic-brief.json --mode flagship
```
The validator must reject a tier downgrade, a camera-only story, a missing
beginning/progression/payoff, insufficient source coverage, a missing requested
transformation and an unverified provider route. Do not bypass it by writing a
manual prompt.
After generation, record visual evidence and run:
```bash
node scripts/validate-creative-acceptance.mjs creative-review.json --stage review
```
Use `--stage integration` only after the owner approves the exact private
proof. Never use a passing codec, keyframe, contact-sheet or scroll-delivery
check as evidence that the creative brief passed.
### Programmatic provider rule
Use structured provider access before browser control. For Higgsfield in Codex:
1. prefer the authenticated Higgsfield CLI;
2. use Higgsfield MCP in clients that expose the connector natively;
3. use a supported API when the account exposes one;
4. use browser control only for a required control unavailable through all
programmatic routes, and record that exact limitation in the brief.
Run `scripts/higgsfield-preflight.mjs` before Higgsfield generation. It checks
the CLI account connection without spending credits. Read
[tool-connections.md](references/tool-connections.md) completely before
provider work.
Keep the first response concise: confirm the accuracy target, source readiness,
provider/spend authority, desired placements and delivery/time budget. Do not
ask the user to choose implementation details the skill can determine.
“First time” means selecting the correct professional route and bounded proof
immediately. It cannot guarantee that a stochastic provider’s first render
will pass.
When required information is missing, make the first response short:
> This experience depends on cinematic source motion, not ordinary CSS. I can
> produce it with an approved media provider and suitable references, but I
> first need the required accuracy, key scenes/placements, source assets,
> provider access and credit cap. I will prove one private signature sequence
> before changing the page and will not substitute basic photo reveals.
Read [cinematic-intake.md](references/cinematic-intake.md),
[generated-product-scrubber.md](references/generated-product-scrubber.md) and
[cinematic-prompts.md](references/cinematic-prompts.md) completely when this
gate activates.
## Standard workflow
### 1. Establish the brief and baseline
Record goal, audience, routes, content/evidence rules, target devices,
framework, release boundary and current build/test state. Read
[workflow.md](references/workflow.md).
### 2. Extract references
Map composition, typography, colour, imagery, entrances, scroll, hover, drag,
camera movement, object state and timing. Distinguish reusable principles from
identity-specific material. For a local recording run:
```bash
bash scripts/extract-reference-frames.sh <video> <output-directory>
```
Read [media-pipeline.md](references/media-pipeline.md).
### 3. Lock one direction
Write seven implementable lines covering goal/audience, tone, composition,
typography, colour/media, motion/reduced-motion and one signature
differentiator. Do not proceed on “clean and modern” alone.
### 4. Select the architecture
Choose the lightest mechanism that preserves the intended experience:
- CSS for local state and entrance changes;
- Intersection Observer or native scroll animation for simple reveals;
- an existing motion library for coordinated component motion;
- GSAP for deliberate pinning/timelines;
- generated or filmed media for photographic camera/object change;
- all-intra video or canvas frames for exact scroll scrubbing;
- WebGL/3D for freely manipulable viewpoints or reliable exact mechanics.
For cinematic product motion, the media is the experience. Prove it first; do
not expect CSS transforms to create the missing film.
Use the lean scalable default:
- one master flagship per major journey;
- reuse approved chapters, crops and clean reversals where they stay truthful;
- add a 3–5 second supporting shot only for a genuinely new fact;
- use code-native motion everywhere else.
Target 15–30 minutes for a private proof when sources/provider are ready,
30–60 minutes for an approved flagship plus scroll delivery, and 5–10 minutes
for a derivative or supporting integration. Allow 75–120 minutes only for new
or inconsistent source packs, evidence-critical mechanics, CAD or compositing.
These are targets, not guarantees. If a timebox is exceeded, report the
evidence and obtain approval before continuing.
### 5. Implement in bounded passes
Build semantic content, macro layout, the approved signature motion,
micro-states, responsive composition and editorial polish. Keep text, labels
and actions in the DOM rather than baking them into generated media.
Prevent process bloat: prove media before page work; perform provider and
source research once per run; do not create multiple redesigns or documentation
passes before proof; run a focused component test first and the full regression
once after final integration; capture technical evidence automatically.
When the client/model supports subagents, default to parallel execution whenever
two or more independent streams exist and delegation saves time. Parallelise
source audit, provider capability/current cost, brief validation, media
preparation/QC, browser checks and documentation. Give visual interpretation,
truth mode, creative direction, spend and acceptance to the lead
high-capability multimodal model; use faster capable models for bounded
mechanical work. Never assign visual QC to a model that cannot inspect the
media, let agents edit the same files concurrently, or parallelise paid
generation, approvals or dependent steps. Rejoin before decisions.
### 6. Validate
After each component, test pointer, keyboard, touch, reduced motion, target
viewports, console/runtime behaviour and focused checks. For cinematic media,
also verify identity/count/geometry, first/end states, forward/backward scrub,
crop and fallback. Then run:
```bash
node scripts/audit-motion-safety.mjs <project-directory>
node scripts/validate-scroll-media.mjs <shipping-scroll-master.mp4> \
--poster <shipping-poster.jpg>
node scripts/validate-package.mjs
```
Fail closed: if the media validator fails, the poster reappears after the first
decoded frame, seeks overlap, rapid direction changes expose stale or blank
frames, the poster changes crop or scale against the first decoded frame, or
the film is only still-image crossfades, do not ship the scrubber. Use the
numbered canvas sequence or a static fallback until the complete gate passes.
Six settled checkpoints alone are insufficient.
Run the project’s full regression baseline before handoff. Read
[verification.md](references/verification.md).
## Resource routing
- [cinematic-intake.md](references/cinematic-intake.md): mandatory questions,
pushback, tiers, spend and stop rules.
- [cinematic-prompts.md](references/cinematic-prompts.md): exact reusable
single-action, flagship and illustrative prompt contracts.
- [generated-product-scrubber.md](references/generated-product-scrubber.md):
cinematic production and scroll-delivery golden path.
- [media-pipeline.md](references/media-pipeline.md): references, ffmpeg,
all-intra video, frames, posters and delivery.
- [tool-connections.md](references/tool-connections.md): provider preflight and
external-tool boundaries.
- [motion-patterns.md](references/motion-patterns.md): code-native motion.
- [framework-recipes.md](references/framework-recipes.md): stack-specific
implementation.
- [accessibility-performance.md](references/accessibility-performance.md):
motion safety and performance.
- [prompts.md](references/prompts.md): user-facing request templates.
- [source-coverage.md](references/source-coverage.md): provenance and known
limitations.
Reusable assets and scripts:
- `assets/cinematic-brief.example.json`
- `assets/creative-acceptance.example.json`
- `assets/cinematic-scroll-controller.js`
- `scripts/validate-cinematic-brief.mjs`
- `scripts/validate-creative-acceptance.mjs`
- `scripts/higgsfield-preflight.mjs`
- `scripts/test-cinematic-regressions.mjs`
- `scripts/render-cinematic-prompt.mjs`
- `scripts/prepare-scroll-media.sh`
- `scripts/validate-scroll-media.mjs`
## Completion report
Report the selected direction, media tier and truth mode; references/provider,
model/settings, attempts and credits; files changed; QC and browser evidence;
fallbacks; unresolved visual inference; and private, staged or production
release status.