Communitygithub.com

Niltra/web-scrollytelling

實現 Apple 風格的電影級滾動體驗(固定英雄、Canvas 幀序列、影片 scrub、有旁白的章節),使用 GSAP ScrollTrigger,無 scroll-jacking 且效能可量測。適用於建構動畫英雄區、固定區段、水平畫廊或任何「網頁就像你能滾動播放的影片」效果。

web-scrollytelling 是什麼?

這是一個專注於建立電影級滾動說故事體驗的 AI 代理技能,靈感來自 Apple 的產品頁面效果。它強制執行一套嚴格的架構原則:使用單一固定容器與單一時間軸,透過 GSAP 的 `scrub: true` 讓動畫進度完全由使用者的原生滾動控制,嚴禁劫持滾輪。技能支援三種核心技術:Canvas 幀序列(從影片輸出 WebP 序列,智慧載入與快取)、影片 scrubbing(使用 blob URL 與短 GOP 編碼確保流暢搜尋),以及 DOM 覆蓋層章節(依進度範圍觸發淡入淡出與佈局變化)。此技能優先考慮效能,限制同時載入的幀數(最多 90-120 幀,行動版減半),僅使用 `transform`、`opacity` 與 `filter` 動畫,並透過暴露除錯狀態至 `window.debug` 來驗證,確保即使 headless 瀏覽器也能正確讀取。適合用於 Cursor、Claude Code 等支援 JS/TS 專案的工具。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Niltra/agent-skills-web/tree/HEAD/skills/web-scrollytelling

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

電影級滾動說故事

基礎架構(不可協商)

  • 單一固定容器,單一時間軸。 英雄區(或主要章節)固定一個容器,持續 N 個 viewport 高度,而一個從 0→1 的進度值驅動所有動畫。如果有多個滾動動畫互相競爭,那只是一個有特效的一般網頁:不是這個。
  • 絕不劫持滾輪。 使用者以自己的原生滾輪控制速度;動畫只是「scrub」(scrub: true)。禁止劫持滾輪或替使用者移動滾輪。
  • 單一動畫迴圈。 如果使用 Lenis,將其整合至 GSAP 的 ticker(autoRaf: false)並同步 ScrollTrigger;或者使用原生滾輪與 scrub。兩個迴圈競爭是 jank 的第一大原因,且無法透過優化素材解決。
  • 文字存活在 DOM 中,疊加在 Canvas 上方,依進度分層顯示。絕不將文案渲染在 Canvas 內。

幀序列(Apple 風格技術)

  • 首選來源:真實影片 → 使用 ffmpeg 提取幀(fps=12..24,縮放至螢幕解析度)。匯出 WebP q≈68-75,並透過視覺檢查結果調整,而非憑直覺。
  • 最多約 90-120 幀;在行動設備上提供一半或 720p 版本。
  • 使用滑動視窗載入:保持當前幀前後 ±6-10 幀;絕不解碼完整序列(完整的 1080p 序列會讓 iOS Safari 當機)。
  • 使用 IntersectionObserver(rootMargin ~800px)預載入,使用 requestIdleCallback 解碼,並設定 fetchPriority="low"(英雄區除外)。
  • Canvas 的 devicePixelRatio 上限為 1.5,並計算 cover/contain;僅繪製已解碼的幀;若缺少目標幀,使用最接近的已載入幀(絕不繪製黑色)。
  • 快取設為不可變(Cache-Control: public, max-age=31536000, immutable),並使用帶版本號的檔名。
  • 針對 prefers-reduced-motion 與慢速連線的降級方案:靜態預覽圖 + 無固定的普通章節。
  • 當不需要後處理時,更簡單的替代方案:按幀切換 <img> 的 src(所有瀏覽器可靠,無需 Canvas)。

影片 Scrub(若使用 <video>)

  • currentTime 由一個 requestAnimationFrame 內的進度值驅動,並加上平滑處理;合併 seeks(Safari 會累積佇列)。
  • 以 blob 載入,使其 100% 可搜尋;使用短 GOP 編碼(每數幀一個關鍵幀),否則 scrub 會卡頓。
  • 永不 autoplay:由滾輪控制播放。

章節與覆蓋層

  • 依進度範圍(10%、35%、60%、85%...)定義 beats,具有淡入淡出效果,並交替從兩側進入以創造節奏。
  • 每個章節的文字保持在 DOM 中,語意順序正確,以利 SEO。
  • 水平畫廊:固定區段 + x 屬性綁定進度;卡片向中心縮放。

效能與驗證

  • 僅動畫 transform、opacity 與 filter;will-change 僅在必要時使用,並在動畫結束後移除。
  • 在本地端與真實行動裝置上使用 requestAnimationFrame 測量幀率;目標是在中等筆電上達到 60fps。
  • Headless 瀏覽器可能讀取到黑色 Canvas(緩衝區未保留):透過 DOM 驗證(計算樣式、元素、暴露在 window.debug 的狀態)並在啟用減少動畫模式時測試。
  • 測試寬度為 375/768/1280/1440;桌面瀏覽器調整大小無法重現 iOS 的記憶體崩潰:請在 QA 報告中說明。

建議的資料結構

一個有序的「鏡頭」陣列:每個鏡頭為 { tipo: '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.

相關技能