Scroll-Bewegungsgrafiken
Eine Canvas-Zeitleiste, die durch die Scrollposition gesteuert wird: eine fixierte Bühne, Spulen, die reine Funktionen des Fortschritts sind, und Bildunterschriften, die die Zeichnung niemals berühren darf. Diese Methode betreibt die Story-Drum auf der ImuTechz-Startseite, die F&E-Drum und den Founder-Path-Film. Sie treibt auch die Fünf-Spulen-Demo in assets/demo.html an.
Die gesamte Technik passt in einen Satz. Die Scrollposition ist die einzige Uhr: Bilde sie auf p ∈ [0, 1] ab und mache jedes Pixel, jede Bildunterschrift und jede Rotation zu einer Funktion von p.
Wie es gut aussieht
- Es spult wie ein Video. Scrolle vorwärts und der Film läuft. Scrolle zurück und er spult Bild für Bild zurück. Anhalten in der Mitte hinterlässt ein Bild, das Sinn ergibt.
- Die Seite wird nie gekapert. Rad, Trackpad, Touch und Tasten bewegen die Seite genauso wie überall sonst. Der Abschnitt ist einfach nur hoch.
- Die Wörter sind immer lesbar. Bildunterschriften sind echter DOM-Text auf einer Karte. Die Zeichnung ordnet sich in dem Raum an, den die Bildunterschriften frei lassen, und die Leinwand wird als Sicherheitsnetz um sie herum beschnitten.
- Es ist eine Steuerung, nicht nur eine Show. Die Seiten einer Story-Drum sind Links. Ihre Schiene, Pfeiltasten, Pfeiltasten und Mausziehen suchen alle durch Scrollen der Seite, sodass Scrollen und Trommel niemals in Konflikt geraten können.
- Eine Seite im Leerlauf kostet nichts. Es wird kein requestAnimationFrame ausgeführt, sobald p zur Ruhe kommt oder der Abschnitt den Viewport verlässt.
- Reduzierte Bewegung wird respektiert. Kein Glätten, kein Trommel-Zwischenlauf und keine Animation zum Einblenden von Bildunterschriften. Der gesamte Inhalt ist trotzdem noch da.
- Es hält von 360 bis 1920 px Breite, in Hell und Dunkel, bei DPR 1 und 2.
Harte Regeln
- p kommt von der Scrollposition, niemals von einer Uhr. Verwende
performance.now(),Date, CSS-Animationen odersetIntervalnicht innerhalb einer Spule. Glätten (ein Lerp zum Ziel-p) ist erlaubt, weil es zum gleichen Bild konvergiert. - Eine Spule ist eine reine Funktion
draw(ctx, t, env). Sie speichert keinen Zustand zwischen den Bildern und ruft niemalsMath.random()auf; verwende stattdessen ein gesetzteshash(i). Gleiches (t, env) muss dieselben Pixel zeichnen. - Fixiere mit CSS, nicht mit JS. Verwende einen hohen Track (
position: relative; height: N×vh), der eineposition: sticky; top: 0; height: 100svh-Bühne enthält. Setze niemalsposition: fixedauf die Bühne, sperre niemals den Body und setze niemalsoverflow: hidden|auto|clipauf einen Vorfahren des Tracks. - Erfasse niemals Eingaben. Verwende kein
preventDefaultbei Rad oder Touch, keinoverflow: hiddenauf html oder body und kein Scroll-Snapping auf dem Track. Nur eine fokussierte Trommel darf Pfeiltasten behandeln, und sie tut dies, indem sie die Seite scrollt. - Suche durch Scrollen. Jeder Button, jedes Schienenelement, jede Taste und jeder Anchor ändert
window.scrollY. Setze niemals p oder eine Rotation direkt. Verwendebehavior: "instant"für programmatische Sprünge, die nicht animieren dürfen, weil"auto"dem CSSscroll-behavior: smootheiner Seite gehorcht. - Text lebt im DOM. Bildunterschriften, Titel und Links sind HTML. Canvas-Text ist auf dekorative Labels wie Jahre, Achsenstriche und Schrittnamen beschränkt.
- Messe Bildunterschriften in jedem Bild und halte die Zeichnung von ihnen fern. Jede Bildunterschrift und jedes HUD-Element ist ein Sperrbereich (
data-keep). Spulen layouten innerhalb vonenv.free, und die Engine schneidet die Sperrbereiche mit einem Even-Odd-Clip aus. - Zeige niemals zwei Bildunterschriften gleichzeitig an. Bildunterschriftenfenster sitzen innerhalb ihrer Spule mit einem Abstand an jeder Grenze, und Spulen blenden in diesem Abstand über.
- Die Schleife stoppt im Leerlauf. Starte rAF bei Scrollen oder Größenänderung nur, während der Abschnitt in der Nähe des Viewports ist (IntersectionObserver), und stoppe sie, wenn p dem Ziel entspricht.
- Die Canvas wird auf die Bühne bei
min(devicePixelRatio, 2)skaliert. RufesetTransform(dpr, …)einmal pro Bild auf und lösche es jedes Bild. - Farben kommen von CSS-Custom-Properties. Härte keine Hellmodus-Palette in eine Spule ein. Lese die Palette bei einer Änderung von
prefers-color-schemeneu ein. - Respektiere
prefers-reduced-motion: reduce. Verwende kein Glätten, lasse die Trommel von Seite zu Seite springen und schalte Animationen zum Einblenden von Bildunterschriften aus. Bilder folgen weiterhin dem Scrollen, weil der Benutzer sie steuert.
Aufbaureihenfolge
Führe es in dieser Reihenfolge durch. Jeder Schritt ist vor dem nächsten testbar.
- Inhalt zuerst. Schreibe die Kapitel: einen Aufmacher, einen Titel, ein oder zwei Sätze und einen optionalen Link für jedes. Wähle die Anzahl der Spulen (3 bis 7) und gib jeder etwa 80 bis 100 svh Scrollen.
- Track und Bühne. Füge den hohen Abschnitt mit einer klebrigen 100svh-Bühne darin hinzu und überprüfe, dass er ohne JS fixiert (siehe layout-and-captions).
- Die Scrub-Engine. Verdrahte
ScrollMotion.scruboderfilm(siehe engine) und protokolliere p. Überprüfe, dass es 0 am Fixierbeginn und 1 am Fixierende liest und dass es sich in beide Richtungen bewegt. - Bildunterschriften und HUD im DOM. Platziere sie pro Breakpoint, markiere sie mit
data-keepund lasse die Engine ihre Opazität von p aus steuern. - Spulen, eine nach der anderen. Schreibe
draw(ctx, t, env)innerhalb vonenv.free(siehe drawing) und scrolle sie vor und zurück, bevor du die nächste schreibst. - Bewegungsgrammatik. Füge Ein-, Halte- und Aus-Hüllkurven, Staffelungen, Verweilzeit und Überblendungen hinzu (siehe motion-grammar).
- Interaktivität, falls es eine Trommel ist. Füge Seitenlinks, die Schiene, Zurück- und Weiter-Buttons, Tasten und Ziehen hinzu, die alle durch Scrollen suchen.
- Leistungs- und Barrierefreiheitsdurchgang. Decke die Leerlaufschleife, DPR, reduzierte Bewegung, Fokusreihenfolge, Bildschirmlesegerät-Text und den Dunkelmodus ab (siehe performance-and-a11y).
- Verifiziere bei 360, 390, 414, 768, 1024, 1280, 1440 und 1920 mit dem headless-Skript (siehe verification). Bezeichne es nicht als fertig, bis alle Prüfungen bestanden sind.
Entscheidungs-Checklisten
Canvas-Film oder DOM/CSS-Transformationen?
- Viele kleine bewegliche Teile, Linien, die zeichnen, Partikel oder Diagramme → Canvas-Film (
ScrollMotion.film). - Eine Handvoll Karten, Bilder oder Texttafeln → DOM-Transformationen, gesteuert durch
scrub(die Trommel ist eine). - Echte 3D-Meshes oder Shader → dieses Skill reicht nicht. Verwende WebGL, behalte aber die Regeln 1 bis 5 und 9 bis 12 bei.
Fixier- oder Ansichtsmodus?
- Der Abschnitt soll den Bildschirm halten, während seine Geschichte abläuft →
mode: "pin"(hoher Track und klebrige Bühne). - Der Effekt reitet mit, während der Inhalt vorbeiläuft, wie bei Laufbändern oder Parallaxe →
mode: "view", ohne Fixierung.
Wie hoch ist der Track?
- Verwende
n × 80–100svh + 100svhfür einen Film undn × 70vh + 100vhfür eine Trommel. Wenn ein Testleser sagt, es sei „zu schnell“, erhöhe die Höhe. Verlangsame es niemals, indem du das Rad kaperst.
Wo kommen die Bildunterschriften hin?
- Desktop (≥ 760 px): neben der Zeichnung (linke oder rechte Karte) oder als breite untere Karte. Telefone: immer ein unteres Blatt, mit der Zeichnung darüber.
- Mit einem festen Site-Header setze
--sm-nav-h, damit das HUD und die Trommel es freihalten.
Braucht es die Trommel?
- Verwende die Trommel, wenn die Kapitel Dinge sind, zu denen ein Benutzer gehen möchte (Seiten, Produkte, Abschnitte). Ansonsten verwende den Film allein.
Fehlermodi und Behebungen
| Symptom | Ursache | Behebung |
|---|---|---|
| Bühne scrollt weg, anstatt zu fixieren | Ein Vorfahre hat overflow: hidden/auto/clip, oder die Bühne hat kein top | Entferne den Überlauf (verwende bei Bedarf overflow-x: clip auf dem Body) und setze top: 0 |
| Animation spielt nur vorwärts oder springt beim Zurückscrollen | Zustand, der über Bilder hinweg akkumuliert wurde, oder eine Uhr oder Math.random in einer Spule | Mache die Spule zu einer reinen Funktion von t; verwende hash(i) für Zufälligkeit |
| Zeichnung läuft unter die Bildunterschrift | Spule auf der gesamten Bühne angeordnet | Ordne in env.free an; behalte data-keep auf der Bildunterschrift; lasse die Engine clippen |
| Bildunterschriftenbox wird während des Überblendens an der falschen Stelle gemessen | getBoundingClientRect verwendet (enthält die Transformation) | Messe Layoutboxen (offsetLeft/Top/Width/Height, siehe boxIn) |
| Zwei Bildunterschriften überlappen sich an einer Grenze | Bildunterschriftenfenster berühren sich | Blende Bildunterschriften bei 1 − cross aus und bei cross ein; Spulen blenden in der Lücke über |
| Lüfter laufen auf einer Seite im Leerlauf | rAF-Schleife stoppt nie | Stoppe, wenn cur === target; schalte mit IntersectionObserver |
| Unscharfe Canvas auf Telefonen / langsam auf 4K | Canvas in CSS-Größe oder unbegrenztem DPR | Verwende width = W × min(dpr, 2) und setTransform(dpr, 0, 0, dpr, 0, 0) |
| Trommel und Seite sind sich nach Klicken auf die Schiene uneinig | Das Steuerelement hat die Rotation direkt gesetzt | Jedes Steuerelement ruft scrollToProgress auf; die Rotation kommt nur von p |
| Ziehen ruckelt, schnappt dann zurück | Seite hat scroll-behavior: smooth, also animiert scrollTo(x, y) | Verwende scrollTo({ top, behavior: "instant" }) während des Ziehens |
| Klicken auf eine Seite nach einem Ziehen öffnet deren Link | Der Klick, der das Ziehen beendet, feuert | Schlucke einen Klick in der Capture-Phase nach einem Ziehen, das sich um > 4 px bewegt hat |
| Mobiler 100vh-Sprung, wenn die URL-Leiste ausgeblendet wird | vh auf der Bühne | Verwende 100svh für die Bühne; berechne p mit der eigenen Höhe der Bühne |
| Dunkelmodus zeigt eine Hellmodus-Zeichnung | Hartcodierte Farben | Lese --sm-*-Tokens über readPalette; lese bei Schemawechsel neu ein |
| Rückseiten der Trommel scheinen durch | Fehlendes backface-visibility: hidden | Setze es mit dem -webkit--Präfix auf jede Seite |
| Vorschaubilder der Trommelseite in falscher Größe gezeichnet | Verwendete das projizierte Rechteck einer 3D-transformierten Seite | Größe nach clientWidth/clientHeight |
Dateien
- references/engine.md: p, die Scrub-Schleife,
film(), Suche, der React-Hook. - references/drawing.md: der Spulenvertrag, Canvas-Einrichtung, Routen, Pop-Ins, Partikel und Paletten.
- references/layout-and-captions.md: Track- und Bühnen-CSS, Sperrbereiche, das freie Rechteck, der Clip, das Trommellayout.
- references/motion-grammar.md: Hüllkurven, Staffelungen, Verweilzeit, Überblendungen, Tempo und Easing.
- references/performance-and-a11y.md: die Leerlaufschleife, Layoutkosten, reduzierte Bewegung, Tastatur, Fokus und Bildschirmlesegeräte.
- references/verification.md: die acht Breiten, das headless Brave/Chrome-Skript und der manuelle Durchlauf.
- assets/demo.html: eigenständig, keine Abhängigkeiten, Doppelklick zum Ausführen. Fünf Spulen und die Story-Drum.
- assets/scroll-motion.js: die Engine (
scrub,film,drum,scrollToProgressund Helfer), UMD. - assets/reels.js: fünf Beispielspulen (orbit, path, stack, wave, close) und
still()für Vorschaubilder. - assets/scroll-motion.css: Film- und Trommelstile, Hell- und Dunkel-Tokens.
- assets/ScrollFilm.jsx: der React-Wrapper für den Film, plus der
useScrub-Hook. - assets/StoryDrum.jsx: die React-Story-Drum, plus eine selbstrollende
DrumPreview. assets/preview-orbit.jpg,assets/preview-path.jpg,assets/preview-close.jpg: Standbilder der Demo bei 1440 × 900.
Beginne mit der Demo: Öffne sie, zeige den Quelltext an und ersetze den Inhalt. Die Verdrahtung am Ende der Datei umfasst etwa 60 Zeilen.