인셔셔RSS 관심 있는 블로그, 뉴스, 기술 정보를 효율적으로 추적하고 읽으세요
원문 읽기 InertiaRSS에서 열기

추천 피드

小众软件
小众软件
博客园 - 叶小钗
有赞技术团队
有赞技术团队
大猫的无限游戏
大猫的无限游戏
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
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)
제 2부: 3.4MB 영상을 40kb의 스크립트 GSAP 애니메이션으로 바꾸기: 카메라 추가
Sugam Panthi · 2026-05-28 · via DEV Community

제1부는 두 날 안에 r/webdev에서 69,000 조회수를 기록했습니다. 그렇게 예상하지 못했습니다. 저는 3.4 MB 영상을 40 KB의 DOM 애니메이션으로 바꾸는 것을 공유할 만큼 흥미로울 것이라고 생각해서 썼습니다. 많은 사람들이 같은 문제를 고민하고 있다는 것을 알게 되었습니다.

댓글은 게시물보다 더 좋았습니다. 사람들은 SEO 색인, 스크린 리더 동작에 대해 물었습니다.prefers-reduced-motion 대체 방법, GSAP이 필요한지 자체에 대한 의문, 그리고 몇몇은 무언가 빠진 점을 지적했습니다. 그들은 옳았습니다.

제1부는 평평한 무대에서 장면을 클릭하는 커서를 보여줬습니다. 모든 것이 동일한 확대 수준에서, 시청자와 동일한 거리에서 일어났습니다. 실제 제품 데모 영상을 보면 다른 점을 알게 됩니다: 카메라가 움직입니다. 중요한 일이 일어나면 행동에 확대하고, 워크플로우를 통해 커서를 따라가며, 장면이 바뀔 때 되돌아갑니다. 이것이 슬라이드 데크와 감독된 영화의 차이입니다.

이 게시물은 카메라를 추가합니다. 같은 40 KB 예산입니다. 비디오 파일이 없습니다.

4가지 상호작용 데모, 옆에서의 비교, 실시간 FPS 스트레스 테스트를 포함한 전체 게시물을 참조하세요.

확대 래퍼 문제

첫 번째로 시도하는 것은 gsap.to(frame, { scale: 1.4 })입니다. 0.5초 동안 작동한 후, 반응형 확대가 사라졌다는 것을 알게 됩니다. 영화 프레임은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. 그것이 전체 수정이었습니다.

Pan math

프레임의 중심으로 확대하기는 쉽습니다. 사용자가 우클릭하려는 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.inOutsine.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.4x에서 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를 제거하여 탭 순서와 스크린 리더에서 요소를 제외합니다. 모든 숨겨진 요소는 autoAlpha를 사용하지만 opacity를 사용하지 않으므로 스크린 리더는 현재 표시된 내용만 볼 수 있습니다.

GSAP이 필요한가요?

간단한 애니메이션에는 필요 없습니다. 하지만 웹 클리퍼 데모에는 두 개의 장면에서 카메라 움직임과 함께 약 50개의 조화된 애니메이션이 있습니다. GSAP은 레이블(이름 있는 비트)을 제공합니다.repeat: -1 리셋 논리, gsap.utils.selector(root) 데이터 속성 쿼리용, 전체 애니메이션 라이브러리, 그리고 스테이거. GSAP 없이 모든 것을 구축할 수 있습니다. 더 오래 걸리고 더 나은 결과를 만들지 못합니다.

GSAP 핵심은 28 KB gzipped입니다. 50개 애니메이션 영화 시네마 데모를 조율하고 있다면, 이것은 인프라입니다.

에이전트 현실

사이트 전체에 걸쳐 다섯 개의 데모, 대략 4,000 줄의 춤编排 코드. 저는 그중 약 60%를 썼다. 나머지 40%는 AI 에이전트가 썼다.

내 60%는 연출이었다: 어떤 부분을 확대할지 결정하고, 두 가지 옵션을 모두 보고 후반부를 선택하며, 확대 중 커서가 죽어있는 것을 알아챈 것, "확대 해제가 200ms 너무 느림"이라고 말했다. 에이전트는 애니메이션을 보고 무언가 잘못된 것을 느낄 수 없다.

대리인의 40%는 구현이었습니다: 1,500줄의 타임라인 코드, DOM 요소, 클릭 도우미, 리셋 블록. 능력 파일에서 정의한 규칙에 따른 패턴 기반 작업. 패턴은 충분히 안정적이어서 다양한 데모에서 출력이 일관되게 나옵니다. 하지만 대리인은 무언가 잘못되어 보일 때를 알지 못합니다. 그 부분은 여전히 제 몫입니다.

성능

웹 클리퍼 데모는 50입니다.to()호출이지만 프레임마다 활성화된 것은 3-5개뿐입니다. 매우.to()쓰기를 합니다transform이거나opacity, 두 번째로 compositor-friendly입니다.전체 게시물에는 실시간 스트레스 테스트와 FPS 계수기가 있습니다여기서는 동시에 8에서 48개의 요소를 푸시하고 프레임 레이트를 모니터링할 수 있습니다.

업데이트된 수학

접근 방식 압축 카메라? 인덱스 가능? 접근 가능? 테마 가능?
GSAP (평평, 일부 1) ~37 KB 아니요
GSAP (이동-확대, 일부 2) ~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입니다.

제1부는 비디오를 대체할 수 있음을 증명한 부분이었습니다. 제2부는 그것이 녹음된 것이 아니라 제작된 것처럼 느껴지기 시작하는 부분입니다.

초기 비용은 현실적입니다. 지속 비용은 거의 영향이 없습니다. 업데이트는 코드 변경이 아니라 재녹음이 아닙니다.


전체 게시물 및 상호작용 데모: spanthi.com/blog/gsap-choreography-part-2

제작 사례: costumary.com | costumary.com/web-clipper

오픈 소스 에이전트 기술: gsap-춤추기