agentsclimarketplace

Fluid animations

Skill radustefandumitru/overdrive/skills/fluid-animations

Implement natural, Apple-quality fluid UI animation and gesture behavior. Use when coding or reviewing spring motion, Framer Motion/React animations, SwiftUI/UIKit animation, CSS transitions, drag/swipe/scroll interactions, rubberbanding, snap points, momentum projection, interruptible animations, press feedback, spatially consistent enter/exit transitions, or any interface motion that should feel tactile, responsive, and physically believable.From its SKILL.md

Install
npx -y skills add radustefandumitru/overdrive --skill fluid-animations

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 18 stars18 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

10.3 KB, ~2.3k tokens by cl100k_base, as published. Nobody here has run it

Fluid Animations

Use this skill to make UI motion feel connected to user intent instead of decorative, delayed, or generic. It is framework-agnostic: apply the principles in React/Framer Motion, SwiftUI, UIKit, CSS, native mobile, or any UI stack.

Detailed principles and formulas live in references/fluid-interface-principles.md. Load that reference when tuning a complex interaction, implementing gestures, auditing an existing animation system, or choosing spring/rubberband/projection behavior.

Routing With Other Skills

  • Pair with emil-design-eng for component feel, easing taste, button behavior, and visual polish.
  • Pair with design-taste-frontend for layout, visual direction, and anti-generic web UI.
  • Pair with modern-web-guidance when implementing modern CSS, browser APIs, dialogs, forms, accessibility, or performance-sensitive web behavior.
  • Pair with playwright-cli after implementation to verify the interaction in a real browser.

Motion Decision Tree

  1. If the motion responds to a user gesture, use a spring or dynamic behavior, not a fixed-duration easing curve.
  2. If the user can change their mind mid-motion, make the animation interruptible and retargetable.
  3. If an element enters or exits, preserve spatial consistency: it should leave toward the place it came from or belongs to.
  4. If a gesture ends with velocity, carry that velocity into the settle, snap, or dismiss animation.
  5. If content hits a boundary, use soft resistance/rubberbanding instead of a hard stop.
  6. If the motion is only decorative and not interactive, CSS transitions or keyframes are acceptable.
  7. If prefers-reduced-motion or an equivalent platform setting is active, reduce travel, bounce, parallax, blur, and looping motion while preserving state clarity.

Core Rules

  • Respond on press/down, not only on click/up. Buttons, cards, tabs, tiles, and handles should show immediate visual feedback.
  • Keep interactive motion continuously controllable. Avoid code that waits for an animation to finish before accepting a new target.
  • Avoid blocking interaction during transitions unless there is a real safety reason.
  • Use position plus velocity to infer intent. For snap points, project momentum and snap from the projected endpoint, not from the current position alone.
  • Start with no overshoot for utilitarian UI. Add bounce only when the triggering gesture had momentum or when bounce teaches a deeper interaction.
  • Make related animations feel like a family. Reuse a small set of spring tokens rather than hand-tuning every component.
  • Prefer transform and opacity for web animation. Avoid animating layout-heavy properties in high-frequency interactions.

Spring Tokens

Create shared tokens in the target codebase instead of scattering raw numbers. Tune per product, but start with a restrained family:

export const fluidSprings = {
  instant: { type: "spring", stiffness: 700, damping: 45, mass: 0.7 },
  snappy: { type: "spring", stiffness: 520, damping: 38, mass: 0.8 },
  standard: { type: "spring", stiffness: 360, damping: 34, mass: 1 },
  heavy: { type: "spring", stiffness: 260, damping: 32, mass: 1.35 },
  momentum: { type: "spring", stiffness: 320, damping: 24, mass: 1 },
  settle: { type: "spring", stiffness: 420, damping: 44, mass: 1 }
} as const;

Use instant or snappy for press feedback, standard for panels/cards, heavy for full-screen surfaces, momentum for gesture releases with velocity, and settle for no-overshoot tap-triggered state changes.

