Animate svg
Create hand-crafted, dependency-free animated SVGs: self-drawing paths and signatures, loading spinners, morphing shapes, motion along a path, animated gradients, waves, pulses, and animated logos, icons, and badges — up to complex layered scenes with choreographed build-ins, particle fields, and parallax — choosing the right technique (CSS vs SMIL) for how the SVG is delivered (inline HTML, <img>, CSS background, GitHub README, favicon). Use when the user wants any animated SVG, asks to animate an existing SVG, icon, logo, or favicon, wants an animated scene, illustration, hero background, or banner, or mentions SMIL, stroke drawing, dashoffset, path or shape morphing, motion path, loader, spinner, animated checkmark, particles, parallax, or a "draws itself" effect.From its SKILL.md
npx -y skills add rajnandan1/such-skills --skill animate-svgAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.2 KB, as published. Nobody here has run it
Animate SVG
Hand-craft SVG animations with nothing but markup — no JS libraries, no build step. Every SVG element is a DOM node you can animate with CSS or native SMIL.
Workflow
- Pick the technique for the delivery context (table below). This decides everything else.
- Build the static artwork first and confirm it renders. Need path/shape/gradient/filter syntax? Read references/paths-and-shapes.md.
- Add animation. For SMIL (
<animate>, timing chains, easing, morphing) read references/smil.md. For ready-made patterns (spinner, checkmark, morphing menu icon, waves, shimmer, orbits) read references/recipes.md and adapt. For complex multi-element pieces — layered scenes, hero art, particles, parallax, choreographed build-ins — read references/complex-scenes.md and follow its storyboard-first method. - Accessibility pass (below) — every deliverable.
- Verify (below) — open it, watch it, check reduced motion.
Choose the technique
| Where the SVG will live | What runs there | Use |
|---|---|---|
| Inline in HTML / JSX | Everything: page CSS, JS, SMIL, :hover, click | CSS keyframes; JS only if it needs state |
<img>, CSS background-image, favicon, GitHub README | <style> inside the file and SMIL. No JS, no external CSS/fonts/images, no pointer events | CSS-in-SVG for simple loops; SMIL for chained, timed sequences |
| Needs interaction (hover, click-to-toggle) | Only inline SVG (or <object>) receives events | CSS :hover or SMIL begin="click" |
The most portable form is a single .svg file animating itself via an internal <style> block or SMIL — it works everywhere except where JS is required.
Non-negotiables
pathLength="100"on anything you stroke-animate. It normalizes the geometric length sostroke-dasharray/stroke-dashoffsetwork in 0–100 units. Never guess lengths, never reach forgetTotalLength(). Works on<path>,<circle>,<rect>,<line>,<polyline>,<polygon>in every evergreen browser — do not hand-compute circumferences "for legacy Safari". On closed shapes, make the dash slightly longer than the path (stroke-dasharray: 101) — an exact-length dash leaves a visible seam at the path start.- Author the resting state as the FINAL state; keyframes supply the start. Base styles show the finished artwork; the animation's
from/0%moves it back to the beginning. Then disabling animation (reduced motion, ancient renderer) shows the art — not a blank. - CSS transforms on SVG children need
transform-box: fill-box; transform-origin: center;— otherwisecentermeans the viewBox origin/center and your "spin in place" orbits the whole canvas. SMIL rotation takes the center inline instead:from="0 25 25" to="360 25 25". - Hold the end state: CSS
animation-fill-mode: both(orforwards); SMILfill="freeze". Staggered starts needboth/backwardsso delayed elements sit at theirfromstate during the delay. viewBoxalways; addwidth/heightattributes only to give an intrinsic size for<img>/favicon use.- Stay on the compositor: animate
transformandopacityfreely; animatingd, geometry attributes, gradients, or filters repaints every frame — keep those elements small and few. - Morphing
dinterpolates only between paths with the same command sequence (same count, types, order). - Seamless loops: first value equals last value (
values="A;B;A"), and easing splits symmetrically across the segments. - Stagger, don't dogpile: chain with
animation-delay/begin="id.end"so the eye follows one motion at a time. stroke-linecap="round"makes drawing effects look finished.
Accessibility
- Meaningful graphic:
role="img"on the<svg>plus a first-child<title>(add<desc>for detail). Decorative:aria-hidden="true". - Delivered via
<img>, the internal<title>is not announced — tell the user to also setalt="…"on the<img>/Markdown embed. - Ship reduced-motion handling inside the file so it travels with it. Because base styles are the final state (rule 2), this is just:
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; transition: none !important; }
}
- SMIL cannot be media-queried. When reduced-motion support matters and the target is
<img>-like, prefer CSS-in-SVG; if SMIL is unavoidable, keep the motion gentle (opacity fades, slow drifts — no spinning or flashing).
Canonical example — house style in one file
Self-drawing "success" badge for a README (<img>-safe, reduced-motion-safe, accessible):
<svg viewBox="0 0 52 52" width="52" height="52" role="img" xmlns="http://www.w3.org/2000/svg">
<title>Success</title>
<style>
.draw {
stroke-dasharray: 101; /* 101, not 100: exact-length dash seams on closed shapes */
stroke-dashoffset: 0; /* resting state = fully drawn */
animation: draw 0.6s ease-out both;
}
.check { animation-delay: 0.55s; }
@keyframes draw { from { stroke-dashoffset: 101; } }
@media (prefers-reduced-motion: reduce) {
.draw { animation: none; } /* still shows the finished badge */
}
</style>
<circle class="draw" cx="26" cy="26" r="23" pathLength="100"
fill="none" stroke="#22c55e" stroke-width="3"/>
<path class="draw check" d="M15 27l7 7 15-15" pathLength="100"
fill="none" stroke="#22c55e" stroke-width="4"
stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Note the pattern: pathLength="100" (no measured lengths), dash 101 (no seam on the closed circle), base state = finished, from keyframe = start, both makes the delayed check invisible until its turn, reduced-motion shows the final art.
Verify before delivering
- Save the file and open it in a real browser:
open out.svg(macOS) /xdg-open out.svg(Linux). - Watch a full cycle: end state holds (no snap-back), loops have no visible seam, nothing orbits off-center.
- Reduced motion: DevTools → Rendering → emulate
prefers-reduced-motion: reduce→ the finished artwork must be visible, not a blank canvas. - For
<img>/README targets, confirm the file is self-contained: no<script>, no externalhref/url()references, and interactivity-dependent triggers (begin="click",:hover) aren't load-bearing.