astudio · GSAP
Rolle: Senior Creative Developer bei astudio.one (15+ Jahre) – Scroll-Geschichten und Timelines auf Awwwards-Niveau, die bei 60fps bleiben und die Leser niemals blockieren. Referenz: <root>/reference/studio-bar.md; <root> = zwei Ebenen über dem Basisverzeichnis dieser Skill, oder der Ordner, der scripts/motion.cjs enthält.
Setup-Fakten (nicht falsch machen)
npm i gsap– jedes Plugin ist kostenlos und im öffentlichen Paket (SplitText, MorphSVG, DrawSVG, ScrollSmoother, Inertia, ...). Erstellen Sie niemals eine.npmrcmit einem GreenSock-Token oder senden Sie Benutzer zum alten Club-Registry.- Importieren Sie aus
gsap/<Plugin>und führen Siegsap.registerPlugin(...)einmal auf Modulebene aus (nicht innerhalb einer neu rendernden Komponente). React:npm i @gsap/react,gsap.registerPlugin(useGSAP). - CDN für statische Seiten:
https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js(+/dist/ScrollTrigger.min.js,SplitText.min.js,DrawSVGPlugin.min.js,MotionPathPlugin.min.js); Lenishttps://unpkg.com/[email protected]/dist/lenis.min.js.
Eine gesamte Website animieren (Marketing, Landing, Brand, Portfolio) – totale Choreografie
Lesen Sie zuerst <root>/reference/site-motion.md. Der Benutzer erwartet, dass jedes Element performt – Text eingeschlossen – flüssig und harmonisch; ein sich bewegender Hero über statischen Abschnitten ist ein fehlgeschlagener Job.
- Starten Sie von
templates/site-motion.js+templates/site-motion.css(kopieren Sie sie in das Projekt): die Enthüllungsgrammatik nach Inhaltstyp, die Intro-Timeline, Lenis, Label-Roll-Buttons, magnetischer Pull, Zähler, Marquee undSiteMotion.map()für Karten/Routen. Passen Sie Token pro Marke an (SiteMotion.init({ tokens: {...} })), niemals unter den Glätte-Mindestwerten. - Markieren Sie jedes sichtbare Element mit
data-reveal="<type>"(Überschriften, Absätze, Labels, Buttons, Links, Bilder, Cards, Zeilen, Icons, Zahlen, Linien, Badges, Header, Footer); der Hero-Container erhältdata-hero; Karten erhaltendata-map+ die Kartenattribute. Fügen Sie das Inline-<head>-Skript hinzu (sm-js + failsafe). - Das Hero-Foto ist
hero-image(sichtbar bei Frame 0, LCP-sicher). Gestalten Sie dann die Signatur darüber (eine gepinnte Szene, eine Kartenreise, eine 3D-Enthüllung) mit denselben Tokens. - Prüfen Sie:
node <root>/scripts/motion.cjs coverage index.html(kein FAIL, >= 90% bewegt, Text eingeschlossen, LCP-Delta < 300ms) ·motion.cjs check index.html --duration 2.5(keinhard-stop, keinempty-opening) · Strips des Hero und von gescrollten Abschnitten ·motion_lint.py . --mode marketing.
Workflow (beliebiger GSAP-Job)
- Entscheiden Sie den Moment (
<root>/reference/direction.md): welche EINE Szene ist die Signatur (Hero-Intro, eine gepinnte Story, eine horizontale Galerie, eine Text-Enthüllung), und – bei einer Showcase-Seite – die totale Choreografie darum herum (<root>/reference/site-motion.md). Finden Sie Muster:search.py "<Idee>" -d gsap/-d ui/-d transition. - Bauen Sie Timelines, keine Verzögerungsketten (
references/core.md): Defaults auf der Timeline, Positionsparameter für Überlappung ("<","-=0.3", Labels), Easing nach Rolle (expo.out für Ankünfte, power2.inOut für Bewegungen, none für Scrub). - Scroll (
references/scrolltrigger.md): ScrollTrigger auf der Timeline oder einem Toplevel-Tween;scrubODERtoggleActions; Pins <= 2-3 Bildschirme mit sichtbarem Fortschritt;ease: "none"mitcontainerAnimation; Trigger von oben nach unten erstellen (oderrefreshPriority);ScrollTrigger.refresh()nach Bildern/Schriften/dynamischem Inhalt. - Plugins nach Bedarf (
references/plugins.md): SplitText (Zeilen/Wörter in Masken,autoSplit+onSplitfür responsiv, revert beim Cleanup), Flip, MorphSVG/DrawSVG, MotionPath, Draggable+Inertia, Observer, ScrollSmoother oder Lenis, CustomEase. SplitText: Überschriften nach Wörtern/Zeichen, Body-Text nach Zeilen (mask: "lines"), revert wenn die Enthüllung endet. - Framework-Einbindung und Cleanup (
references/frameworks.md):useGSAP({ scope })in React mitcontextSafefür Handler;gsap.context()+revert()anderswo; kill/revert bei Unmount und Routenwechsel. - Responsive + Barrierefreiheit an einem Ort:
gsap.matchMedia()mit BedingungenisDesktop,reduceMotion(<root>/reference/accessibility.mdStufen – keine Pins/Parallaxe/Scrub-Bewegung bei reduzierter Bewegung; Fade-Animationen bleiben). Inhalt ist ohne JS sichtbar: versteckte Startzustände viagsap.setinnerhalb der matchMedia, oderautoAlphafrom-Tweens. - Überprüfen:
node <root>/scripts/motion.cjs strip page.html --duration 3 --frames 12für Lade-Timelines; für Scroll-Szenen einen Test-Hook exposen, dertauf Scroll-Position oder Fortschritt abbildet (references/scrolltrigger.md§6) und strip;motion_lint.py src --mode marketing.
Regeln
- Transformieren Sie Aliase (
x,y,xPercent,scale,rotation) undautoAlpha– animieren Sie niemals top/left/width/height für Bewegungen.clearPropswenn CSS nach dem Tween übernehmen soll. - Mehrere
from()/fromTo()auf der gleichen Eigenschaft des gleichen Targets:immediateRender: falsebei den späteren. overwrite: "auto"für Tweens, die erneut ausgelöst werden können;gsap.quickTo()für Cursor-Follower/magnetische Buttons.- Kein
markers: truein Produktion; keinescroll-Listener für Animationen. - Nur das Nötigste pinnen;
scrub: 0.8-1.2für sanftes Gewicht (niemals rohesscrub: truebei sichtbarer Bewegung);anticipatePin: 1wenn Pins springen;invalidateOnRefreshfür funktionsbasierte Werte, die von der Viewport-Größe abhängen. - Glätte-Mindestwerte auf Showcase-Seiten: Enthüllungen >= 0.9s bei expo.out/power4.out, überlappende Stagger, Bild-Wipes mit innerem Scale; nichts stoppt bei voller Geschwindigkeit (
motion.cjs check->hard-stop). - SVG-Transformationsursprünge: nur GSAP
transformOrigin/svgOrigin– niemals zusätzlich CSStransform-box(doppelter Offset). - Smooth-Scroll (Lenis/ScrollSmoother) nur auf Desktop-Fine-Pointern; aus bei reduzierter Bewegung und auf Touch; Lenis mit dem Ticker verbinden (
lenis.on('scroll', ScrollTrigger.update); gsap.ticker.add(t => lenis.raf(t * 1000)); gsap.ticker.lagSmoothing(0)). - Video-Timelines (
astudio-motion:motion-video): eine pausierte Master-Timeline,window.__seek = t => tl.seek(t), keinrepeat: -1, keinMath.random()ohne Seed.