{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "paint-brush-02",
  "title": "paint-brush-02",
  "description": "Animated paint brush icon",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "icons/paint-brush-02.tsx",
      "content": "'use client';\n\nimport type { Variants } from 'motion/react';\nimport { motion, useAnimation } from 'motion/react';\nimport type { HTMLAttributes } from 'react';\nimport { forwardRef } from 'react';\nimport { useIconAnimation } from '@/lib/use-icon-animation';\nimport { cn } from '@/lib/utils';\n\nexport interface PaintBrush02IconHandle {\n  startAnimation: () => void;\n  stopAnimation: () => void;\n}\n\ninterface PaintBrush02IconProps extends HTMLAttributes<HTMLDivElement> {\n  size?: number;\n}\n\nconst paintTimes = [0, 0.12, 0.42, 0.58, 0.84, 1];\n\n// Roll up the wall to lay a vertical strip, then collect it on the return pass.\nconst brushVariants: Variants = {\n  normal: {\n    transform: 'none',\n    transition: { duration: 0.2, ease: [0.23, 1, 0.32, 1] },\n  },\n  animate: {\n    transform: [\n      'translate3d(0px, 0px, 0px) rotate(0deg)',\n      'translate3d(0.08px, -0.55px, 0px) rotate(0.4deg)',\n      'translate3d(0.2px, -4px, 0px) rotate(1.1deg)',\n      'translate3d(0.2px, -4px, 0px) rotate(1.1deg)',\n      'translate3d(0.04px, -0.7px, 0px) rotate(0.25deg)',\n      'translate3d(0px, 0px, 0px) rotate(0deg)',\n    ],\n    transition: {\n      duration: 0.76,\n      ease: [0.77, 0, 0.175, 1],\n      times: paintTimes,\n    },\n  },\n};\n\nconst paintMarkVariants: Variants = {\n  normal: { pathLength: 0 },\n  animate: {\n    pathLength: [0, 0.12, 1, 1, 0.18, 0],\n    transition: {\n      duration: 0.76,\n      ease: [0.77, 0, 0.175, 1],\n      times: paintTimes,\n    },\n  },\n};\n\nconst generatedGeometryVariants: Variants = {\n  normal: { visibility: 'hidden' },\n  animate: {\n    visibility: ['hidden', 'visible', 'visible', 'visible', 'visible', 'hidden'],\n    transition: { duration: 0.76, ease: 'linear', times: paintTimes },\n  },\n};\n\nconst PaintBrush02Icon = forwardRef<PaintBrush02IconHandle, PaintBrush02IconProps>(\n  ({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {\n    const controls = useAnimation();\n    const { handleMouseEnter, handleMouseLeave } = useIconAnimation({\n      controls,\n      loops: false,\n      onMouseEnter,\n      onMouseLeave,\n      ref,\n    });\n\n    return (\n      <div\n        className={cn(className)}\n        onMouseEnter={handleMouseEnter}\n        onMouseLeave={handleMouseLeave}\n        {...props}\n      >\n        <svg\n          xmlns=\"http://www.w3.org/2000/svg\"\n          width={size}\n          height={size}\n          viewBox=\"0 0 24 24\"\n          fill=\"none\"\n          overflow=\"visible\"\n        >\n          <motion.g\n            variants={generatedGeometryVariants}\n            animate={controls}\n            initial=\"normal\"\n          >\n            <motion.path\n              d=\"M10.5 5V9.2\"\n              stroke=\"currentColor\"\n              strokeLinecap=\"butt\"\n              strokeWidth=\"12.5\"\n              vectorEffect=\"non-scaling-stroke\"\n              variants={paintMarkVariants}\n              animate={controls}\n              initial=\"normal\"\n            />\n          </motion.g>\n          <motion.g\n            variants={brushVariants}\n            animate={controls}\n            initial=\"normal\"\n            style={{ transformBox: 'view-box', originX: 0.56, originY: 0.88 }}\n          >\n            <path\n              d=\"M4 5C4 4.25579 4 3.88369 4.08912 3.58019C4.30005 2.86183 4.86183 2.30005 5.58019 2.08912C5.88369 2 6.25579 2 7 2H14C14.7442 2 15.1163 2 15.4198 2.08912C16.1382 2.30005 16.7 2.86183 16.9109 3.58019C17 3.88369 17 4.25579 17 5C17 5.74421 17 6.11631 16.9109 6.41981C16.7 7.13817 16.1382 7.69995 15.4198 7.91088C15.1163 8 14.7442 8 14 8H7C6.25579 8 5.88369 8 5.58019 7.91088C4.86183 7.69995 4.30005 7.13817 4.08912 6.41981C4 6.11631 4 5.74421 4 5Z\"\n              stroke=\"currentColor\"\n              strokeLinecap=\"round\"\n              strokeWidth=\"1.5\"\n            />\n            <path\n              d=\"M12 17.5C12 17.0341 12 16.8011 12.0761 16.6173C12.1776 16.3723 12.3723 16.1776 12.6173 16.0761C12.8011 16 13.0341 16 13.5 16C13.9659 16 14.1989 16 14.3827 16.0761C14.6277 16.1776 14.8224 16.3723 14.9239 16.6173C15 16.8011 15 17.0341 15 17.5V20.5C15 20.9659 15 21.1989 14.9239 21.3827C14.8224 21.6277 14.6277 21.8224 14.3827 21.9239C14.1989 22 13.9659 22 13.5 22C13.0341 22 12.8011 22 12.6173 21.9239C12.3723 21.8224 12.1776 21.6277 12.0761 21.3827C12 21.1989 12 20.9659 12 20.5V17.5Z\"\n              stroke=\"currentColor\"\n              strokeLinecap=\"round\"\n              strokeWidth=\"1.5\"\n            />\n            <path\n              d=\"M17.249 5C18.1037 5 18.531 5 18.8681 5.15224C19.9978 5.6624 20.0005 6.86278 20.0005 8.00422C20.0005 8.96065 20.0005 9.43886 19.8701 9.84219C19.4513 11.1378 17.7387 11.768 16.0836 12.2373C14.9006 12.5727 14.3091 12.7404 13.9045 13.2756C13.5 13.8107 13.5 14.4389 13.5 15.6952V16\"\n              stroke=\"currentColor\"\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n              strokeWidth=\"1.5\"\n            />\n          </motion.g>\n        </svg>\n      </div>\n    );\n  }\n);\n\nPaintBrush02Icon.displayName = 'PaintBrush02Icon';\n\nexport { PaintBrush02Icon };\n",
      "type": "registry:ui"
    },
    {
      "path": "lib/use-icon-animation.ts",
      "content": "'use client';\n\nimport type { LegacyAnimationControls } from 'motion/react';\nimport { useReducedMotion } from 'motion/react';\nimport type {\n  ForwardedRef,\n  MouseEventHandler,\n} from 'react';\nimport { useCallback, useImperativeHandle, useRef } from 'react';\n\nexport interface AnimatedIconHandle {\n  startAnimation: () => void;\n  stopAnimation: () => void;\n}\n\ninterface UseIconAnimationOptions {\n  controls: LegacyAnimationControls;\n  loops?: boolean;\n  onMouseEnter?: MouseEventHandler<HTMLDivElement>;\n  onMouseLeave?: MouseEventHandler<HTMLDivElement>;\n  ref: ForwardedRef<AnimatedIconHandle>;\n}\n\nexport function useIconAnimation({\n  controls,\n  loops = false,\n  onMouseEnter,\n  onMouseLeave,\n  ref,\n}: UseIconAnimationOptions) {\n  const shouldReduceMotion = useReducedMotion();\n  const isControlledRef = useRef(false);\n  const isPlayingRef = useRef(false);\n  const runRef = useRef(0);\n\n  const startAnimation = useCallback(() => {\n    if (shouldReduceMotion || isPlayingRef.current) return;\n\n    isPlayingRef.current = true;\n    const run = ++runRef.current;\n    controls.set('normal');\n    void controls.start('animate').then(() => {\n      if (runRef.current === run) isPlayingRef.current = false;\n    });\n  }, [controls, shouldReduceMotion]);\n\n  const stopAnimation = useCallback(() => {\n    if (!loops) return;\n\n    runRef.current++;\n    isPlayingRef.current = false;\n    void controls.start('normal');\n  }, [controls, loops]);\n\n  useImperativeHandle(\n    ref,\n    () => {\n      isControlledRef.current = true;\n      return { startAnimation, stopAnimation };\n    },\n    [startAnimation, stopAnimation]\n  );\n\n  const handleMouseEnter = useCallback<MouseEventHandler<HTMLDivElement>>(\n    (event) => {\n      onMouseEnter?.(event);\n      if (!isControlledRef.current) startAnimation();\n    },\n    [onMouseEnter, startAnimation]\n  );\n\n  const handleMouseLeave = useCallback<MouseEventHandler<HTMLDivElement>>(\n    (event) => {\n      onMouseLeave?.(event);\n      if (!isControlledRef.current) stopAnimation();\n    },\n    [onMouseLeave, stopAnimation]\n  );\n\n  return { handleMouseEnter, handleMouseLeave };\n}\n",
      "type": "registry:lib"
    }
  ],
  "type": "registry:ui"
}