{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "image-01",
  "title": "image-01",
  "description": "Animated image icon",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "icons/image-01.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\n/** Imperative controls for the Image 01 icon animation. */\nexport interface Image01IconHandle {\n  startAnimation: () => void;\n  stopAnimation: () => void;\n}\n\ninterface Image01IconProps extends HTMLAttributes<HTMLDivElement> {\n  size?: number;\n}\n\nconst PHOTO_DURATION = 0.58;\nconst PHOTO_TIMES = [0, 0.28, 0.68, 1];\nconst PHOTO_EASE = [0.23, 1, 0.32, 1] as const;\n\n// The complete photo lifts as one object while its scene shifts with shallow\n// parallax. Every layer begins and ends on the untouched Hugeicons artwork.\nconst photoVariants: Variants = {\n  normal: { transform: 'translateY(0px) rotate(0deg) scale(1)' },\n  animate: {\n    transform: [\n      'translateY(0px) rotate(0deg) scale(1)',\n      'translateY(-0.75px) rotate(-2deg) scale(1.03)',\n      'translateY(0.2px) rotate(0.55deg) scale(0.992)',\n      'translateY(0px) rotate(0deg) scale(1)',\n    ],\n    transition: {\n      duration: PHOTO_DURATION,\n      ease: PHOTO_EASE,\n      times: PHOTO_TIMES,\n    },\n  },\n};\n\nconst sunVariants: Variants = {\n  normal: { transform: 'translate(0px, 0px) scale(1)' },\n  animate: {\n    transform: [\n      'translate(0px, 0px) scale(1)',\n      'translate(0.75px, -0.9px) scale(0.96)',\n      'translate(-0.15px, 0.2px) scale(1.06)',\n      'translate(0px, 0px) scale(1)',\n    ],\n    transition: {\n      duration: PHOTO_DURATION,\n      ease: PHOTO_EASE,\n      times: [0, 0.34, 0.74, 1],\n    },\n  },\n};\n\nconst landscapeVariants: Variants = {\n  normal: { transform: 'translateY(0px) scaleY(1)' },\n  animate: {\n    transform: [\n      'translateY(0px) scaleY(1)',\n      'translateY(1.05px) scaleY(0.97)',\n      'translateY(-0.3px) scaleY(1.015)',\n      'translateY(0px) scaleY(1)',\n    ],\n    transition: {\n      duration: PHOTO_DURATION,\n      ease: PHOTO_EASE,\n      times: [0, 0.38, 0.76, 1],\n    },\n  },\n};\n\n/** Animated Hugeicons Image 01 icon. */\nconst Image01Icon = forwardRef<Image01IconHandle, Image01IconProps>(\n  ({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {\n    const controls = useAnimation();\n    const { handleMouseEnter, handleMouseLeave } = useIconAnimation({\n      controls,\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        <motion.div\n          variants={photoVariants}\n          animate={controls}\n          initial=\"normal\"\n          style={{\n            width: size,\n            height: size,\n            transformOrigin: '50% 50%',\n          }}\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.circle\n              cx=\"7.5\"\n              cy=\"7.5\"\n              r=\"1.5\"\n              stroke=\"currentColor\"\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n              strokeWidth=\"1.5\"\n              variants={sunVariants}\n              animate={controls}\n              initial=\"normal\"\n              style={{\n                transformBox: 'view-box',\n                transformOrigin: '7.5px 7.5px',\n              }}\n            />\n            <path\n              d=\"M2.5 12C2.5 7.52166 2.5 5.28249 3.89124 3.89124C5.28249 2.5 7.52166 2.5 12 2.5C16.4783 2.5 18.7175 2.5 20.1088 3.89124C21.5 5.28249 21.5 7.52166 21.5 12C21.5 16.4783 21.5 18.7175 20.1088 20.1088C18.7175 21.5 16.4783 21.5 12 21.5C7.52166 21.5 5.28249 21.5 3.89124 20.1088C2.5 18.7175 2.5 16.4783 2.5 12Z\"\n              stroke=\"currentColor\"\n              strokeWidth=\"1.5\"\n            />\n            <motion.path\n              d=\"M5 21C9.37246 15.775 14.2741 8.88406 21.4975 13.5424\"\n              stroke=\"currentColor\"\n              strokeWidth=\"1.5\"\n              variants={landscapeVariants}\n              animate={controls}\n              initial=\"normal\"\n            />\n          </svg>\n        </motion.div>\n      </div>\n    );\n  }\n);\n\nImage01Icon.displayName = 'Image01Icon';\n\nexport { Image01Icon };\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"
}