agentsclimarketplace

Motion base ui

Skill gokulkrishh/skills/skills/motion-base-ui

Animating Base UI components with Motion for React. Use this skill when implementing animations on Base UI components (Menu, Dialog, Popover, Tooltip, Switch, etc.) with the Motion library. Triggers on: motion animation, base-ui animate, animate dropdown, animate dialog, animate popover, exit animation, spring animation, render prop animation, AnimatePresence base-ui.From its SKILL.md

Install
npx -y skills add gokulkrishh/skills --skill motion-base-ui

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

One thing to look at

  • 3 stars3 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

4.7 KB, as published. Nobody here has run it

Animating Base UI with Motion for React

Instructions

When animating Base UI components with Motion, follow these rules strictly.

Importing

  • Always import from motion/react, never from framer-motion
import { motion, AnimatePresence } from "motion/react";

Base UI + Motion Integration

Pass a motion component via the Base UI render prop. Never use the function/spread props approach as this causes type errors.

<Menu.Popup
  render={<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} />}
>
  {/* Children */}
</Menu.Popup>

Exit Animations

Some Base UI components (ContextMenu, Popover, Dialog) control their own conditional rendering. To add exit animations:

  1. Hoist the open state with useState
  2. Add keepMounted to the Portal component
  3. Wrap the Portal in AnimatePresence
function App() {
  const [open, setOpen] = useState(false);
  return (
    <Dialog.Root open={open} onOpenChange={setOpen}>
      <Dialog.Trigger>Open</Dialog.Trigger>
      <AnimatePresence>
        {open && (
          <Dialog.Portal keepMounted>
            <Dialog.Backdrop
              render={
                <motion.div
                  initial={{ opacity: 0 }}
                  animate={{ opacity: 1 }}
                  exit={{ opacity: 0 }}
                />
              }
            />
            <Dialog.Popup
              render={
                <motion.div
                  initial={{ opacity: 0, scale: 0.95 }}
                  animate={{ opacity: 1, scale: 1 }}
                  exit={{ opacity: 0, scale: 0.95 }}
                />
              }
            >
              {/* Content */}
            </Dialog.Popup>
          </Dialog.Portal>
        )}
      </AnimatePresence>
    </Dialog.Root>
  );
}

Note: Portal keeps the tree mounted as long as Base UI detects animations via element.getAnimations(). Motion runs opacity, transform, filter, and clipPath via hardware acceleration, so ensure at least one of these is used for exit animations.

Performance

  • Add willChange: "transform" when animating transform, x, y, scale, etc.
  • Also add opacity, clipPath, or filter to willChange if animating those
  • Only these values are valid for willChange: transform, opacity, clipPath, filter
  • Prefer animating transform over independent transforms (x, y, scaleX) for hardware acceleration
  • Use independent transforms when composing multiple competing transforms:
animate(element, { x: 100 });
hover(() => {
  animate(element, { scale: 1.2 });
  return () => animate(element, { scale: 1 });
});
  • Always use independent transforms when defining any transform via style:
<motion.div animate={{ x: 100 }} style={{ scale: 2 }} />

Motion Values

  • Use value.on("change", update), never value.onChange(update)
  • Use value.stop() to end current animation — don't track animation in a variable
  • Starting a new animation on a value automatically stops the current one

animate Function

Three valid syntaxes:

// Motion value
animate(motionValue, targetValue, options);

// Origin to target (add onUpdate to options)
animate(originValue, targetValue, { onUpdate: (v) => {} });

// Element or object
animate(element, { opacity: 1 }, options);

Variant Propagation

Use initial/whileHover/whileTap on parent motion.* elements. Children with matching variants keys inherit the active variant automatically — no animate prop needed:

<motion.li initial="idle" whileHover="hover">
  <motion.span
    variants={{
      idle: { scale: 1 },
      hover: { scale: 1.2 },
    }}
  />
</motion.li>

Easing

  • Easing is defined via the ease option in camelCase: easeOut, easeInOut
  • Spring config via lib/springs.ts:
import { springs } from "@/lib/springs";

animate(motionX, targetX, springs.moderate);

// or
<motion.div transition={springs.moderate} />;

Rules

  • Never import from framer-motion
  • Always use render prop for Base UI + Motion, never function/spread
  • Use AnimatePresence + keepMounted for exit animations on portalled components
  • Prefer willChange over transform: translateZ(0)
  • Use camelCase for easing: easeOut not ease-out

Keep looking

Skills are one crate of 627,801. 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.