慣性聚合 高效追蹤和閱讀你感興趣的部落格、新聞、科技資訊
閱讀原文 在慣性聚合中打開

推薦訂閱源

小众软件
小众软件
博客园 - 叶小钗
有赞技术团队
有赞技术团队
大猫的无限游戏
大猫的无限游戏
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
Hugging Face - Blog
Hugging Face - Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
aimingoo的专栏
aimingoo的专栏
Blog — PlanetScale
Blog — PlanetScale
爱范儿
爱范儿
T
Tailwind CSS Blog
Jina AI
Jina AI
量子位
Stack Overflow Blog
Stack Overflow Blog
人人都是产品经理
人人都是产品经理
J
Java Code Geeks
V
Visual Studio Blog
月光博客
月光博客

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
第二部分:用 40kb 的 GSAP 脚本動畫替換 3.4MB 的影片:添加相機
Sugam Panthi · 2026-05-28 · via DEV Community

第一部分 在兩天內在 r/webdev 上達到 69,000 次觀看。我沒有預期到這個結果。我寫它是因為我想取代一個 3.4 MB 的影片,用 40 KB 的 DOM 動畫來實現,覺得這樣的內容夠有趣可以分享。結果發現很多人都在思考同樣的問題.

註解比文章本身更好。人們問到了關於 SEO 索引、螢幕讀取器行為,prefers-reduced-motion 的備用方案,無論 GSAP 是否真的必要,好幾個人指出它缺少了某個東西。他們是對的。

第一部分是一個游標在平坦的舞台上游走過場景。所有事情都發生在同樣的縮放層級,與觀眾同樣的距離。觀看一個真實的產品示範影片,你會注意到一些不同之處:鏡頭會移動。當發生重要的事情時,它會縮放到動作中,跟隨游標通過一個工作流程,當場景變化時會拉回。那就是簡報和導演電影之間的區別。

這篇貼文增加了相機。同樣是40 KB預算。沒有視頻檔案.

參考完整貼文,包含4個互動示範、並列比較,以及實時FPS壓力測試

縮放包裝器問題

你首先嘗試的是gsap.to(frame, { scale: 1.4 })。它只運作半秒鐘,然後你發現你的響應式縮放消失了。膠片框架使用transform: scale(filmScale) 需要適應其容器寬度,而 GSAP 則直接覆蓋了它。兩者都寫入相同的 CSS transform 屬性。它們不能在相同的元素上共存。

解決方案是在 GSAP 擁有的框架內包裝一個外殼:

<div data-film-frame style={{ transform: `scale(${filmScale})` }}>
  <div data-film-zoom className="origin-center">
    {/* All scene content */}
  </div>
  <Cursor />  {/* Outside the zoom wrapper */}
</div>

進入全螢幕模式 退出全螢幕模式

GSAP 動畫化data-film-zoom。外框的響應比例尺沒有被改變。滑鼠光標位於縮放包外,所以在內容縮放時它的大小保持不變。這花了我很長時間才弄清楚。兩個 div。那就是整個修復的解決方法。

滾動數學

將焦點對準框架中心很容易。將焦點對準特定元素,例如即將右鍵點擊的 Pinterest 貼釘,才是真正難題。您需要翻譯放大外殼,讓目標結束時位於可見視口中心:

const ZOOM = 1.45;
const panTo = (target) => ({
  x: (FILM_WIDTH / 2 - target.x) * (ZOOM - 1),
  y: (FILM_HEIGHT / 2 - target.y) * (ZOOM - 1),
});

進入全螢幕模式 離開全螢幕模式

放大至1.0倍時,無需翻譯。放大至1.45倍時,每個離中心點的像素需要將其距離乘以0.45倍進行翻譯以補償。

保持放大狀態,拖動滾動跟隨

我第一次嘗試的最大錯誤是在一次互動中放大,然後縮小,接著為下一次互動再放大,然後再次縮小。看起來像是一個預算有限的PowerPoint放大過渡效果。

正確的模式:縮放一次,保持縮放,滑動跟隨游標透過整個互動順序,換場景時縮放一次出來。

// Zoom in on right-click
tl.to(zoom, {
  scale: ZOOM, x: panPin.x, y: panPin.y,
  duration: 0.65, ease: "expo.out",
}, "zoomIn");

// Context menu while zoomed
tl.to(ctx, { autoAlpha: 1, duration: 0.16 }, "zoomIn+=0.35");

// Camera pans to follow cursor to the save button (still zoomed)
tl.to(zoom, {
  x: panSave.x, y: panSave.y,
  duration: 0.55, ease: "sine.inOut",
}, "panToSave");

// Only zoom out when done
tl.to(zoom, {
  scale: 1, x: 0, y: 0,
  duration: 0.45, ease: "sine.inOut",
}, "zoomOut");

進入全螢幕模式 離開全螢幕模式

在完整文章中查看這個作為實時互動示範在運行

慣性效果不是一成不變

第一部分使用了power2.out 用於幾乎所有情況。適合扁平化展示。但當加入鏡頭運動時,不同運動類型需要不同的緩動效果,否則整體感覺就不對

運動 緩動 為何
鏡頭橫移 sine.inOut 最平滑的曲線。感覺像真實的鏡頭在滾車上
戲劇性推近 expo.out 快速開始,長時間減速。呼嘯聲然後穩定下來。
游標移動 sine.inOut 自然手部加速
淡入 sine.out 逐漸顯現
點擊壓縮 power2.out 迅速壓力反應
點擊釋放 back.out(2.2) 輕微過度擊中。感覺真實
輸入文字 none 真實打字並不輕鬆。

