Communitygithub.com

Niltra/web-scrollytelling

GSAP ScrollTrigger를 활용해 Apple 스타일의 시네마틱 스크롤 경험(핀 고정 영웅, 캔버스 프레임 시퀀스, 비디오 스크러빙, 내레이티브 챕터)을 구현합니다. 스크롤 하이재킹 없이 성능을 측정하며, 애니메이션 히어로, 고정 섹션, 수평 갤러리 등 '웹이 마치 움직이는 비디오처럼' 보이는 모든 효과에 사용하세요.

web-scrollytelling란 무엇인가요?

이 스킬은 Apple의 스크롤 기반 스토리텔링에서 영감을 받은, 영화 같은 스크롤 경험을 구현하기 위한 완전한 아키텍처와 기술 세트를 제공합니다. GSAP ScrollTrigger를 핵심 엔진으로 사용하며, 단일 고정(pin)과 단일 타임라인 원칙을 고수하여 여러 애니메이션이 충돌하지 않도록 합니다. 네이티브 스크롤을 하이재킹하지 않고(scroll-jacking 금지), 사용자의 스크롤 속도에 맞춰 애니메이션이 자연스럽게 '스크러빙'됩니다. 프레임 시퀀스, 비디오 스크러빙, 수평 갤러리, 텍스트 챕터 오버레이를 포함한 다양한 효과를 지원하며, 텍스트는 항상 DOM에 유지되어 SEO와 접근성을 보장합니다. 성능 최적화에 중점을 두어, devicePixelRatio 캡, 슬라이딩 윈도우 프레임 디코딩, `transform`/`opacity`만 애니메이션하는 등의 구체적인 지침을 제공하며, prefers-reduced-motion 및 느린 연결을 위한 폴백도 포함합니다. 주로 Apple 스타일의 랜딩 페이지, 제품 소개, 내러티브 스크롤 사이트를 구축하는 개발자에게 적합합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Niltra/agent-skills-web/tree/HEAD/skills/web-scrollytelling

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

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

문서

시네마틱 스크롤스토리텔링

기본 아키텍처 (필수)

  • 단일 핀, 단일 타임라인. 히어로(또는 주요 챕터)는 N개의 뷰포트 높이 동안 지속되는 컨테이너를 고정하고, 진행률 0→1이 모든 것을 제어합니다. 여러 스크롤 애니메이션이 경쟁한다면, 그것은 단순한 효과가 있는 일반 웹일 뿐입니다.
  • 절대 스크롤 하이재킹 금지. 사용자는 네이티브 스크롤로 속도를 제어하며, 애니메이션은 '스크러빙'됩니다(scrub: true). 휠을 가로채거나 사용자 대신 스크롤을 움직이는 것은 금지됩니다.
  • 단일 애니메이션 루프. Lenis는 GSAP 티커(autoRaf: false)와 ScrollTrigger에 통합되어 동기화됩니다. 또는 네이티브 스크롤을 scrub과 함께 사용합니다. 두 개의 루프가 경쟁하는 것은 잔상(jank)의 주된 원인이며, 에셋 최적화로 해결되지 않습니다.
  • 텍스트는 DOM에 존재하며, 캔버스 위에 오버레이되고 진행률에 따라 레이어가 나뉩니다. 절대 캔버스 내에서 텍스트를 렌더링하지 마십시오.

프레임 시퀀스 (Apple 스타일 기법)

  • 선호하는 소스: 실제 비디오 → ffmpeg로 프레임 추출(fps=12..24, 화면 해상도로 크기 조정). WebP q≈68-75로 내보내고 직관이 아닌 결과를 보며 미세 조정합니다.
  • 최대 ~90-120 프레임; 모바일에서는 절반 또는 720p 버전을 제공합니다.
  • 슬라이딩 윈도우 방식으로 로드: 현재 프레임 주변 ±6-10 프레임만 유지; 전체 시퀀스를 디코딩하지 않습니다(1080p 전체 시퀀스는 iOS Safari를 죽입니다).
  • IntersectionObserver(rootMargin ~800px), requestIdleCallback을 사용한 디코드, 히어로를 제외한 fetchPriority="low"로 사전 로드합니다.
  • 캔버스는 devicePixelRatio를 1.5로 제한하고 cover/contain을 계산하여 사용; 디코딩된 프레임만 그리며, 정확한 프레임이 없으면 이미 로드된 가장 가까운 프레임을 사용합니다(절대 검은색으로 그리지 않음).
  • 불변 캐시(Cache-Control: public, max-age=31536000, immutable)와 버전 관리된 파일 이름을 사용합니다.
  • prefers-reduced-motion 및 느린 연결에 대한 폴백: 정적 포스터 + 핀이 없는 일반 챕터.
  • 후처리가 필요 없는 더 간단한 대안: 프레임별로 <img>의 src를 교체(모든 브라우저에서 안정적, 캔버스 불필요).

비디오 스크러빙 (<video> 사용 시)

  • currentTime은 단일 requestAnimationFrame에서 진행률에 의해 제어되며, 부드럽게 처리됩니다; 탐색을 병합합니다(Safari는 큐를 누적).
  • 100% 탐색 가능하도록 Blob으로 로드합니다; 짧은 GOP(매 몇 프레임마다 키프레임)로 인코딩해야 스크럽이 끊기지 않습니다.
  • 절대 자동 재생 금지: 스크롤이 움직입니다.

챕터 및 오버레이

  • 진행률 범위(10%, 35%, 60%, 85%...)로 정의된 비트(Beats), 페이드 인/아웃 및 리듬을 위한 교차 진입 방향.
  • 각 챕터는 SEO를 위해 올바른 의미론적 순서로 DOM에 텍스트를 유지합니다.
  • 수평 갤러리: 섹션 고정 + 진행률에 연결된 x; 카드는 중앙으로 스케일됩니다.

성능 및 검증

  • transform, opacity, filter만 애니메이션합니다. will-change는 필요한 경우에만 사용하고 완료 후 제거합니다.
  • 로컬 및 가능하면 실제 모바일 기기에서 requestAnimationFrame으로 프레임을 측정합니다. 중간급 노트북에서 60fps를 목표로 합니다.
  • Headless 캡처는 캔버스를 검은색으로 읽을 수 있습니다(버퍼 미보존): DOM으로 확인 (계산된 스타일, 요소, window.debug에 노출된 상태) 및 축소 모드가 활성화된 상태에서 확인합니다.
  • 375/768/1280/1440에서 테스트합니다. 데스크톱 브라우저 크기 조정은 iOS의 메모리 충돌을 재현하지 않습니다. QA 보고서에 명시하십시오.

권장 데이터 구조

정렬된 '장면' 배열: 각 장면은 { type: 'frames' | 'overlay' | 'galeria', ... }입니다. 영화 재구성 = 목록 재정렬. 프레임은 패턴으로 참조됩니다(/seq/plano-01/0001.webp).

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

관련 스킬