React And Framer Motion Patterns

Use Framer Motion for gesture-driven, interruptible, or physics-based motion:

import { AnimatePresence, animate, motion, useMotionValue, useReducedMotion } from "framer-motion";
import { fluidSprings } from "@/lib/fluid-springs";

function DismissiblePanel({ open, onDismiss, children }) {
  const reduceMotion = useReducedMotion();
  const y = useMotionValue(0);

  return (
    <AnimatePresence>
      {open && (
        <motion.section
          initial={{ y: reduceMotion ? 0 : "100%", opacity: reduceMotion ? 0 : 1 }}
          animate={{ y: 0, opacity: 1 }}
          exit={{ y: reduceMotion ? 0 : "100%", opacity: reduceMotion ? 0 : 1 }}
          transition={reduceMotion ? { duration: 0.12 } : fluidSprings.heavy}
          style={{ y }}
          drag={reduceMotion ? false : "y"}
          dragConstraints={{ top: 0, bottom: 0 }}
          dragElastic={0.18}
          onDragEnd={(_, info) => {
            if (info.velocity.y > 700 || info.offset.y > 180) {
              animate(y, window.innerHeight, {
                ...fluidSprings.momentum,
                velocity: info.velocity.y,
                onComplete: onDismiss
              });
            } else {
              animate(y, 0, { ...fluidSprings.settle, velocity: info.velocity.y });
            }
          }}
        >
          {children}
        </motion.section>
      )}
    </AnimatePresence>
  );
}

Use whileTap/pressed states for immediate response:

<motion.button
  whileTap={{ scale: 0.97 }}
  transition={fluidSprings.instant}
  onClick={commitAction}
>
  Continue
</motion.button>

SwiftUI And UIKit Patterns

  • In SwiftUI, prefer .spring(response:dampingFraction:blendDuration:) or interactive spring APIs over fixed duration for interactive elements.
  • In UIKit, prefer UIViewPropertyAnimator with UISpringTimingParameters when an animation needs to be interruptible, scrubbed, paused, or retargeted.
  • Carry gesture velocity from DragGesture, UIPanGestureRecognizer, or scroll data into the final animation.
  • Keep touch-down highlighting separate from action confirmation: highlight immediately, commit on release/up inside the target, cancel when released outside.

CSS Use

Use CSS for simple hover/focus/color/opacity changes and decorative keyframes. Keep it restrained:

.pressable {
  transition:
    transform 160ms cubic-bezier(0.25, 1, 0.5, 1),
    opacity 160ms cubic-bezier(0.25, 1, 0.5, 1);
}

.pressable:active {
  transform: scale(0.97);
}

@media (prefers-reduced-motion: reduce) {
  .pressable {
    transition-duration: 80ms;
  }
}

Avoid using CSS-only fixed-duration transitions for drag, throw, snap, route transitions that can be interrupted, or state changes where the user's next input may arrive before the motion completes.

Proximity Interaction Pattern

Use proximity effects sparingly for dock-like toolbars, playful icon strips, spatial menus, and premium landing-page details where nearby elements should respond to pointer distance. The effect should feel like a soft field around the cursor, not a noisy hover gimmick.

Performance rule: do not call getBoundingClientRect() on every pointermove. Cache item centers once, recompute on resize/layout changes with ResizeObserver, then use pointer coordinates against the cached centers.

type ProximityItem = {
  el: HTMLElement;
  cx: number;
  cy: number;
};

