Communitygithub.com

nehakanjamala/personal_website

This skill should be used when the user asks to "animate an SVG", "make a line draw itself on", "do a stroke draw-on / signature animation", "morph one shape into another", "move an element along a path", "animate an icon/logo", or "animate an SVG gradient or filter". Covers stroke-dashoffset draw-on, path morphing, motion-along-path, and animated icons/gradients/filters via CSS, SMIL, and GSAP.

What is personal_website?

personal_website is a Claude Code agent skill that this skill should be used when the user asks to "animate an SVG", "make a line draw itself on", "do a stroke draw-on / signature animation", "morph one shape into another", "move an element along a path", "animate an icon/logo", or "animate an SVG gradient or filter". Covers stroke-dashoffset draw-on, path morphing, motion-along-path, and animated icons/gradients/filters via CSS, SMIL, and GSAP.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/nehakanjamala/personal_website/tree/HEAD/.agents/skills/svg-animation

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

SVG Animation

Crisp, lightweight, infinitely scalable vector motion — ideal for icons, illustrations, logos, and data marks. SVG can be animated three ways: CSS (declarative, simple), SMIL (<animate> inside the SVG), and JS (GSAP/Web Animations, for control and morphing). Choose per task; the techniques below say which.

When to use

  • Stroke "draw-on" of icons, illustrations, signatures, maps
  • Shape/path morphing and animated icon state changes (menu ↔ close, play ↔ pause)
  • Moving an element along a path (motion path)
  • Animated gradients, filters (glow, displacement), and animated logos

Core techniques

Stroke draw-on (the staple)

Draw the dash array as long as the path, offset it fully (invisible), then animate the offset to 0.

.path {
  stroke-dasharray: var(--len);
  stroke-dashoffset: var(--len);
  animation: draw 1.4s ease forwards;
}
@keyframes draw { to { stroke-dashoffset: 0; } }

Getting the length:

  • JS (most reliable): const len = path.getTotalLength(); path.style.setProperty("--len", len);
  • No-JS trick: set pathLength="1" on the <path>, then stroke-dasharray: 1; stroke-dashoffset: 1; and animate to 0. This normalizes any path to a 0–1 length so no measurement is needed.

Reverse (erase) by animating offset from 0 back to len. Stagger multiple paths with animation-delay. Direction of drawing follows the path's point order; reverse it in the editor or negate the offset sign if it draws "backwards".

Morphing one path into another

Paths interpolate point-by-point, so a naive morph requires both d attributes to have the same number and type of commands. Two robust approaches:

  • GSAP MorphSVG (free as of GSAP 3.12) — handles mismatched point counts automatically and finds a good mapping:
gsap.registerPlugin(MorphSVGPlugin);
gsap.to("#start", { morphSVG: "#end", duration: 0.8, ease: "power2.inOut" });
// Convert any shape to a morph-able path:
MorphSVGPlugin.convertToPath("circle, rect, ellipse, line, polygon");
  • Flubber (small standalone lib) — generates interpolators without GSAP, good with React/Framer Motion:
import { interpolate } from "flubber";
const interpolator = interpolate(pathA, pathB, { maxSegmentLength: 2 });
// interpolator(0) === pathA, interpolator(1) === pathB; feed t into a tween.

For hand-authored morphs (icon toggles), keep both paths with identical command structure and animate d directly via Web Animations or CSS (d is animatable in modern browsers via path("...")).

Motion along a path

  • GSAP MotionPath (preferred — control, alignment, scrub):
gsap.registerPlugin(MotionPathPlugin);
gsap.to("#rocket", {
  duration: 4, repeat: -1, ease: "none",
  motionPath: { path: "#track", align: "#track", autoRotate: true, alignOrigin: [0.5, 0.5] },
});

autoRotate: true orients the object to the path tangent; align makes coordinates relative to the path element.

  • SMIL (no JS):
<path id="track" d="M10,80 C40,10 120,10 150,80" fill="none"/>
<circle r="6" fill="#3b82f6">
  <animateMotion dur="3s" repeatCount="indefinite" rotate="auto">
    <mpath href="#track"/>
  </animateMotion>
</circle>
  • CSS offset-path (modern, declarative): offset-path: path("M10,80 C..."); animation: move 3s linear infinite; with @keyframes move { to { offset-distance: 100%; } } and offset-rotate: auto.

Animated gradients and filters

Gradients: animate gradientTransform or stop offsets. A sheen sweep:

<linearGradient id="sheen">
  <stop offset="0%"  stop-color="#fff" stop-opacity="0"/>
  <stop offset="50%" stop-color="#fff" stop-opacity=".8"/>
  <stop offset="100%" stop-color="#fff" stop-opacity="0"/>
  <animateTransform attributeName="gradientTransform" type="translate"
    from="-1 0" to="1 0" dur="2s" repeatCount="indefinite"/>
