Claude Agent Skill · by Wshobson

Interaction Design

Creates smooth, purposeful animations and microinteractions using Framer Motion, CSS transitions, and gesture libraries. Handles the full spectrum from button h

Install
Terminal · npx
$npx skills add https://github.com/wshobson/agents --skill interaction-design
Works with Paperclip

How Interaction Design fits into a Paperclip company.

Interaction Design drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.

S
SaaS FactoryPaired

Pre-configured AI company — 18 agents, 18 skills, one-time purchase.

$27$59
Explore pack
Source file
SKILL.md320 lines
Expand
---name: interaction-designdescription: Design and implement microinteractions, motion design, transitions, and user feedback patterns. Use when adding polish to UI interactions, implementing loading states, or creating delightful user experiences.--- # Interaction Design Create engaging, intuitive interactions through motion, feedback, and thoughtful state transitions that enhance usability and delight users. ## When to Use This Skill - Adding microinteractions to enhance user feedback- Implementing smooth page and component transitions- Designing loading states and skeleton screens- Creating gesture-based interactions- Building notification and toast systems- Implementing drag-and-drop interfaces- Adding scroll-triggered animations- Designing hover and focus states ## Core Principles ### 1. Purposeful Motion Motion should communicate, not decorate: - **Feedback**: Confirm user actions occurred- **Orientation**: Show where elements come from/go to- **Focus**: Direct attention to important changes- **Continuity**: Maintain context during transitions ### 2. Timing Guidelines | Duration  | Use Case                                  || --------- | ----------------------------------------- || 100-150ms | Micro-feedback (hovers, clicks)           || 200-300ms | Small transitions (toggles, dropdowns)    || 300-500ms | Medium transitions (modals, page changes) || 500ms+    | Complex choreographed animations          | ### 3. Easing Functions ```css/* Common easings */--ease-out: cubic-bezier(0.16, 1, 0.3, 1); /* Decelerate - entering */--ease-in: cubic-bezier(0.55, 0, 1, 0.45); /* Accelerate - exiting */--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1); /* Both - moving between */--spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* Overshoot - playful */``` ## Quick Start: Button Microinteraction ```tsximport { motion } from "framer-motion"; export function InteractiveButton({ children, onClick }) {  return (    <motion.button      onClick={onClick}      whileHover={{ scale: 1.02 }}      whileTap={{ scale: 0.98 }}      transition={{ type: "spring", stiffness: 400, damping: 17 }}      className="px-4 py-2 bg-blue-600 text-white rounded-lg"    >      {children}    </motion.button>  );}``` ## Interaction Patterns ### 1. Loading States **Skeleton Screens**: Preserve layout while loading ```tsxfunction CardSkeleton() {  return (    <div className="animate-pulse">      <div className="h-48 bg-gray-200 rounded-lg" />      <div className="mt-4 h-4 bg-gray-200 rounded w-3/4" />      <div className="mt-2 h-4 bg-gray-200 rounded w-1/2" />    </div>  );}``` **Progress Indicators**: Show determinate progress ```tsxfunction ProgressBar({ progress }: { progress: number }) {  return (    <div className="h-2 bg-gray-200 rounded-full overflow-hidden">      <motion.div        className="h-full bg-blue-600"        initial={{ width: 0 }}        animate={{ width: `${progress}%` }}        transition={{ ease: "easeOut" }}      />    </div>  );}``` ### 2. State Transitions **Toggle with smooth transition**: ```tsxfunction Toggle({ checked, onChange }) {  return (    <button      role="switch"      aria-checked={checked}      onClick={() => onChange(!checked)}      className={`        relative w-12 h-6 rounded-full transition-colors duration-200        ${checked ? "bg-blue-600" : "bg-gray-300"}      `}    >      <motion.span        className="absolute top-1 left-1 w-4 h-4 bg-white rounded-full shadow"        animate={{ x: checked ? 24 : 0 }}        transition={{ type: "spring", stiffness: 500, damping: 30 }}      />    </button>  );}``` ### 3. Page Transitions **Framer Motion layout animations**: ```tsximport { AnimatePresence, motion } from "framer-motion"; function PageTransition({ children, key }) {  return (    <AnimatePresence mode="wait">      <motion.div        key={key}        initial={{ opacity: 0, y: 20 }}        animate={{ opacity: 1, y: 0 }}        exit={{ opacity: 0, y: -20 }}        transition={{ duration: 0.3 }}      >        {children}      </motion.div>    </AnimatePresence>  );}``` ### 4. Feedback Patterns **Ripple effect on click**: ```tsxfunction RippleButton({ children, onClick }) {  const [ripples, setRipples] = useState([]);   const handleClick = (e) => {    const rect = e.currentTarget.getBoundingClientRect();    const ripple = {      x: e.clientX - rect.left,      y: e.clientY - rect.top,      id: Date.now(),    };    setRipples((prev) => [...prev, ripple]);    setTimeout(() => {      setRipples((prev) => prev.filter((r) => r.id !== ripple.id));    }, 600);    onClick?.(e);  };   return (    <button onClick={handleClick} className="relative overflow-hidden">      {children}      {ripples.map((ripple) => (        <span          key={ripple.id}          className="absolute bg-white/30 rounded-full animate-ripple"          style={{ left: ripple.x, top: ripple.y }}        />      ))}    </button>  );}``` ### 5. Gesture Interactions **Swipe to dismiss**: ```tsxfunction SwipeCard({ children, onDismiss }) {  return (    <motion.div      drag="x"      dragConstraints={{ left: 0, right: 0 }}      onDragEnd={(_, info) => {        if (Math.abs(info.offset.x) > 100) {          onDismiss();        }      }}      className="cursor-grab active:cursor-grabbing"    >      {children}    </motion.div>  );}``` ## CSS Animation Patterns ### Keyframe Animations ```css@keyframes fadeIn {  from {    opacity: 0;    transform: translateY(10px);  }  to {    opacity: 1;    transform: translateY(0);  }} @keyframes pulse {  0%,  100% {    opacity: 1;  }  50% {    opacity: 0.5;  }} @keyframes spin {  to {    transform: rotate(360deg);  }} .animate-fadeIn {  animation: fadeIn 0.3s ease-out;}.animate-pulse {  animation: pulse 2s ease-in-out infinite;}.animate-spin {  animation: spin 1s linear infinite;}``` ### CSS Transitions ```css.card {  transition:    transform 0.2s ease-out,    box-shadow 0.2s ease-out;} .card:hover {  transform: translateY(-4px);  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1);}``` ## Accessibility Considerations ```css/* Respect user motion preferences */@media (prefers-reduced-motion: reduce) {  *,  *::before,  *::after {    animation-duration: 0.01ms !important;    animation-iteration-count: 1 !important;    transition-duration: 0.01ms !important;  }}``` ```tsxfunction AnimatedComponent() {  const prefersReducedMotion = window.matchMedia(    "(prefers-reduced-motion: reduce)",  ).matches;   return (    <motion.div      animate={{ opacity: 1 }}      transition={{ duration: prefersReducedMotion ? 0 : 0.3 }}    />  );}``` ## Best Practices 1. **Performance First**: Use `transform` and `opacity` for smooth 60fps2. **Reduce Motion Support**: Always respect `prefers-reduced-motion`3. **Consistent Timing**: Use a timing scale across the app4. **Natural Physics**: Prefer spring animations over linear5. **Interruptible**: Allow users to cancel long animations6. **Progressive Enhancement**: Work without JS animations7. **Test on Devices**: Performance varies significantly ## Common Issues - **Janky Animations**: Avoid animating `width`, `height`, `top`, `left`- **Over-animation**: Too much motion causes fatigue- **Blocking Interactions**: Never prevent user input during animations- **Memory Leaks**: Clean up animation listeners on unmount- **Flash of Content**: Use `will-change` sparingly for optimization