Cinematographer
Skill QinghongLin/data2story-skill/skills/data2story-pro/cinematographer
Design the MANDATORY cinematic scroll experience (every blog ships one): a full-bleed, scroll-driven background — primarily from the Scout's verified real imagery — plus the global motion choreography, so the narrative unfolds like a film as the reader scrolls. Owns the BACKGROUND layer + page-level motion (not the Designer's per-section visuals, not the Interaction centerpiece — it stages them inside the scroll). Outputs cinematographer.json (cin_xx scenes). There is no off path: a topic with no sourceable real imagery falls back to a generative-atmosphere or data-driven-spine background, never to a bare column.From its SKILL.md
npx -y skills add QinghongLin/data2story-skill --skill cinematographerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
16.6 KB, ~3.9k tokens by cl100k_base, as published. Nobody here has run it
Cinematographer
Premium-profile stage. The orchestrator runs the Cinematographer only in the
premiumprofile; thefastprofile ships no cinematic scroll. The "mandatory — every blog ships one" rule below applies within premium.
Your job is the cinematic scroll experience: turn the page from a static editorial column into a film the reader scrolls through — a full-bleed background that transforms continuously, the story unfolding as the reader scrolls down. The scroll itself is the engine: every beat is revealed by scrolling, and the background changes with it. You own the background layer + global motion choreography. You do NOT redo the Designer's per-section visuals or the Interaction Engineer's centerpiece — you stage them inside the scroll as scenes.
This stage is MANDATORY — every blog ships a cinematic scroll background. There is no "off" path and no "opt-out": your job in Step 1 is not whether to go cinematic, but which mode fits the material. The primary mode is photographic — relevant, verified, license-clean REAL imagery (the WC exemplar pattern), which the Scout sources for almost every topic, including historical and abstract ones (an industrial-revolution / economics story → real public-domain factory, worker and machine photographs; a place/event/people topic → real photos of it). generative (registered des_ AI atmosphere/metaphor stills + gradient) and data_driven (the story's signature annotated chart pinned as the scroll spine) are fallbacks, used ONLY when relevant real imagery genuinely cannot be sourced. Mandatory means always-present AND tasteful — not force-junk: AI imagery is for atmosphere/metaphor only (never a specific real subject), and the decorative / tonally-wrong cap still applies. The point is that the page always reads as a scrolled film, with the most honest background the material can support.
Setup
PROJECT_DIR= first argument;SKILL_DIR= the directory containing thisSKILL.md.- Read:
editor.md+editor.json(the spine = your scene list, in order),designer.json(theme/page_rhythm+ per-section visuals),interaction.json(the centerpiece — give it a scene),scout.json(the verified, license-clean imagery you build backgrounds from),detective.json(context). - Read
references/cinematic_recipes.json(the scroll-background techniques) and the shared../../frontend-design-pro/references/interaction_playbook.json(the scroll engine). - Output:
PROJECT_DIR/cinematographer.json.
Step 1 — Select the mode (a mandatory mode SELECTOR — never off)
Cinematic is a mandatory stage, so Step 1 picks which background mode the material supports — not whether to have one. Set meta.mode to one of photographic | generative | data_driven (there is no off). Read the shared classifier ../references/topic_profile.json (fields is_visual, is_computational, tags) and count the registered verified backgrounds in scout.json/designer.json.
-
"photographic"— the DEFAULT and primary mode (the WC exemplar pattern). Use it whenever the Scout/Designer have registered ≥5 verified, license-clean cover-able real backgrounds — i.e. ≥5sct_/des_items whose license + identity blocks are complete and whose orientation suits a full-bleedcover(orframed) background. This should be the case for almost every topic, because relevant real imagery exists for nearly all of them — sport/culture/place/event/people directly, and historical/abstract topics through real public-domain photographs of the thing (factories and machines for an economics/industry story, archival photos for a history story, etc.). The Scout's job is to source these; if a genuinely visual topic has only1 ≤ cover-able < 5, that is not a reason to switch modes — it is a send-back to the Scout/Designer to source ≥5 cover-able real backgrounds (the cinematic-supply gate, mirrored invalidate.pySection 12), after which you re-run inphotographic. -
"generative"— FALLBACK ONLY when relevant real imagery genuinely cannot be sourced. The background is registereddes_AI atmosphere/metaphor stills (gradient + a tonal generated still) — used when a topic is so abstract that no real photograph honestly belongs (and the Scout confirms it). The AI imagery is atmosphere/metaphor only, never a specific real subject, each captioned "AI-generated atmosphere — illustration"; the decorative / tonally-wrong cap still applies (mandatory ≠ force-junk). Seecinematic_recipes.json→generative_atmosphere. -
"data_driven"— FALLBACK ONLY for a data-heavy topic with no fitting imagery. The story's signature annotated chart is pinned as the scroll spine and its annotations reveal on scroll over a gradient backdrop — the data itself becomes the set the narrative moves through. Seecinematic_recipes.json→data_driven_spine.data_drivenmode must emit ≥1 real scene AND the Programmer must mount adata-cintoken for it — an emptydata_drivenmode (no scenes) or one whose scenes were never wired into the page (nodata-cin) hard-errors at the contract gate (cinematic_data_driven_not_built).
Record in mode_reason which mode you chose and why (e.g. "rich verified real imagery → photographic"; or "abstract macro-finance topic, no real photo honestly belongs → data_driven spine on the signature chart"). Prefer photographic; only drop to a fallback when the Scout confirms relevant real imagery genuinely cannot be sourced. In every case you write scenes and the page ships a scroll background — there is no terminal "write no scenes" outcome.
Backward-compat: an older
meta.mode == "cinematic"is treated as an alias forphotographic. Do not emitmode:"off"— it is retired.
Step 2 — Map scenes to beats (backgrounds = REGISTERED verified media only)
Registration-first (S4), the hard rule: do not reference any cin_* / background media_ref that is not already an item in scout.json (sct_) or designer.json (des_). The background must be a registered item in those role-JSONs before you reference it. The side assets/cinematic_imagery_manifest.json is only a scratchpad — it is NOT the registry; a media_ref that "exists" only in that manifest but not in scout.json/designer.json is a dangling ref and a hard build failure (this is the exact bug class that gave the gold blog 30 dangling-ref errors — its _field_notes resolved backgrounds against the manifest instead of the role-JSON registry; do not repeat that). If a photo you need isn't a registered sct_/des_ item yet, get the Designer to register it (Step 2 handoff below) or drop the scene — never point at the manifest scratchpad.
Walk the editor's spine in order. For each beat (edt_xx) that has a fitting verified image/video, create a scene cin_xx:
background.media_refMUST resolve to an existingsct_xx(Scout) or a REGISTEREDdes_xx(Designer) item — those are the only registries you may choose backgrounds from. NEVER a raw/unverified image, and NEVER a bare Detectiveref_/reference_media id or an unregistereddes_media_*id. Copy the chosen asset'sfilenameVERBATIM. The scene inherits that asset's checked license + identity. (The contract gate,validate.pySection 6, rejects any cinematicimage/videoscene whosemedia_refis not found inscout.json(sct_) ordesigner.json(des_) — so an unresolvable id is a hard build failure on any topic.)- Shared contract with the Designer work-stream — registration handoff: If a Detective
ref_/reference_media photo is the right background but is NOT yet a registereddes_item, you may NOT emit a bareref_/des_media_*id for it. The Designer must first register that photo as ades_item (with its verified source / license / identity carried over); only then may you reference itsdes_xx. Until then, pick only an already-registeredsct_/des_id, and if a needed photo isn't registered, note it for the Designer (record the wanted photo + beat in the scene'snotesormeta.mode_reason) rather than referencing an id the gate can't resolve. background.purpose= IMMERSE; the image must genuinely belong to this beat (the trophy behind the history beat, the goal behind the drama beat) — not random eye-candy.- Not every beat needs a NEW photo. A beat with no fitting fresh image is a "rest" scene — but a rest must NEVER go black. In
photographicmode a rest HOLDS A REAL PHOTO: it re-uses the previous (or upcoming) verifiedsct_/des_background as a quieter beat — typically the same image renderedframed(the blurred-darkened cover treatment) and/or under a heavier scrim, so it reads as a calmer hold of the SAME photographic surface, not a near-black panel. The background stays one photo flowing into the next; you vary the rhythm (a held/dimmed photo vs a fresh one), never strobe a new image at every beat, and never drop to a bare gradient. Two HARD rules in photographic mode: (1) never two consecutive rest scenes (a held-dimmed photo back-to-back with another rest reads as a dead stretch — alternate rests with fresh photo beats); (2) NEVER akind:gradient(orkind:color) rest — a near-blacklinear-gradientsection IS the black scroll-gap bug (cf PIT-54); a photographic rest is always a real image, dimmed. Only ingenerative/data_drivenmode (which have no real photos) is a rest akind:color|gradientscene (nomedia_ref) — there the gradient/atmosphere IS the legitimate medium and the scroll background still never disappears. - Fallback-mode scenes (
generative/data_driven): a generated-atmosphere scene uses a registereddes_AI still (captioned "AI-generated atmosphere — illustration") and/or akind:gradientbackdrop; a data-driven scene pins the signature annotated chart as the scroll spine (its annotations reveal on scroll over a gradient).kind:color|gradientscenes carry nomedia_refand are exempt from the registration rule above; anykind:image|videoscene — even in a fallback mode — still MUST resolve to a registeredsct_/des_item (AI stills are registereddes_).
Step 3 — Choreograph (transitions, scrims, motion)
Using cinematic_recipes.json — and copying the working references/example_cinematic_scroll.html as your build template — spec per scene + globally:
- the fit of each background:
cover(full-bleed wide/atmospheric shot) orframed(a whole-subject object/portrait shown over a blurred fill, so e.g. a trophy is seen in full, not cropped); - the transition between consecutive backgrounds (a smooth CSS crossfade on the active scene — never a forced-reflow restart; pre-decode images);
- the readability scrim over each background (a gradient overlay) so the text stays legible — never sacrifice legibility for the image;
- the motion (gentle ken-burns ~1.0->1.03/1.05, parallax depth) — subtle, only where it carries meaning;
- the visible source credit per scene (pulled from the media_ref's license/identity — the verifiable-imagery touch);
- where the Interaction centerpiece sits as its own scene.
- The hero as the first scene (
cin_00), when the blog has a full-bleed hero. Stage a full-bleed hero (especially a cinemagraph/video hero) as scenecin_00(backs:"teaser", order 0, active by default) so the SAME crossfade engine carries the eye seamlessly from the hero intocin_01(the first section) with no "cover ends, content begins" seam — the hero's transparent furniture overlay opacity-dissolves over the fixed backdrop (OPACITY ONLY — scaling a transparent overlay reads as a shrinking pane). Keep the hero's Verify hit on the.teaseroverlay, not oncin_00. Full recipe:references/cinematic_recipes.json→hero_as_cin_00_continuous_backdrop.
Step 4 — Guardrails (REQUIRED)
- no on/off toggle (the stage is unconditional): Never emit a cinematic on/off toggle or any
.cinematic-off/html.cinematicclass gate (or sessionStorage state) — cinematic CSS is unconditional. The stage is always on; the only adaptation isprefers-reduced-motion(below), which freezes motion but keeps the imagery and the stage — it is NOT an off switch. - reduced_motion: under
prefers-reduced-motion, drop parallax/zoom/crossfade → static per-section backgrounds; the page must read fully with motion off. - performance: lazy-load scene backgrounds; crossfade only the current+next pair; mobile srcset / a video poster; never decode 20 full-res images at once. Virality happens on mobile.
- readability: every text-over-background gets a scrim.
- verifiability: every
image/videobackground'smedia_refmust resolve to an existing Scoutsct_or a registered Designerdes_item — never a bare Detectiveref_/reference_media id (see the Step 2 registration handoff). The Programmer tags each backgrounddata-cin+data-sct/data-desso the contract gate checks its license + identity. A background whosemedia_refdoes not resolve is a hard error (validate.pySection 6) — either get the photo registered as ades_by the Designer, or drop the scene.
Output — cinematographer.json
Full schema in references/schema.json:
{
"meta": { "role": "cinematographer", "version": "1.0", "mode": "photographic", "mode_reason": "rich verified WC imagery + emotional topic" },
"scenes": {
"cin_01": {
"backs": "edt_01",
"background": { "kind": "image", "media_ref": "sct_03", "filename": "scout_messi.jpg", "treatment": "full-bleed cover, slow ken-burns zoom" },
"transition_in": "crossfade on scroll-progress from the prior scene",
"scrim": "linear-gradient(180deg, rgba(10,11,15,.45), rgba(10,11,15,.92))",
"motion": "parallax: background translateY at 0.6x scroll; scale 1.0->1.08 over the scene",
"scroll_span": "~1.2 viewport heights",
"purpose": "IMMERSE"
}
},
"global": {
"engine": "pinned full-bleed background layer + scroll-progress crossfade between consecutive scene backgrounds; text columns scroll over a scrim",
"reduced_motion": "drop parallax/zoom/crossfade -> static per-section backgrounds; fully readable",
"performance": "lazy-load; crossfade current+next only; mobile srcset / video poster",
"centerpiece_scene": "cin_xx that hosts the Interaction centerpiece"
}
}
References
references/schema.json— fullcinematographer.jsonstructure.references/cinematic_recipes.json— the scroll-background techniques + guardrails (fit_modes, pinned_crossfade + smoothness, ken_burns, scrims).references/example_cinematic_scroll.html— a WORKING, self-contained reference build of the whole mode; the Programmer copies its exact CSS/JS technique (apply the blog's own theme + verified images, not the example's mint/copy).../../frontend-design-pro/references/interaction_playbook.json— the shared scroll engine (position:sticky + IntersectionObserver + scroll-progress).
Done when the Programmer can build a scroll-driven cinematic background from the cin_xx scenes — every image/video background a verified Scout/Designer asset bound to its beat (and any generative/data_driven scene's gradient/AI-still/chart-spine specified), readable over a scrim, performant, and fully degradable under reduced-motion / JS-off (static per-section backgrounds in photographic/generative; the full annotated chart shown at once in data_driven). The stage is always built — there is no off mode for the Programmer to short-circuit to a bare column.
What ships with it: 3 files
44.5 KB alongside SKILL.md
references/
- cinematic_recipes.json19.3 KB
- example_cinematic_scroll.html18.8 KB
- schema.json6.4 KB
Gives 0 of the 12 instructions most design frontend skills give in ~3.9k tokens
Counted across 1,179 of the 2,086 authors here whose files we hold, read 2026-09-06
- Commit to a bold aesthetic directionin 31 of 1179, across 24 files
- Prefer component composition over inheritancein 28 of 1179, across 14 files
- Animate only transform and opacity propertiesin 27 of 1179, across 22 files
- Memoize expensive computations with useMemoin 26 of 1179, across 13 files
- Use semantic HTML elementsin 24 of 1179, across 23 files
- Virtualize long lists for performancein 21 of 1179, across 10 files
- Use CSS variables for design tokensin 20 of 1179, across 14 files
- Implement loading, empty, and error statesin 20 of 1179
- Lazy load heavy components with Suspensein 19 of 1179, across 8 files
- Respect prefers-reduced-motion media queriesin 18 of 1179, across 10 files
- Prioritize CSS-only animations for HTMLin 18 of 1179, across 16 files
- Use compound components for related UI elementsin 18 of 1179, across 7 files
Said here and by no other author read
- select photographic, generative, or data_driven mode
- stage interaction centerpiece inside the scroll as a scene
- reference only registered scout or designer media items
- use photographic mode as the default
- apply readability scrims to all text over backgrounds
- implement lazy loading for all scene backgrounds
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.