</linearGradient>

Filters: animate feDisplacementMap scale for gooey/wobble, feGaussianBlur stdDeviation for focus pulls, or feColorMatrix/feFlood for glow. Filters are paint-heavy — animate sparingly and prefer transform/opacity where possible.

Implementation choice (pick fast)

NeedUse
Single declarative draw/fadeCSS
Self-contained, no JS bundleSMIL (<animate*> in the SVG)
Coordinated, scrubbable, scroll-tiedGSAP
Mismatched-point morphGSAP MorphSVG or Flubber
Path following with rotationGSAP MotionPath / CSS offset-path

SMIL caveat: not supported in IE/old Edge and historically deprecation-flagged; for max reach or scroll-syncing, prefer CSS or JS. SMIL is still fine for self-contained icon assets in evergreen browsers.

Authoring and optimization

  • Build/clean with SVGO: keep viewBox, drop editor metadata, but disable cleanupIds/removeViewBox and any plugin that renames IDs you reference from CSS/JS/SMIL. Disable mergePaths and convertShapeToPath if you animate individual sub-paths or shapes.
  • Inline the SVG in the DOM (not <img src>) so CSS/JS can reach its internals; <img>-embedded SVG can only self-animate via internal SMIL/CSS.
  • Set explicit viewBox and avoid fixed width/height so the asset scales fluidly.
  • For draw-on, ensure paths are actual strokes (fill:none; stroke:...), not filled outlines — dashoffset only affects strokes.
  • Respect prefers-reduced-motion: gate looping/large motion; keep a static final state.

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.

For a self-contained icon/logo/draw-on the deliverable is one HTML file that opens directly in a browser — inline the SVG in the markup, drive the animation with one mechanism, no build step. One file is the right tier for a vector asset; don't reach for a bundler.

Output contract:

  • One .html file: inline <svg>, plus CSS @keyframes / a <script> with GSAP from CDN / SMIL <animate*> — pick one driver.
  • Include the seek harness matching that driver so any moment can be frozen for a screenshot.

Seek harness — freeze an exact moment. ?t=N seeks and pauses so a screenshot lands on a still frame. Use the mechanism that matches how the SVG animates:

<script>
  const t = new URLSearchParams(location.search).get("t");
  if (t !== null) {
    const N = parseFloat(t);
    // SMIL: pause the SVG's own clock and scrub it
    const svg = document.querySelector("svg");
    svg.pauseAnimations(); svg.setCurrentTime(N);
    // CSS @keyframes draw-on: el.style.animationDelay=(-N)+"s"; el.style.animationPlayState="paused";
    // GSAP timeline: tl.pause(); tl.seek(N);
  }
  window.__ready = true;
</script>

Verify loop — render → freeze → screenshot → check: open the file at start / mid / end (?t=0, ?t=<dur/2>, ?t=<dur>), screenshot each, and check fidelity (stroke draws in the right direction, morph endpoints clean) plus artifacts (path clipped by viewBox, stroke vanishing from a stale dashoffset, FOUC, jank at the morph seam). Any headless tool works:

npx playwright screenshot --wait-for-timeout=500 "file://$PWD/icon.html?t=0.7" frame-mid.png

Before you finish:

  1. Opens standalone — no console errors, inline SVG reachable, CDN (if any) loads.
  2. The seek mechanism for your driver freezes a deterministic frame.
  3. Screenshotted at start / mid / end — matches the brief, no clipping or off-viewBox strokes.
  4. prefers-reduced-motion honored — looping/large motion gated, static final state kept.
  5. Easing is intentional — ease/GSAP ease chosen on purpose, no accidental linear draw-on.

Reference files

  • references/svg-techniques.md — full dashoffset math and getTotalLength gotchas, the pathLength="1" normalization, GSAP MorphSVG vs Flubber decision guide with code, an icon-toggle morph (hamburger↔close), MotionPath/offset-path details, SMIL-vs-CSS-vs-JS tradeoffs, and an SVGO config tuned for animation.

Individual skills in this repo

This repo contains 13 individual skills — each has its own dedicated page.

nehakanjamala/personal_website

This skill should be used when the user asks to "fix janky CSS animation", "make animation 60fps", "stop layout thrashing", "animate width/height/top/left smoothly", "convert animation to transform", "animate box-shadow performantly", "animate height auto", "FLIP animation", or "why is my scroll/hover animation choppy".

nehakanjamala/personal_website

