Video- & Prototyp-Bewegungsextraktion (video-to-gsap)
1. Zweck & Auslöser
Flüssige Mikrointeraktionen und filmische Bewegungen unterscheiden hochwertige E-Commerce-Erlebnisse. Schlecht implementierte Web-Animationen verursachen jedoch Thread-Blockaden, ausgelassene Frames (Ruckler), Speicherlecks und eine schlechte Interaction to Next Paint (INP). Dieses Skill steuert die Extraktion und Implementierung von butterweichen 60/120 FPS Animationen.
Auslöser:
- Wenn der Benutzer einen Videoclip, ein GIF oder ein Figma-Bewegungsprototyp bereitstellt.
- Beim Animieren von Warenkorb-Slide-Overn, Seitenübergängen, Akkordeon-Expandern, Produktkarten-Hover-Effekten oder Checkout-Abschluss-Animationen.
- Beim Erstellen von scrollgesteuerten Animationen mit ScrollTrigger.
2. Bewegungsdekonstruktionsprotokoll
Beim Analysieren eines Bewegungsclips systematisch identifizieren:
- Die Choreografie-Sequenz:
- Bühne / Auslöser: Welche Aktion startet die Bewegung (Hover, Scrollen, Routenwechsel, Klick)?
- Antizipation: Gibt es eine subtile Gegenbewegung vor der primären Bewegung?
- Aktion & Verschiebung: Welche Elemente bewegen sich, in welche Richtungen, über welche Entfernung (px, rem oder %)?
- Beruhigung & Nachlauf: Überschwingt es (Spring/Elastic) oder verlangsamt es sich sanft (
power3.out,expo.out)?
- Zeitliche Aufschlüsselung:
- Dauer jedes Elements (z.B. Drawer-Eingang:
450ms, Hintergrund-Einblendung:300ms). - Staffelungsabstand zwischen gestaffelten Kindern (z.B. Produktgitter-Karten:
0.06sStagger).
- Dauer jedes Elements (z.B. Drawer-Eingang:
- Easing-Signatur:
- Linear: streng für kontinuierliche Schleifen (z.B. Laufschrift).
- Ease-out (
power2.out,expo.out): für UI-Eingänge (schneller Eintritt, sanftes Absetzen). - Ease-in (
power2.in): für UI-Ausgänge (beschleunigt aus dem Bildschirm). - Ease-in-out (
power3.inOut): für Zustandsänderungen, die im Sichtfeld bleiben.
3. Leistungs- & Hardwarebeschleunigungsstandards
Regel 1: Nur Composite-Eigenschaften animieren
- Erlaubt:
transform(x,y,xPercent,yPercent,scale,rotation,skew) andopacity(oder GSAPautoAlpha). - Streng verboten: Animieren von Layout- oder Paint-Eigenschaften (
width,height,top,left,right,bottom,margin,padding,border-width). Diese zwingen den Browser-CPU, bei jedem Frame die Layout-Geometrie neu zu berechnen und Pixel neu zu zeichnen, was zu INP-Verschlechterung und ausgelassenen Frames führt.
Regel 2: Keine Speicherlecks mit scoped useGSAP
- Immer das offizielle
@gsap/react-Paket und denuseGSAP-Hook verwenden. - Einen
scope-Container-Ref bereitstellen. Jeder Selektor wird automatisch gescoped und alle Timeline-, Tween- und ScrollTrigger-Instanzen werden beim Aushängen der Komponente sauber zurückgesetzt und zerstört. - Dies verhindert Zombie-Event-Listener und Speicherrückstände in Single Page Apps und React 19 Fast-Refresh-Zyklen.
Regel 3: FOUC (Flash of Unstyled Content) vermeiden
autoAlphaanstelle vonopacityverwenden.autoAlphasetztvisibility: hidden, wenn die Opazität 0 erreicht, und verhindert so Geisterklicks und Rendering-Flashes vor der Hydratation.- Alternativ CSS-Standard-Ausblendungszustände deklarieren und mit
gsap.fromTosichtbar machen.
4. Produktionsimplementierungs-Blueprint
"use client";
import { useRef } from "react";
import gsap from "gsap";
import { useGSAP } from "@gsap/react";
import { ScrollTrigger } from "gsap/ScrollTrigger";
// Registrierung der Plugins sicherstellen
if (typeof window !== "undefined") {
gsap.registerPlugin(useGSAP, ScrollTrigger);
}
interface ProductShowcaseProps {
readonly items: Array<{ id: string; title: string; price: string }>;
}
export function ProductShowcase({ items }: ProductShowcaseProps) {
const containerRef = useRef<HTMLDivElement | null>(null);
useGSAP(
() => {
// Hardwarebeschleunigte Eingangstimeline
const tl = gsap.timeline({
defaults: {
ease: "expo.out",
duration: 0.8,
},
});
tl.from(".showcase-header", {
autoAlpha: 0,
y: 30,
clearProps: "all", // Inline-Stile nach der Animation bereinigen
}).from(
".product-card",
{
autoAlpha: 0,
y: 40,
scale: 0.96,
stagger: 0.08,
duration: 0.7,
clearProps: "transform,opacity",
},
"-=0.4" // Nahtlose Überlappung
);
},
{ scope: containerRef } // Gescopte Bereinigungsgrenze
);
return (
<section ref={containerRef} className="w-full py-16 px-6">
<div className="showcase-header max-w-4xl mx-auto text-center mb-12">
<h2 className="text-h1 font-bold text-content-primary">Featured Collection</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-7xl mx-auto">
{items.map((item) => (
<article
key={item.id}
className="product-card will-change-transform bg-surface-elevated rounded-lg p-6 border border-border-subtle"
>
<h3 className="text-h3 font-semibold text-content-primary">{item.title}</h3>
<p className="text-content-secondary mt-2">{item.price}</p>
</article>
))}
</div>
</section>
);
}
5. Einhaltung reduzierter Bewegung
Immer Benutzer respektieren, die reduzierte Bewegung bevorzugen:
const { contextSafe } = useGSAP({ scope: containerRef });
// Zugänglichkeitspräferenz prüfen
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (prefersReducedMotion) {
// Sofort im endgültigen Ruhezustand rendern, ohne Animation
gsap.set([".showcase-header", ".product-card"], { autoAlpha: 1, y: 0, scale: 1 });
return;
}