Scroll-driven presentation decks: one stage, one continuous timeline, and moves that turn one element into the next.
한국어 · Getting started · Claude Code skill · Architecture
You write a deck.yaml. Scrolline lays every beat on one paused GSAP timeline, the mouse wheel scrubs it, presenter keys jump between stops, and the same timeline renders to MP4.
- v1 reused 12 scene templates, so every deck read as the same deck with new pictures. v2 has no scenes: a deck is one continuous master timeline on one stage.
- Beats hand off instead of cutting. A link move carries part of one beat (a bar, a dot, a date) into the place it holds in the next beat, so the audience follows one object rather than a slide change.
- Each concept has its own motion grammar. A concept pack fixes the camera axis, timing and allowed moves, and names signature moves the deck must use. The six example decks move differently because their grammars differ.
Adding video? Issue your own Pexels or Pixabay API key first and keep it in
.env(git-ignored, blocked bynpm run check). See docs/media.md.
Six decks, one per concept. Decks marked sample use a fictional company and say so on screen. The others use real data with a source list in deck.yaml.
| Deck | Concept | Typical use | Signature moves |
|---|---|---|---|
rail-ai-decade · Generative AI, 2017 to 2026 |
rail · horizontal time rail |
company history, roadmap, an industry's decade | rail-advance era-shift counter-handoff |
data-ev-shift · How far the EV shift has come |
data · data journalism |
quarterly results, market analysis | dot-multiply mark-morph annotation-pin |
launch-orbit-note · Minute product launch (sample) |
launch · product launch |
product or feature launch | lit-from-dark sticky-scrub-link number-slam |
zoom-root-cause · Q3 revenue diagnosis (sample) |
zoom · infinite zoom drill-down |
root cause, TAM-SAM-SOM, org structure | zoom-dive zoom-surface depth-ladder |
canvas-pitch · Seed pitch on a map (sample) |
canvas · camera flythrough |
pitch deck, strategy map, process | arc-flight establish-crane atlas-pullback |
kinetic-next-word · How AI writes an answer |
kinetic · kinetic type lecture |
lecture, keynote, statement | word-door slot-pick phrase-fold |
The decks are in Korean. See docs/concepts.md for what each concept allows.
Requires Node.js 22 or newer. ffmpeg is needed only to cut frame sequences, and the HyperFrames CLI (fetched by npx) only to export MP4.
git clone https://github.com/gongnyang/awesome-html-scrolline-deck.git
cd awesome-html-scrolline-deck
git checkout v2
npm install
npm run devOpen http://localhost:5173/decks/rail-ai-decade/ and scroll, or press →.
Start your own deck from a concept:
npm run deck -- new my-review --concept data # decks/my-review/{deck.yaml,index.html,main.js,assets/}
# write beats in decks/my-review/deck.yaml
npm run deck -- plan my-review # stops and timings, computed in node
npm run export -- my-review # out/export/my-review.mp4The full walkthrough is in docs/getting-started.md, and every deck.yaml field is in docs/writing-a-deck.md.
- id: b-trend
type: chart
kind: bar
categories: ["Q1", "Q2", "Q3"]
series:
- { name: "Revenue ($M)", values: [3.1, 3.6, 4.2] }
title: "Each quarter added about $0.5M"
states:
- name: steps
notes:
- { index: 1, text: "+0.5" }
- { index: 2, text: "+0.6" }
place: { slot: full }
steps:
- { name: steps, move: annotation-pin } # a stop after the stepBeats hold content and moves hold motion. A beat renderer draws only the finished state. The concept supplies default moves, and each beat can name its own enter, exit, link, steps, camera or ambient move.
flowchart TD
site["site/ (gallery)"] --> decks
decks["decks/<id>: deck.yaml, main.js, assets/, sequences/"] --> concepts
concepts["concepts/<id>: concept.json, tokens.css"] --> moves
moves["moves/<family>/<id>.js: enter, exit, link, step, camera, ambient"] --> engine
engine["engine/: stage, plan + build, scroll, presenter, handoff, media, export"]
tools["tools/: cli, check, export, capture, smoke"] -.-> decks
tools -.-> engine
- engine knows nothing about content. It renders beats, plans the timeline in node (no DOM), builds the master timeline, drives it from scroll and keys, and exports.
- moves are small units of motion with a fixed contract: pure
timing, deterministicbuild, notl.from, no clock orMath.random. Each move ships with a test. - concepts pick a camera axis, timing, eases, tokens and an allow list of moves.
- decks are data plus assets. Deck-only scenes go in
sequences/.
Imports only go downward, and npm run check blocks upward imports, cycles and imports across sibling folders. See docs/architecture.md.
| Key | Action |
|---|---|
| → ↓ Space PageDown | next stop |
| ← ↑ Shift+Space PageUp | previous stop |
| Home End | first, last stop |
| b . | blackout |
| f | fullscreen |
The wheel and the keys move the same scroll position. A key press travels to the next stop in 0.9 to 2.6 s, depending on distance. With reduced motion, or with ?motion=reduce, the jump is instant and moves fall back to fades of the same length, so every stop lands at the same time.
| Need | How | Beat |
|---|---|---|
| Video that scrubs with the scroll | image sequence drawn on a canvas, cut with npm run frames |
type: video, mode: scrub |
| Live footage inside a beat | <video muted playsinline> that plays while the beat is active |
type: video, mode: play or loop |
| Video inside letters or a shape | text mask applied by a move (mask-word-in), or a clip-path shape |
mask: { type: text, text: "10년" } |
Scrubbed video uses frames rather than video.currentTime so that seeking is exact in both directions on every browser. See docs/media.md.
npm run export -- rail-ai-decade # out/export/rail-ai-decade.mp4
npm run export -- rail-ai-decade --dry-run # print the timeline map and path only
npm run capture -- rail-ai-decade --stops # one PNG per stop in out/capture/rail-ai-decade/Export replaces scrolling with a presentation path. It travels from stop to stop, holds 1.6 s on each one (exportHold per beat), and renders the paused timeline through HyperFrames at 1920×1080. Because the timeline depends only on time, the MP4 shows the same frames as the browser. See docs/export.md.
npm test # vitest + happy-dom: engine modules, every move, every deck
npm run check # dependency rules, a test next to every module, state schemas, move static rules
npm run ci # both; the merge conditionMove tests run a shared contract check: seek determinism, rewind to the initial state, no blur or 3D under reduced motion, and handoff landing within 1 px. GitHub Actions runs npm ci, npm test and npm run check on every push to main and v2, and on every pull request.
SKILL.md makes this repository a Claude Code skill named scrolline-deck. It takes you from a brief to a concept, then deck.yaml, a smoke run and the MP4. Link the checkout into your skills folder:
ln -s "$PWD" ~/.claude/skills/scrolline-deckengine/ stage, timeline plan/build, scroll, presenter, handoff, media, export, beat renderers
moves/ move library by family (reveal, type, morph, camera, rail, data, media, assemble, emphasis)
concepts/ concept packs: concept.json + tokens.css
decks/ example decks: deck.yaml + main.js + assets/
tools/ cli, checks, export, capture, smoke, frame extraction
site/ gallery
docs/ guides
plan/ design source of truth (Korean): PLAN, ARCHITECTURE, CONTRACTS
state/ board.json + runs.jsonl build-state log
See CONTRIBUTING.md. In short, keep commits small, put a test next to every module, keep each commit to one hat (Hat: feature or Hat: refactor), and run npm run ci before a pull request.
Code: MIT © gongnyang.
- Motion sources. Every move lists the techniques it borrows from in
sources, using slugs from awesome-ai-motion. - References. Scroll stories and keynotes such as The Pudding, Our World in Data, The New York Times, Codrops and Apple product pages were studied for ideas only. No code or assets from them are included. See docs/attribution.md.
- Stock footage. Pexels License, credited per deck in
decks/<id>/assets/CREDITS.md. Other media was rendered for this repository. - Data. Each non-sample deck lists its sources, with access dates, in
deck.yaml. - Dependencies. Built on GSAP (GreenSock standard no-charge license), Lenis (MIT) and Vite (MIT). HyperFrames (Apache-2.0) renders the exports.