This skill should be used when the user asks to "respect prefers-reduced-motion", "honor reduced motion", "make my animations accessible", "fix vestibular / motion-sickness issues", "add a useReducedMotion hook", "gate GSAP / Framer Motion / Lenis for reduced motion", or "meet WCAG 2.3.3 / C39". Provides tiered (not all-or-nothing) reduced-motion patterns in CSS and JS.

nehakanjamala/personal_website

Create, modify, debug, and deploy Apify Actors, and write their input and output schemas. Use when building an Actor from scratch, changing or troubleshooting Actor code, generating or updating .actor schema files, or pushing an Actor to the Apify platform. To wrap an existing non-Actor project, use apify-actorization instead.

nehakanjamala/personal_website

Convert existing projects into Apify Actors - serverless cloud programs. Actorize JavaScript/TypeScript (SDK with Actor.init/exit), Python (async context manager), or any language (CLI wrapper). Use when migrating code to Apify, wrapping CLI tools as Actors, or adding Actor SDK to existing projects.

nehakanjamala/personal_website

Deprecated. Output schema generation moved to the apify-actor-development skill; prefer that skill whenever it is available.

nehakanjamala/personal_website

Design and build an official Apify integration for a company's product - workflow-automation apps (Zapier/n8n-style), AI agent plugins (coding-agent skills+MCP bundles or OpenClaw/Hermes-style harnesses), AI framework packages (LangChain/LlamaIndex-style), or direct application clients via apify-client. Use when planning, creating, or reviewing an integration that exposes Apify Actors, runs, datasets, or key-value stores inside another product.

nehakanjamala/personal_website

Universal AI-powered web scraper for any platform. Scrape data from Instagram, Facebook, TikTok, YouTube, LinkedIn, X/Twitter, Google Maps, Google Search, Google Trends, Reddit, Airbnb, Yelp, and 15+ more platforms. Use for lead generation, brand monitoring, competitor analysis, influencer discovery, trend research, content analytics, audience analysis, review analysis, SEO intelligence, recruitment, or any data extraction task.

nehakanjamala/personal_website

This skill should be used when the user asks to "add a glassmorphism effect", "frosted glass UI", "Apple liquid glass style", "frosted blur card", "translucent glass panel animation", "make a frosted nav bar", "build a glass modal/dialog", "animate a glass card on hover", or "add a refracting liquid-glass hero". Covers frosted translucent panels with backdrop-filter blur, edge/specular highlights, SVG liquid-glass refraction, motion on hover/scroll/enter, and accessible reduced-transparency fallbacks.

nehakanjamala/personal_website

This skill should be used when the user asks to "build a scroll animation", "add ScrollTrigger", "pin a section while scrolling", "scrub an animation to scroll", "create a hero timeline", "do a horizontal scroll section", "split text and animate words", "animate a layout change with GSAP Flip", "sync ScrollTrigger with Lenis", "Lenis smooth scroll jittery", "ScrollTrigger markers drift", "ScrollTrigger pins break with Lenis/Locomotive", or "set up smooth scroll with GSAP pinning". Covers GSAP timelines, ScrollTrigger, SplitText, Flip, and Lenis/Locomotive smooth-scroll sync for code-driven web motion.

nehakanjamala/personal_website

This skill should be used when the user asks to "add a Lottie animation", "play a .lottie or .json animation", "integrate a Bodymovin/After Effects animation on web or mobile", "control Lottie playback / segments", "make a scroll-driven Lottie", "recolor a Lottie at runtime", or "export an AE animation to Lottie". Covers dotLottie/lottie-web integration, playback control, interactivity, theming, and the AE export checklist.

nehakanjamala/personal_website

This skill should be used when the user asks to "add a hover/press effect", "animate a toggle or switch", "build an animated like button", "make a toast/snackbar slide in", "animate a drawer or modal", "animate list reordering or add/remove", "do a shared-element layout transition", or "polish UI feedback". Covers UI motion with Framer Motion (motion/react) and modern CSS.

nehakanjamala/personal_website

This skill should be used when the user asks to "animate page or route transitions", "add a page transition or crossfade between views", "animate route changes in Next.js App Router", "use the View Transitions API", "AnimatePresence exit doesn't fire on navigation", or "Framer Motion exit animation not working / exit animation before unmount in Next.js". Covers enter/exit page-transition animation with the View Transitions API and Framer Motion, for Next.js App Router and general SPA routing.

nehakanjamala/personal_website

Scrape web pages using Scrapling with anti-bot bypass (like Cloudflare Turnstile), stealth headless browsing, spiders framework, adaptive scraping, and JavaScript rendering. Use when asked to scrape, crawl, or extract data from websites; web_fetch fails; the site has anti-bot protections; write Python code to scrape/crawl; or write spiders.

Related Skills