Loading...
Loading...
This skill should be used when the user asks to "animate this diagram", "build a flowchart that reveals step by step", "animate an architecture/sequence diagram", "make a chart animate in", "grow the bars / draw the line / count up the number", "show data flowing along a connector", or "turn a static diagram into a guided reveal". Covers SVG, Framer Motion, D3, and Remotion.
npx skill4agent add iart-ai/explainer-video-skills diagram-animation| Goal | Mechanism | Easing |
|---|---|---|
| Node appear | scale 0.8→1 + opacity, | |
| Edge connect | | |
| Flowing data | animate | |
| Bar grow | | |
| Line chart | path | |
| Count-up | interpolate value with eased | |
| Highlight | active full-opacity, others | 0.3s |
<svg viewBox="0 0 400 200" id="flow">
<g class="node" opacity="0"><circle cx="60" cy="100" r="28" fill="#0A84FF"/></g>
<g class="node" opacity="0"><circle cx="200" cy="100" r="28" fill="#0A84FF"/></g>
<g class="node" opacity="0"><circle cx="340" cy="100" r="28" fill="#0A84FF"/></g>
<path class="edge" d="M88 100 H172" stroke="#888" stroke-width="3" fill="none" pathLength="1"/>
<path class="edge" d="M228 100 H312" stroke="#888" stroke-width="3" fill="none" pathLength="1"/>
</svg>
<script type="module">
import gsap from "https://cdn.jsdelivr.net/npm/gsap/+esm";
gsap.set(".edge", { strokeDasharray: 1, strokeDashoffset: 1 });
const tl = gsap.timeline({ defaults: { ease: "power2.out" } });
tl.to(".node", { opacity: 1, scale: 1, transformOrigin: "center",
duration: .45, stagger: .35, ease: "back.out(1.6)", startAt: { scale: .8 } })
.to(".edge", { strokeDashoffset: 0, duration: .5, stagger: .35 }, "-=0.9");
</script>pathLength="1".flow-line { stroke-dasharray: 8 8; animation: march 0.6s linear infinite; }
@keyframes march { to { stroke-dashoffset: -16; } } /* = sum of dash pattern */
@media (prefers-reduced-motion: reduce){ .flow-line { animation: none; } }offset-path.packet { offset-path: path("M88 100 H312"); animation: travel 1.4s linear infinite; }
@keyframes travel { to { offset-distance: 100%; } }.bar { transform: scaleY(0); transform-origin: bottom; }
.bar.in { transform: scaleY(1); transition: transform .6s cubic-bezier(.22,1,.36,1); }
/* stagger via inline transition-delay per bar */const len = pathEl.getTotalLength();
pathEl.style.strokeDasharray = len;
pathEl.style.strokeDashoffset = len;
pathEl.getBoundingClientRect(); // force reflow
pathEl.style.transition = "stroke-dashoffset 1s ease-in-out";
pathEl.style.strokeDashoffset = "0";function countUp(el, to, dur = 1200) {
const t0 = performance.now();
const fmt = new Intl.NumberFormat();
(function tick(now){
const k = Math.min(1, (now - t0) / dur);
const e = 1 - Math.pow(1 - k, 3); // easeOutCubic
el.textContent = fmt.format(Math.round(to * e));
if (k < 1) requestAnimationFrame(tick);
})(t0);
}variantsstaggerChildren.transition().duration().attr()tweenprefers-reduced-motionPackaged helper ():scripts/freezes thescripts/seek-shot.sh anim.html 0 1.5 3harness and screenshots each moment;?t=Ntiles them for one-glance review. Seescripts/contact-sheet.sh sheet.png frame-*.png.scripts/README.md
remotion still.html<script>tl?t=Ntl.pause(); tl.seek(N)svg.pauseAnimations(); svg.setCurrentTime(N)animationDelay<script>
// ... build your master timeline as `tl` ...
const t = new URLSearchParams(location.search).get("t");
if (t !== null) { tl.pause(); tl.seek(parseFloat(t)); } // frozen at t seconds
window.__ready = true; // ready signal for headless wait
console.log("duration", tl.duration());
</script>…/diagram.html?t=0?t=<dur/2>?t=<dur>tl.duration()npx playwright screenshot --wait-for-timeout=500 "file://$PWD/diagram.html?t=1.2" frame-mid.png?t=NsetCurrentTimeprefers-reduced-motionreferences/diagram-and-chart-recipes.md