Back home
Developer Reference

Animated Icons Library

Drop-in React components for hover-interactive GIF icons. Each icon decodes once and supports four playback variants — forward-and-reverse, looping, play-once, and mouse-X scrub. Designed for tool grids, nav menus, and feature showcases that need to feel alive.

The 4 Variants

Same source GIF — four different playback behaviors. Hover each preview to see it in action.

Demo icon: Video upload
1

Reverse on leave

reverseOnLeave

Plays forward on hover, plays backward when you leave. Feels physical, like a spring returning to rest.

Drop-in usage

jsx
<AnimatedIcon
  id="video-upload"
  variant="reverseOnLeave"
  hovered={hovered}
  className="w-24 h-24"
/>

When to use: Default — tool preview cards, nav icons

2

Loop on hover

loopOnHover

Loops forward continuously while hovered. Snaps back to frame 0 on leave.

Drop-in usage

jsx
<AnimatedIcon
  id="video-upload"
  variant="loopOnHover"
  hovered={hovered}
  className="w-24 h-24"
/>

When to use: Loading states, processing indicators

3

Play once

playOnce

Plays through once on hover and stops on the last frame. Resets to frame 0 on leave.

Drop-in usage

jsx
<AnimatedIcon
  id="video-upload"
  variant="playOnce"
  hovered={hovered}
  className="w-24 h-24"
/>

When to use: One-shot reactions, celebrations, notifications

4

Scrub on mouse X

scrubOnMouseX

Frame index follows your cursor across the icon. No requestAnimationFrame — direct mapping.

drag mouse across me

Drop-in usage

jsx
<AnimatedIcon
  id="video-upload"
  variant="scrubOnMouseX"
  hovered={hovered}
  className="w-24 h-24"
/>

When to use: Timeline scrubbers, before/after reveals, comparisons

Usage Patterns

Recommended

Drop-in card

Use AnimatedIconCard for tool grids. Handles hover state, link, and layout in one component.

card usage
import AnimatedIconCard from '@/components/animated-icons/AnimatedIconCard';

<AnimatedIconCard
  iconId="gif-pixelator"
  title="GIF Pixelator"
  description="Convert any GIF to 8-bit pixel art"
  to="/gif-pixelator"
/>
Advanced

Raw icon

Use AnimatedIcon directly when you need custom layout or hover triggers (e.g. parent-driven hover).

raw usage
import { useState } from 'react';
import AnimatedIcon from '@/components/animated-icons/AnimatedIcon';

function MyToolCard() {
  const [hovered, setHovered] = useState(false);
  return (
    <div onMouseEnter={() => setHovered(true)}
         onMouseLeave={() => setHovered(false)}>
      <AnimatedIcon
        id="gif-pixelator"
        hovered={hovered}
        className="w-24 h-24"
      />
    </div>
  );
}

Registered Icons(1)

Every icon currently registered in lib/hoverGif/registry.js. Hover any row to preview.

PreviewIDLabelVariantSpeedTags
video-uploadVideo uploadreverseOnLeave2×
uploadvideoconverter

Add a New Icon

Upload or paste a GIF, tweak the settings, preview it live, and copy the registry entry. Then paste it into lib/hoverGif/registry.js.

Icon Builder

Design → preview → copy registry entry

Add a GIF

auto from label

slowerfaster

Live preview

Add a GIF source
to start previewing

Paste this into ANIMATED_ICONS in lib/hoverGif/registry.js

registry entry
{
  id:      "my-icon",
  label:   "My Icon",
  src:     "https://your-cdn.com/icons/your-icon.gif",
  variant: "reverseOnLeave",
  speed:   2,
  bob:     true,
},

Field reference

  • id — stable string key (required)
  • label — short human name (required)
  • src — GIF URL (required, must be a real .gif)
  • variant — one of the 4 variants
  • speed — 0.25..3 (default 2)
  • bob — idle floating motion (default true)
  • tags — optional array for filtering

Tips for good icons

  • Keep GIFs under ~150KB for snappy decode
  • Square aspect ratios fit grids best
  • 10–20 frames is plenty for most icons
  • Loop-friendly motion works for all 4 variants
  • Test in the builder above before committing
Prefer to write it by hand? Show example+
registry entry
// lib/hoverGif/registry.js
export const ANIMATED_ICONS = [
  // ...existing entries
  {
    id: 'gif-pixelator',
    label: 'GIF Pixelator',
    src: 'https://your-cdn.com/icons/pixelator.gif',
    variant: 'reverseOnLeave',  // forward on hover, reverse on leave
    speed: 2,                   // 2× faster than the source GIF's frame delay
    bob: true,                  // gentle floating animation when idle
    tags: ['pixel', 'remix'],
  },
];

FAQ

What format does the source need to be in?+
A standard animated GIF. The component decodes it into individual canvas frames using gifuct-js so each frame can be played forward, backward, or scrubbed. APNG and WebP are not supported yet.
How does it perform with many icons on screen?+
Each icon decodes its GIF once on mount and caches the frames as HTMLCanvasElements. Drawing a frame is a single ctx.drawImage call. A grid of 30+ icons runs at 60fps in modern browsers. The bob animation is staggered with a random delay per icon so they don't pulse in lockstep.
Why not just use an <img> tag with the GIF?+
Native GIF playback can't be paused, reversed, or scrubbed. By decoding to canvas frames we get full control over playback direction, speed, and frame-accurate seeking — which is what makes the "rewind on leave" effect feel physical.
How do I add a new icon to the library?+
Append a new entry to ANIMATED_ICONS in lib/hoverGif/registry.js with a unique id, a label, a GIF url, and the variant you want. It will then be available everywhere via <AnimatedIcon id="your-id" /> and show up in this gallery automatically.
Can I override the variant per usage?+
Yes — pass variant, speed, or bob as props and they take precedence over the registry entry. Useful when the same source GIF should behave differently in different contexts.
Source files: components/animated-icons/ · lib/hoverGif/registry.jsPowered by gifuct-js + framer-motion