function setupProximityDock(container: HTMLElement) {
  let items: ProximityItem[] = [];

  const measure = () => {
    items = [...container.querySelectorAll<HTMLElement>("[data-proximity-item]")].map((el) => {
      const rect = el.getBoundingClientRect();
      return { el, cx: rect.left + rect.width / 2, cy: rect.top + rect.height / 2 };
    });
  };

  const render = (event: PointerEvent) => {
    for (const item of items) {
      const distance = Math.hypot(event.clientX - item.cx, event.clientY - item.cy);
      const influence = Math.max(0, 1 - distance / 160);
      item.el.style.setProperty("--proximity", influence.toFixed(3));
    }
  };

  const reset = () => {
    for (const item of items) item.el.style.setProperty("--proximity", "0");
  };

  const observer = new ResizeObserver(measure);
  observer.observe(container);
  measure();

  container.addEventListener("pointermove", render);
  container.addEventListener("pointerleave", reset);

  return () => {
    observer.disconnect();
    container.removeEventListener("pointermove", render);
    container.removeEventListener("pointerleave", reset);
  };
}
[data-proximity-item] {
  --proximity: 0;
  transform: translateZ(0) scale(calc(1 + var(--proximity) * 0.18));
  filter: brightness(calc(1 + var(--proximity) * 0.14));
  transition:
    transform 180ms cubic-bezier(0.23, 1, 0.32, 1),
    filter 180ms cubic-bezier(0.23, 1, 0.32, 1);
}

@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  [data-proximity-item] {
    transform: none;
    filter: none;
  }
}

Credit the public pattern inspiration to @gabriell_lab (https://x.com/gabriell_lab/status/2060336070059864461) and the rect-caching/ResizeObserver performance correction to @baptistebriel (https://x.com/baptistebriel/status/2060351541345681851) when documenting or sharing this pattern.

Gesture Checklist

  • Tap: highlight on down, commit on up, allow cancellation outside the hit area and re-entry back inside.
  • Drag/swipe: use a small hysteresis threshold before committing direction, then track finger/content one-to-one.
  • Snap: project momentum, choose the nearest endpoint to the projected position, then animate there with carried velocity.
  • Boundary: apply rubberband resistance past the edge, then settle back smoothly.
  • Multi-gesture surfaces: begin detecting possible gestures in parallel; cancel competing interpretations only once intent is clear.

Review Checklist

Before finishing motion work, verify:

  • Immediate response exists for every interactive element.
  • In-flight animations can be interrupted or retargeted.
  • Enter and exit paths are spatially consistent.
  • Gesture velocity is preserved into release animations.
  • Snap points use projected momentum when flicks should matter.
  • Boundaries feel soft, not frozen.
  • Bounce is purposeful, not default decoration.
  • Reduced-motion behavior is implemented.
  • Browser/native testing confirms no jank, layout shift, text overlap, or accidental blocked input.

What ships with it: 2 files

10.1 KB alongside SKILL.md

agents/

Gives 0 of the 12 instructions most css styling skills give in ~2.3k tokens

Counted across 512 of the 512 authors here whose files we hold, read 2026-09-06

  • Animate only transform and opacityin 32 of 512, across 30 files
  • Respect prefers-reduced-motionin 21 of 512
  • Support reduced motion preferencesin 16 of 512, across 6 files
  • Use Tailwind CSS for stylingin 14 of 512, across 13 files
  • Specify AnimatePresence mode explicitlyin 12 of 512, across 2 files
  • Set initial states explicitlyin 12 of 512, across 2 files
  • Use semantic HTML elementsin 11 of 512, across 10 files
  • Use oklch for color valuesin 11 of 512, across 10 files
  • Honor prefers-reduced-motion in animationsin 10 of 512
  • Provide a reduced-motion fallback for animationsin 10 of 512, across 9 files
  • Use property names in camelCasein 9 of 512, across 4 files
  • Ensure UI animations stay under 300msin 9 of 512, across 6 files

Said here and by no other author read

  • Make animations interruptible and retargetable
  • Preserve spatial consistency for entering elements
  • Carry gesture velocity into the settle animation
  • Use soft resistance when content hits boundaries
  • Respond immediately on press down
  • Keep interactive motion continuously controllable

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.