60fps-animation
iart-ai/web-animation-skills · Agent Skill
Web animasyon performansı rehberi, düzenin bozulmasını önlemek ve besteciye dost yöntemlerle saniyede 60/120 kareye kadar sorunsuz hareket elde etmek için.
Kuruluma geç ↓Genel bakış
| Yayıncı | |
|---|---|
| Depo | iart-ai/web-animation-skills ↗ |
| Skill klasörü | 60fps-animation |
| Yıldız | 58 |
| Fork | 9 |
| Dosyalar | 3 |
| Lisans | MIT |
| Son güncelleme | 22 Haziran 2026 |
| Bağlantılar | Skill kaynağı ↗ · Depo ↗ |
Mozgi kontrolü
Skill dosyalarında bulduklarımız. Ayrıntılar abonelikle.
Kurulum
Skill, SKILL.md dosyası içeren bir klasördür. Ajanınızı seçin ve komutları proje kökünde bir terminalde çalıştırın (macOS, Linux veya Windows'ta Git Bash).
Promptu Claude, Codex veya başka bir asistana yapıştırın: skill'i inceleyip sizin için kuracaktır.
Install the “60fps-animation” skill from mozgi.io (https://mozgi.io/skills/iart-ai-60fps-animation/) for me. 1. Download the archive: https://mozgi.io/skills/iart-ai-60fps-animation/download If it fails, take the skill folder from the source: https://github.com/iart-ai/web-animation-skills/tree/main/skills/60fps-animation 2. Read SKILL.md and the other files. Check the skill is safe: no hidden commands, no sending data elsewhere, no scripts doing something other than described. If anything looks suspicious, stop and tell me. 3. Put the “60fps-animation” folder into your agent's skills folder: .claude/skills/ for Claude Code, .agents/skills/ for Codex, .cursor/skills/ for Cursor, .gemini/skills/ for Gemini CLI. Inside the project if we are in one, otherwise in the home folder (~/.claude/skills/ etc.). 4. Make sure <skills folder>/60fps-animation/SKILL.md exists. 5. Briefly tell me what this skill does and offer to try it on my task. If you cannot do a step yourself, tell me what to click or type.
git clone --depth 1 --branch main https://github.com/iart-ai/web-animation-skills.git /tmp/web-animation-skills mkdir -p .claude/skills cp -r /tmp/web-animation-skills/skills/60fps-animation .claude/skills/60fps-animation
Claude Code'u yeniden başlatın — skill listede görünür; elle çağırmak için /60fps-animation. Tüm projeler için ~/.claude/skills.
git clone --depth 1 --branch main https://github.com/iart-ai/web-animation-skills.git /tmp/web-animation-skills mkdir -p .agents/skills cp -r /tmp/web-animation-skills/skills/60fps-animation .agents/skills/60fps-animation
Codex skill'leri geçerli klasörden depo köküne kadar .agents/skills içinde arar; /skills veya $60fps-animation ile çağırın. Tüm projeler için ~/.agents/skills.
git clone --depth 1 --branch main https://github.com/iart-ai/web-animation-skills.git /tmp/web-animation-skills mkdir -p .cursor/skills cp -r /tmp/web-animation-skills/skills/60fps-animation .cursor/skills/60fps-animation
Cursor skill'i açılışta yükler; Agent sohbetinde “/” ile çağırın. Cursor .claude/skills ve .agents/skills klasörlerini de okur. Tüm projeler için ~/.cursor/skills.
git clone --depth 1 --branch main https://github.com/iart-ai/web-animation-skills.git /tmp/web-animation-skills mkdir -p .gemini/skills cp -r /tmp/web-animation-skills/skills/60fps-animation .gemini/skills/60fps-animation
Gemini CLI, görev uyduğunda skill'i etkinleştirmeyi önerir — siz onaylarsınız. Tüm projeler için ~/.gemini/skills.
Kurulumdan önce SKILL.md ve eşlik eden dosyaları inceleyin. Önizleme için dosyaya tıklayın.
SKILL.md içeriği
Yazarın orijinal metni · salt okunurPerformant Web Animation
Eliminate the #1 cause of janky web animation: animating properties that force the browser to recalculate layout (reflow) or repaint on every frame. The browser renders in stages — layout → paint → composite. Animating width, height, top, left, margin, padding, box-shadow, or filter re-runs layout and/or paint each frame, blocking the main thread. Animating transform and opacity runs entirely on the compositor (often the GPU), skipping layout and paint, which is what makes animation smooth at 60/120fps.
When to use
Use when an animation stutters or drops frames, when a hover/scroll effect feels heavy, when animating size/position/shadow, when a layout change needs to animate smoothly (cards reordering, an element moving between containers), when animating height: auto, or when reviewing animation code for performance.
Core rule: animate only transform and opacity
Map every "expensive" animation to a cheap equivalent.
| Animating (expensive) | Triggers | Replace with (cheap) |
|---|---|---|
| width / height | Layout + Paint | transform: scaleX()/scaleY() (+ FLIP for true size) |
| top / left / margin | Layout + Paint | transform: translate() |
| box-shadow | Paint | Animate opacity of a pseudo-element holding the shadow |
| filter: blur() | Paint (heavy) | Cross-fade two layers via opacity, or accept sparingly |
| background-position | Paint | transform: translate() on a child layer |
| color / background | Paint | Often acceptable; or cross-fade layers |
Position and size via transform
/* BAD: animates layout every frame */
.box { transition: left 300ms, width 300ms; left: 0; width: 100px; }
.box:hover { left: 200px; width: 200px; }
/* GOOD: compositor-only */
.box {
transition: transform 300ms ease;
transform: translateX(0) scaleX(1);
transform-origin: left center;
}
.box:hover { transform: translateX(200px) scaleX(2); }
scaleX distorts inner content (text stretches). For true resizing without distortion, use FLIP.
Cheap box-shadow via pseudo-element opacity
Animating box-shadow repaints a large blurred region every frame. Instead paint the shadow once on a ::after, then animate only its opacity.
.card { position: relative; }
.card::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
box-shadow: 0 12px 28px rgba(0,0,0,0.35);
opacity: 0;
transition: opacity 300ms ease;
pointer-events: none;
}
.card:hover::after { opacity: 1; }
The blurred shadow is rasterized once; hovering only changes a compositor opacity — smooth at any frame rate.
FLIP: animate layout changes cheaply
FLIP (First, Last, Invert, Play) animates a *layout* change (reorder, resize, move between containers) using only transform. Measure where the element was (First) and will be (Last), apply an inverting transform so it visually appears unmoved, then animate the transform back to identity (Play). The DOM ends in its real final layout; the motion is pure compositor work.
function flip(el, mutate) {
const first = el.getBoundingClientRect(); // First
mutate(); // change the DOM/layout
const last = el.getBoundingClientRect(); // Last
const dx = first.left - last.left;
const dy = first.top - last.top;
const sx = first.width / last.width;
const sy = first.height / last.height;
el.animate(
[
{ transformOrigin: 'top left',
transform: `translate(${dx}px, ${dy}px) scale(${sx}, ${sy})` }, // Invert
{ transformOrigin: 'top left', transform: 'none' }, // Play
],
{ duration: 300, easing: 'cubic-bezier(0.2, 0, 0, 1)' }
);
}
// usage: animate an element moving to a new grid position
flip(card, () => targetContainer.appendChild(card));
The Web Animations API animate() runs the transform on the compositor. For many elements, batch all getBoundingClientRect() reads *before* any mutation (see layout thrashing below).
Animating height: auto
height: auto is not interpolatable historically. Modern and fallback approaches:
/* Modern (Chrome 129+/supporting browsers): opt size keywords into animation */
.panel {
interpolate-size: allow-keywords; /* enables animating to/from auto */
height: 0;
overflow: clip;
transition: height 300ms ease;
}
.panel.open { height: auto; }
/* calc-size() also works: height: calc-size(auto, size); */
/* Robust fallback today: CSS grid 1fr -> 0fr */
.wrapper {
display: grid;
grid-template-rows: 0fr; /* collapsed */
transition: grid-template-rows 300ms ease;
}
.wrapper.open { grid-template-rows: 1fr; }
.wrapper > .content { overflow: hidden; min-height: 0; }
The grid trick animates the track size (compositor-friendly enough and broadly supported) and needs no JS height measurement. Use interpolate-size: allow-keywords / calc-size(auto, size) where the target browsers support it; keep the grid technique as the cross-browser default.
Avoid layout thrashing (batch reads, then writes)
Reading a layout property (offsetWidth, getBoundingClientRect, scrollTop, getComputedStyle) after a write forces a *synchronous* reflow. Interleaving reads and writes in a loop ("layout thrashing") can run dozens of forced reflows per frame.
// BAD: read, write, read, write... forces reflow each iteration
items.forEach((el) => {
const w = el.offsetWidth; // read (forces layout)
el.style.width = w * 1.5 + 'px'; // write (invalidates layout)
});
// GOOD: batch all reads, then all writes
const widths = items.map((el) => el.offsetWidth); // all reads
items.forEach((el, i) => { // all writes
el.style.width = widths[i] * 1.5 + 'px';
});
For frame-synced work, read in a requestAnimationFrame callback and apply writes; libraries like fastdom formalize this read/write scheduling.
will-change: use sparingly
will-change: transform promotes an element to its own compositor layer ahead of time, avoiding a hitch at animation start. But every promoted layer costs GPU memory, and over-use degrades performance.
.menu { will-change: transform; } /* only on elements about to animate */
Rules: apply just before the animation (e.g. on hover/parent state), remove it after (will-change: auto) when idle, never blanket-apply to many elements, and never leave it permanently on large/numerous nodes. A single transform: translateZ(0) hack does the same promotion but is harder to undo — prefer will-change.
Deliver & verify (standalone HTML)
> Packaged helper (scripts/): scripts/seek-shot.sh anim.html 0 1.5 3 freezes the ?t=N harness and screenshots each moment; scripts/contact-sheet.sh sheet.png frame-*.png tiles them for one-glance review. See scripts/README.md.
The deliverable is one self-contained .html that opens directly in a browser — the markup, the CSS/JS animation, and a freeze harness in one file. For this skill, verification is two-pronged: the frame must look right *and* be cheap to produce (compositor-only).
Output contract:
- One
.html, deps via CDN if any, animation driven by CSS transitions/@keyframesor the Web Animations API. - A freeze mechanism so a screenshot lands on a deterministic frame:
- CSS
@keyframes→?t=Nsetsel.style.animationDelay = (-N)+'s'; el.style.animationPlayState = 'paused'. - WAAPI / JS → keep the animation object and
anim.pause(); anim.currentTime = N*1000.
Verify loop — freeze → screenshot, then profile for jank:
1. Open headless at start / mid / end (?t=0, mid, end), screenshot each; confirm the motion is visually correct (no clipped/stretched text from scaleX, FLIP lands on the real layout, shadow/height transitions look right).
2. Confirm it's compositor-only — the whole point of this skill. Either:
- DevTools → Performance: record the animation, check there is no purple "Layout" or green "Paint" band per frame (only "Composite Layers").
- Or headless trace:
npx playwright screenshotfor the visual, plus a CDP/tracingcapture, and assert noLayout/Paintevents fire during the animation window.
3. Watch the FPS/“Frame Rendering Stats” overlay stays at 60 — dropped frames mean an expensive property slipped back in.
npx playwright screenshot --wait-for-timeout=500 "file://$PWD/anim.html?t=0.3" frame.png
Before you finish:
1. Opens standalone — no console errors.
2. Only transform / opacity animate per frame; DevTools shows no per-frame Layout/Paint.
3. Screenshotted at start / mid / end — correct, no scaleX text distortion, FLIP lands true.
4. Holds 60fps; will-change applied just-in-time and removed when idle (no leftover layers).
5. prefers-reduced-motion honored.
Quick reference
| Goal | Do this |
|---|---|
| Move element | transform: translate() |
| Resize without distortion | FLIP with transform |
| Shadow on hover | Animate opacity of shadow pseudo-element |
| Expand to content height | grid 0fr→1fr, or interpolate-size: allow-keywords |
| Many elements moving | Batch getBoundingClientRect reads, then writes |
| Smooth animation start | will-change just-in-time, remove when idle |
| Verify it's compositor-only | DevTools Performance: no purple "Layout"/green "Paint" per frame |
Gotchas
scaleX/scaleYstretches text and children; use FLIP when content must stay crisp.transformpercentages are relative to the element's own box, not the parent — different fromleft: %.- Overusing
will-changeortranslateZ(0)creates too many layers and *hurts* performance; promote only what animates. filterandbackdrop-filterare compositor-related but still expensive; animate their presence via opacity cross-fades rather than animating the blur radius.- The grid
1fr→0frcontent must haveoverflow: hiddenandmin-height: 0or it won't collapse. - Always gate non-essential motion behind
@media (prefers-reduced-motion: reduce).
Reference files
references/patterns-and-profiling.md— full runnable examples (accordion, reorder list, parallax), DevTools profiling walkthrough to confirm compositor-only frames, reduced-motion patterns, and a property-cost cheat sheet.
Sık sorulan sorular
60fps-animation skill'i ne yapar?
Web animasyon performansı rehberi, düzenin bozulmasını önlemek ve besteciye dost yöntemlerle saniyede 60/120 kareye kadar sorunsuz hareket elde etmek için.
60fps-animation nasıl kurulur?
Bu sayfadaki “Kurulum” bölümünü açın ve ajanınızı seçin — Claude Code, Codex, Cursor veya Gemini CLI: skill klasörünü doğru yere kopyalayan hazır komutlar orada. Ya da “Asistanla” sekmesindeki promptu kopyalayın; asistan skill'i inceleyip kuracaktır.
60fps-animation hangi yapay zekâlarla çalışır?
Skill'ler düz Markdown talimatlarıdır (Agent Skills formatı), bu yüzden 60fps-animation SKILL.md okuyan her ajanla çalışır: Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode ve diğerleri. Model talimatları yalnızca görev skill açıklamasına uyduğunda yükler.
60fps-animation ücretsiz mi?
Skill, iart-ai tarafından açık olarak yayımlandı (MIT lisansı). Skill'in kendisi ücretsizdir — yalnızca kullandığınız token'lar için yapay zekâ sağlayıcınıza ödeme yaparsınız.
Skill kurmak güvenli mi?
Skill, ajanınızın izleyeceği talimatlardır; kurmadan önce SKILL.md ve eşlik eden dosyaları okuyun. Skill klasöründeki betikler yalnızca ajanınız çalıştırırsa çalışır — ne yaptığını izleyin ve gereksiz izin vermeyin.
Skill, MCP sunucusu veya eklentiden nasıl farklıdır?
MCP sunucusu veya eklenti modele yeni araçlar verir — çalışıp sonuç döndüren kod. Skill ise bilgi ve süreç verir: göreve nasıl yaklaşılacağı, hangi adımların izleneceği ve iyi sonucun neye benzediği. Sunucu veya API anahtarı gerekmez.