scroll-cinema
Skill1 starsChanged 4 months agoMITView on GitHub
Build scroll-driven "scroll-cinema" websites where scrolling scrubs a camera path instead of translating a document — pinned full-viewport stages, aperture/iris opens, continuous dolly moves, 3D card entries, stacked panels that dim as the next slides over, parallax copy, and masked staggered text reveals. Pure vanilla JS + CSS custom properties, no GSAP/ScrollTrigger/Lenis/Locomotive/Framer. Use this whenever someone wants a "premium agency site", a cinematic or immersive landing page, a scroll-triggered or scroll-scrubbed animation, a pinned/sticky section that animates as you scroll, a hero that transforms on scroll, an Awwwards-style or "expensive-looking" site, a scrollytelling piece, or references a site/reel whose scrolling animation they want reproduced. Also use it when someone asks whether a particular scroll animation is buildable, or wants an existing scroll effect debugged (janky scrubbing, sticky not sticking, animation stuck at its start state).
3 other projects use a version of this.
Adopted by
Most recently taken up by
- forever8896/scroll-cinema-skillstheir own version, first seen Oct 25, 2026
- arturmuller25/claude-skillstheir own version, first seen Sep 29, 2026
- tdimino/claude-code-minoantheir own version, first seen Apr 16, 2026
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- tdimino/claude-code-minoan★ 41same name
- arturmuller25/claude-skills★ 0same name
- forever8896/scroll-cinema-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
We split this skill into the rules it gives an agent
1 rule. 0 are common, 1 is distinctive, and 0 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
1
Distinctive
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 31
Every stage is a tall section with a sticky child.
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Scroll-cinema
Sites where the wheel drives a camera rather than the document. The whole genre reduces to one primitive — map scroll position to a number between 0 and 1, publish it as a CSS custom property, and let CSS do the rest — plus a catalogue of moves built on top of it.
Everything here is vanilla. Libraries are not needed for this and they cost you 40–100 KB plus a scroll-hijacking layer that fights the browser.
Start here
- Read
references/mechanics.mdfor the move catalogue with working code — aperture, dolly, parallax, 3D card entry, stacked panels, masked reveals, cycling readouts, progress rails. - Read
references/pitfalls.mdbefore you debug anything. It is a list of failures that look like logic bugs but are CSS-semantics or browser-lifecycle traps. Several cost real time to rediscover. assets/template.htmlis a complete working page using every mechanic — single file, no dependencies, dark/light themed, with a toggleable overlay that labels each move as it fires. Copy it and replace the content, or lift individual mechanics out of it.
The engine
Every stage is a tall section with a sticky child. The section's height is the scroll budget; the sticky child is what you actually see.
<section class="stage" id="s-hero" style="height:460vh">
<div class="pin"><!-- one viewport of content --></div>
</section>.stage{position:relative}
.pin{position:sticky;top:0;height:100svh;overflow:hidden}Progress is how far the section has travelled through its own scrollable span:
const r = stage.getBoundingClientRect();
const span = r.height - innerHeight; // scrollable distance
const p = clamp(-r.top / span, 0, 1); // 0 at entry, 1 at exit
stage.style.setProperty("--p", p.toFixed(4));Then carve p into overlapping phase windows and publish each one:
const sub = (p,a,b) => clamp((p - a) / (b - a), 0, 1); // remap a slice to 0..1
const ease = t => t * t * (3 - 2 * t); // smoothstep
stage.style.setProperty("--pOpen", ease(sub(p, 0.08, 0.42)));
stage.style.setProperty("--pShear", sub(p, 0.30, 0.46));
stage.style.setProperty("--pDolly", ease(sub(p, 0.38, 1.00)));CSS consumes them directly, because unitless custom properties compose in
calc():
.orb { transform: translate(-50%,-50%) scale(calc(.42 + var(--pDolly,0) * 9.4)) }
.copy { transform: translateX(calc(var(--pShear,0) * -130%))
skewX(calc(var(--pShear,0) * -9deg)) }Two things make this worth doing rather than reaching for a library:
- Overlapping windows are what create the "one continuous camera" feel.
--pShearfinishing at 0.46 while--pDollystarts at 0.38 means the headline is still leaving as the camera begins to move. Non-overlapping windows read as a slideshow; that is the single biggest quality difference between a cheap scroll site and an expensive one. - Keeping interpolation in CSS means the compositor handles it. Your JS writes a handful of strings per frame and touches no layout.
Drive it with one listener for the whole page, coalesced through rAF:
let queued = false;
function onScroll(){
if (queued) return;
queued = true;
requestAnimationFrame(t => { queued = false; layout(t); });
}
window.addEventListener("scroll", onScroll, { passive:true });
window.addEventListener("resize", onScroll);Budgeting stage height
Scroll budget is pacing. Roughly 100vh of section height buys one second of comfortable screen time on a trackpad.
- A single mechanic (a card entering, a headline resolving): 60–150vh
- A stage with 2–3 overlapping phases: 250–450vh
- Anything over ~500vh feels like the page has stopped responding
Multi-panel stages divide their budget evenly: three stacked panels in a 400vh stage get ~133vh each. If a panel feels rushed, lengthen the stage rather than compressing the other panels.
Workflow
- Storyboard first, in words. List the beats and what each one has to communicate. Motion that isn't carrying meaning is what makes these sites feel like showreels instead of sales tools.
- Build the engine and one stage. Get progress publishing correctly and
verify with a readout before adding a second mechanic — a wrong
spansilently pins everything at 0 or 1. - Layer the phases inside that stage, overlapping their windows.
- Add stages, then tune the height budget by actually scrolling it.
- Do the fallbacks last but do not skip them (see below).
Non-negotiables
Reduced motion needs a different layout, not faster animation. A scrubbed
page with its transitions set to 0.01ms is broken — sticky stages stack into
an unreadable pile. Fall back to normal document flow: skip the js class
entirely so stages become ordinary sections.
if (matchMedia("(prefers-reduced-motion: reduce)").matches) return;
document.documentElement.classList.add("js");:root:not(.js) .pin{position:relative;height:auto;min-height:100svh}
:root:not(.js) .panel{position:relative;transform:none;filter:none}
:root:not(.js) .reveal-line > span{transform:none;opacity:1;filter:none}This doubles as the no-JS path, so the page is readable before the script runs and if it never runs.
Only animate transform, opacity and filter. Anything touching
layout (width, top, margin) reflows every frame and the scrub will stutter.
Use 100svh, not 100vh, or mobile browser chrome crops every pinned
stage.
Text over bright art needs a scrim. A gradient overlay between the art and the copy, not a text-shadow. This is the most common legibility failure in the genre.
What this cannot give you
Be straight with people about this, because it is the thing they are usually
actually asking. The motion system is fully reproducible from a prompt. The
plates are not — the rendered 3D scenes, the shot photography, the colour
grade that holds across sections. Procedural atmosphere (gradients, caustics,
dispersion, flares, starfields — all in references/mechanics.md) gets you a
long way and costs kilobytes instead of megabytes, but it is a different look
from rendered artwork, not a substitute for it.
The other half is art direction: which scenes, in which order, and the judgement to cut one. A coding agent builds the camera. It does not decide where to point it.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

