Communitygithub.com

비디오 및 프로토타입 모션 추출 (video-to-gsap)

비디오 녹화본, GIF 또는 Figma 프로토타입 애니메이션이 제공될 때 모션 choreography를 타이밍, easing 곡선, 공간 궤적 및 stagger로 분해하고, @gsap/react와 useGSAP을 사용하여 Next.js 16에서 하드웨어 가속 및 메모리 누수 없는 GSAP 애니메이션을 구현합니다.

비디오 및 프로토타입 모션 추출 (video-to-gsap)란 무엇인가요?

이 스킬은 비디오, GIF, 또는 Figma 모션 프로토타입을 분석하여 정밀한 GSAP 애니메이션으로 변환하는 전문 기술입니다. 사용자가 제공한 모션 클립을 체계적으로 분해하여 타이밍, easing 곡선, 공간 이동 궤적 및 stagger 오프셋을 추출하고, Next.js 16 환경에서 @gsap/react의 useGSAP 훅을 활용하여 안전하게 구현합니다. 주요 특징으로는 오직 transform(x, y, scale, rotation 등)과 opacity와 같은 합성 속성만 애니메이션하여 60/120 FPS의 부드러운 성능을 보장하며, useGSAP 스코프를 통해 컴포넌트 언마운트 시 모든 타임라인과 ScrollTrigger 인스턴스가 자동 정리되어 메모리 누수를 방지합니다. 또한 prefers-reduced-motion 미디어 쿼리를 존중하여 접근성을 준수하고, clearProps와 autoAlpha를 활용한 FOUC(스타일 적용 전 깜빡임) 제거 기능을 제공합니다. Cursor, Claude Code, Codex 등 다양한 AI 에이전트 플랫폼에서 사용할 수 있습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/billel-chami/nextjs-medusa-handbook/tree/HEAD/.agents/skills/video-to-gsap

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

비디오 및 프로토타입 모션 추출 (video-to-gsap)은(는) 무엇을 하나요?

1. 목적 및 트리거

유연한 미세 상호작용과 영화 같은 모션은 고급 상거래 경험을 차별화합니다. 그러나 잘못 구현된 웹 애니메이션은 스레드 차단, 프레임 드롭(잔크), 메모리 누수, 그리고 낮은 INP(Interaction to Next Paint)를 유발합니다. 이 스킬은 부드러운 60/120 FPS 애니메이션의 추출 및 구현을 관리합니다.

트리거:

  • 사용자가 비디오 클립, GIF 또는 Figma 모션 프로토타입을 제공할 때
  • 카트 슬라이드오버, 페이지 전환, 아코디언 확장, 제품 카드 호버, 또는 체크아웃 완료 축하 애니메이션을 만들 때
  • ScrollTrigger를 사용한 스크롤 기반 애니메이션을 만들 때

2. 모션 분해 프로토콜

모션 클립을 분석할 때 체계적으로 다음을 식별합니다:

  1. 코레오그래피 시퀀스:
    • 스테이징 / 트리거: 어떤 동작이 모션을 시작하는가 (호버, 스크롤, 경로 변경, 클릭)?
    • 준비 동작: 주 모션 전에 미묘한 역방향 움직임이 있는가?
    • 동작 및 이동: 어떤 요소가 어떤 방향으로, 얼마나 멀리 (px, rem 또는 %) 이동하는가?
    • 정착 및 후속 동작: 오버슈팅(스프링/탄성)하는가 아니면 부드럽게 감속하는가 (power3.out, expo.out)?
  2. 타이밍 분석:
    • 각 요소의 지속 시간 (예: 서랍 진입: 450ms, 배경 페이드: 300ms).
    • 스태거된 자식들 사이의 stagger 오프셋 (예: 제품 그리드 카드: 0.06s stagger).
  3. Easing 시그니처:
    • 선형: 연속 루프에만 사용 (예: 마키).
    • Ease-out (power2.out, expo.out): UI 진입용 (빠른 진입, 부드러운 정착).
    • Ease-in (power2.in): UI 종료용 (화면 밖으로 가속).
    • Ease-in-out (power3.inOut): 뷰 내 상태 변환용.

3. 성능 및 하드웨어 가속 표준

규칙 1: 합성 속성만 애니메이션

  • 허용됨: transform (x, y, xPercent, yPercent, scale, rotation, skew) 및 opacity (또는 GSAP autoAlpha).
  • 엄격히 금지: 레이아웃 또는 페인트 속성 (width, height, top, left, right, bottom, margin, padding, border-width)을 애니메이션하는 것. 이는 브라우저 CPU가 매 프레임마다 레이아웃 지오메트리를 다시 계산하고 픽셀을 다시 그리도록 강제하여 INP 저하 및 프레임 드롭을 유발합니다.

규칙 2: Scoped useGSAP으로 메모리 누수 제로

  • 항상 공식 @gsap/react 패키지와 useGSAP 훅을 사용하세요.
  • scope 컨테이너 ref를 제공하세요. 내부의 모든 선택자는 자동으로 스코프 지정되며, 모든 타임라인, 트윈 및 ScrollTrigger 인스턴스는 컴포넌트가 언마운트될 때 깔끔하게 복원되고 제거됩니다.
  • 이는 싱글 페이지 앱 및 React 19 빠른 새로고침 사이클에서 좀비 이벤트 리스너와 메모리 보유를 방지합니다.

규칙 3: FOUC(스타일 적용 전 깜빡임) 제거

  • opacity 대신 autoAlpha를 사용하세요. autoAlpha는 불투명도가 0에 도달하면 visibility: hidden을 설정하여 하이드레이션 전에 고스트 클릭과 렌더링 깜빡임을 방지합니다.
  • 또는 CSS 기본 숨김 상태를 선언하고 gsap.fromTo로 표시하세요.

4. 프로덕션 구현 청사진

"use client";

import { useRef } from "react";
import gsap from "gsap";
import { useGSAP } from "@gsap/react";
import { ScrollTrigger } from "gsap/ScrollTrigger";

// Ensure plugins are registered safely
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(
    () => {
      // Hardware-accelerated entrance timeline
      const tl = gsap.timeline({
        defaults: {
          ease: "expo.out",
          duration: 0.8,
        },
      });

      tl.from(".showcase-header", {
        autoAlpha: 0,
        y: 30,
        clearProps: "all", // Clean up inline styles post-animation
      }).from(
        ".product-card",
        {
          autoAlpha: 0,
          y: 40,
          scale: 0.96,
          stagger: 0.08,
          duration: 0.7,
          clearProps: "transform,opacity",
        },
        "-=0.4" // Seamless overlap
      );
    },
    { scope: containerRef } // Scoped cleanup boundary
  );

  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. 축소된 모션 준수

항상 축소된 모션을 선호하는 사용자를 존중하세요:

const { contextSafe } = useGSAP({ scope: containerRef });

// Check accessibility preference
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

if (prefersReducedMotion) {
  // Instantly render in final resting state without animation
  gsap.set([".showcase-header", ".product-card"], { autoAlpha: 1, y: 0, scale: 1 });
  return;
}

관련 스킬