{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "image-generation",
  "title": "Image generation",
  "description": "A tile that shows an image being made: a soft glow that sharpens into the result as progress rises.",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/manniche/image-generation/image-generation.tsx",
      "content": "import { Check, Sparkles } from 'lucide-react'\nimport { AnimatePresence, MotionConfig, motion } from 'motion/react'\nimport type { ReactNode } from 'react'\nimport { cn } from '@/lib/utils'\n\nexport type ImageGenerationProps = {\n  /** 0 to 1. At 1 the result is shown. */\n  progress: number\n  /** The finished image, usually an <img>. Rendered behind the blur while it sharpens. */\n  children?: ReactNode\n  prompt?: string\n  /** A small badge in the corner, e.g. “1024 × 1024”. */\n  size?: string\n  labels?: Partial<Record<'working' | 'ready', string>>\n  className?: string\n}\n\nconst EN = { working: 'Creating image', ready: 'Image ready' }\n\n/** A tile that shows an image being made: a soft glow that sharpens into the result as progress rises. */\nexport function ImageGeneration({ progress, children, prompt, size, labels = {}, className }: ImageGenerationProps) {\n  const t = { ...EN, ...labels }\n  const p = Math.min(1, Math.max(0, progress))\n  const done = p >= 1\n\n  return (\n    <MotionConfig reducedMotion=\"user\">\n      <figure className={cn('w-full max-w-xs', className)}>\n        <div\n          role=\"img\"\n          aria-label={done ? (prompt ?? t.ready) : `${t.working}, ${Math.round(p * 100)}%`}\n          className=\"relative isolate aspect-square overflow-hidden rounded-3xl border bg-muted\"\n        >\n          {/* The result sits underneath from the start and comes into focus as progress rises. */}\n          <motion.div\n            className=\"absolute inset-0\"\n            initial={false}\n            animate={{ filter: `blur(${done ? 0 : 28 - p * 20}px)`, scale: done ? 1 : 1.12 - p * 0.06, opacity: done ? 1 : 0.15 + p * 0.55 }}\n            transition={{ type: 'spring', bounce: 0, duration: done ? 0.9 : 0.6 }}\n          >\n            {children}\n          </motion.div>\n\n          {/* Drifting light while the image is being made. */}\n          <AnimatePresence>\n            {!done && (\n              <motion.div key=\"glow\" className=\"absolute inset-0\" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0, transition: { duration: 0.6 } }}>\n                <span className=\"absolute -inset-1/4 animate-[spin_9s_linear_infinite] bg-[conic-gradient(from_0deg,transparent,color-mix(in_oklch,var(--color-primary)_35%,transparent),transparent_40%,color-mix(in_oklch,var(--color-foreground)_18%,transparent),transparent_75%)] blur-2xl motion-reduce:animate-none\" />\n                <span className=\"absolute inset-x-0 bottom-0 h-1 bg-foreground/10\">\n                  <motion.span className=\"block h-full origin-left bg-foreground/70\" initial={false} animate={{ scaleX: p }} transition={{ type: 'spring', bounce: 0, duration: 0.5 }} />\n                </span>\n              </motion.div>\n            )}\n          </AnimatePresence>\n\n          {size && <span className=\"absolute top-2.5 right-2.5 rounded-full bg-background/70 px-2 py-0.5 font-mono text-[11px] text-muted-foreground backdrop-blur\">{size}</span>}\n        </div>\n\n        <figcaption className=\"mt-3\" aria-live=\"polite\">\n          <AnimatePresence mode=\"popLayout\" initial={false}>\n            <motion.p\n              key={done ? 'ready' : 'working'}\n              initial={{ opacity: 0, y: 6, filter: 'blur(2px)' }}\n              animate={{ opacity: 1, y: 0, filter: 'blur(0px)' }}\n              exit={{ opacity: 0, y: -6, filter: 'blur(2px)' }}\n              transition={{ type: 'spring', bounce: 0, duration: 0.35 }}\n              className=\"flex items-center gap-2 text-sm font-medium\"\n            >\n              {done ? <Check className=\"size-4\" aria-hidden /> : <Sparkles className=\"size-4 animate-pulse motion-reduce:animate-none\" aria-hidden />}\n              {done ? t.ready : t.working}\n              {!done && <span aria-hidden className=\"ml-auto font-mono text-xs text-muted-foreground tabular-nums\">{Math.round(p * 100)}%</span>}\n            </motion.p>\n          </AnimatePresence>\n          {prompt && <p className=\"mt-1 line-clamp-2 text-sm text-muted-foreground\">“{prompt}”</p>}\n        </figcaption>\n      </figure>\n    </MotionConfig>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "agent"
  ],
  "type": "registry:component"
}