最大的一次升級是將power2.inOut換成sine.inOut在鏡頭移動上。power2有一個明顯的加速度衝刺,在大規模下感覺像機械般。sine在任何曲線上的任何點都沒有可察覺的衝刺。

滑鼠光標從不僵死

當鏡頭移動時,會有場景切換但游標凍結的時刻。這些時刻破壞了虛擬感。每個鏡頭移動應該在相同時間軸標籤上有同步的游標移動:

// BAD: cursor is dead during zoom
tl.to(zoom, { scale: 1.4, x: panX, y: panY, duration: 0.7 }, "zoomIn");

// GOOD: cursor drifts toward its next target during zoom
tl.to(zoom, {
  scale: 1.4, x: panX, y: panY,
  duration: 0.7, ease: "expo.out",
}, "zoomIn");
tl.to(cursor, {
  x: current.x + (next.x - current.x) * 0.3,
  y: current.y + (next.y - current.y) * 0.3,
  duration: 0.65, ease: "sine.out",
}, "zoomIn");

進入全螢幕模式 退出全螢幕模式

游標不必準確到達。向下一個目標偏移20-30%就足夠了。平靜,但從不停止。

完整貼文有一個並列比較,顯示凍結狀態與滑動游標在放大時的差異

流暢的迴圈

第一部分的迴圈很突兀。由於鏡頭移動,問題更嚴重,因為放大倍數會從1.4倍瞬間跳回1.0倍

解決方法是加入結尾動畫:

tl.to(zoom, { scale: 1, x: 0, y: 0, duration: 0.8, ease: "sine.inOut" }, "outro");
tl.to(cursor, { x: offScreenX, y: offScreenY, duration: 0.7, ease: "sine.in" }, "outro+=0.1");
tl.to({}, { duration: 0.6 }); // breathing room

進入全螢幕模式 退出全螢幕模式

而且有個時間規則:初稿總是太慢。在第一個可用版本後,將你的時間縮短 20-30%。

SEO、主題設定,以及視頻無法做到的事

<video>標籤上查看原始碼,Google 就能看見<video src="demo.mp4">。一個黑色方塊。在 GSAP 示範中查看原始碼,每個按鈕標籤、菜單項目和標題都是可索引的文本。我沒有進行過受控排名測試,但從邏輯上講:真實 DOM 文本比不透明的二进制大塊更優。

超越索引,DOM示範會隨產品變化而變化。行銷更改按鈕標籤?更改文字字串。品牌顏色更新?更改一個十六進制值。您希望示範按鈕能實際轉化?將它們連接到一個真正的註冊模態。影片無法做到任何這些。

可訪問性

prefers-reduced-motion: reduce 被啟用時,跳過整個時間線並渲染靜態狀態。GSAP的 autoAlpha 設置兩者opacity: 0visibility: hidden,移除從 tab 順序和螢幕讀取器中。每個隱藏的元素使用 autoAlpha,而不是 opacity,所以螢幕讀取器只看到當前可見的部分。

它需要 GSAP嗎?

對於簡單的動畫,不需要。但網頁剪輯示範包含兩個場景中約 50 個協調動畫,包括鏡頭移動。GSAP 提供標籤(命名節拍),repeat: -1 配備重設邏輯,gsap.utils.selector(root) 用於資料屬性查詢,一個完整的彈性函式庫,以及 staggering。你可以不用 GSAP 來建立所有這些。這將花費更長的時間並產生更差的结果。

GSAP 核心 28 KB 壓縮後。如果你正在策劃一個包含 50 個動畫的電影節目示範,它就是基礎設施。

代理現實

站內共有五個示範,大約有4,000行編舞程式碼。我寫了大約60%的那部分。另一40%則由AI代理寫的。

我的60%是導演工作:決定要放大什麼,在觀看兩個選項後選擇eases,發現放大時游標感覺死滯,說「縮小動作慢了200毫秒。」代理無法觀看動畫並感覺到有什麼不對勁。

代理人的40%是實現:1,500行時間線程代碼、DOM元素、點擊輔助工具、重置塊。遵循我在一個技能文件中定義的規則進行模式化工作。這些模式穩定到足以讓輸出在不同示範中保持一致。但代理人不知道當某個東西看起來錯誤時。那部分仍然是我的。

性能

網頁剪輯器示範有 50 .to() 呼叫,但任何一幀只有 3-5 個會主動進行插值動畫。每個 .to() 都寫入到 transformopacity,這兩者對合成器都很友好。完整帖子有一個實時壓力測試,帶有 FPS 計數器,你可以從 8 個到 48 個並發元素,並觀察帧率。

更新的數學

方法 壓縮 相機? 可索引? 可存取? 可主題化?
GSAP (扁平, 第一部分) ~37 KB
GSAP (平移縮放, 第二部分) ~40 KB
15秒 MP4 (H.264) 2-4 MB 預設內建
15秒 WebM (VP9) 1-2 MB 預設內建
15秒 GIF 8-15 MB 已烘焙

添加相機為捆綁增加了約3 KB。所有五個生產示範在costumary.com下壓縮後總和不到80 KB。視頻中的等價物將是15-20 MB。

第一部分證明了你可以替換一段影片。第二部分是開始感覺像是指導而非錄製的部分.

前期的成本是實實在在的。持續的成本接近零。更新是程式碼變更,不是重新錄製.


完整文章與互動示範: spanthi.com/blog/gsap-choreography-part-2

製作範例: costumary.com | costumary.com/web-clipper

開源代理技能: gsap-choreography