{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "perfect-preview",
  "type": "registry:ui",
  "title": "Perfect preview",
  "description": "Hold to perfect: while the pen is held still after a rough stroke, the fitted clean shape draws itself round as a faint green outline over 450 ms; when it closes the host morphs the stroke into the shape.",
  "dependencies": [],
  "registryDependencies": [
    "https://metalui.dev/r/tokens.json"
  ],
  "files": [
    {
      "path": "packages/metalui/src/components/perfect-preview/perfect-preview.tsx",
      "type": "registry:ui",
      "target": "components/metalui/perfect-preview/perfect-preview.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\n/* ─────────────────────────────────────────────────────────\n * PERFECT PREVIEW: hold to perfect (DRAWING.md DR-05)\n *\n *   idle     nothing\n *   holding  the pen is still at the end of a rough stroke: the clean shape the core fitted\n *            (shape_recognize) draws itself round as a faint green outline over 450 ms. The\n *            outline is the timer: when it closes, the hold is done.\n *   done     the host morphs the stroke into the clean shape (180 ms, settle spring) while\n *            the outline fades over the same time\n *   cancel   moving again or Escape: back to idle at once, the hand-drawn stroke stays\n *   tuning   still holding after the morph, the shape is in the hand: the host turns and\n *            resizes it around its centre as the pointer moves. Here: a centre dot, a dashed\n *            guide from the centre to the pointer, and a readout of the angle and size\n *            (the host catches the angle at 0°, 45° and 90°). Letting go places it.\n * Reduce Motion: no trace; the outline shows whole for the hold, then goes.\n * Drawn in world coordinates inside the transformed world.\n * ───────────────────────────────────────────────────────── */\n\nexport interface PerfectPreviewProps {\n  /** The fitted shape's outline path in world coordinates. */\n  d: string;\n  phase: 'idle' | 'holding' | 'done' | 'tuning';\n  /** While tuning: the shape's centre, the pointer (world), the turn in degrees and the size as a factor. */\n  tune?: { centre: { x: number; y: number }; pointer: { x: number; y: number }; angle: number; scale: number };\n  /** The canvas scale (1 at 100 %), so the line keeps its screen width. */\n  scale?: number;\n  /** The outline closed: the hold is complete. The host starts the morph. */\n  onHeld?: () => void;\n  className?: string;\n}\n\nconst LAYER = 'mu-perfect-preview perfect-layer';\nconst GUIDE = 'mu-perfect-guide perfect-guide';\nconst CENTRE = 'mu-perfect-centre perfect-centre';\nconst READOUT = 'mu-perfect-readout perfect-readout';\nconst OUTLINE = {\n  holding: 'mu-perfect-outline perfect-outline perfect-holding reduced-motion:animate-none',\n  done: 'mu-perfect-outline perfect-outline perfect-done',\n};\n\n/** The fitted shape, tracing itself while the pen is held still. */\nexport function PerfectPreview({ d, phase, tune, scale = 1, onHeld, className }: PerfectPreviewProps) {\n  if (phase === 'idle') return null;\n  const vars = { '--mu-canvas-scale': scale } as React.CSSProperties;\n  if (phase === 'tuning') {\n    if (!tune) return null;\n    const { centre: c, pointer: p } = tune;\n    const r = 3 / scale;\n    return (\n      <>\n        <svg aria-hidden width={1} height={1} className={className ? `${LAYER} ${className}` : LAYER} style={vars}>\n          <path className={GUIDE} d={`M${c.x} ${c.y}L${p.x} ${p.y}`} />\n          <circle className={CENTRE} cx={c.x} cy={c.y} r={r} />\n        </svg>\n        <span className={READOUT} style={{ ...vars, left: p.x, top: p.y }}>\n          {`${Math.round(tune.angle)}° · ${Math.round(tune.scale * 100)} %`}\n        </span>\n      </>\n    );\n  }\n  return (\n    <svg aria-hidden width={1} height={1} className={className ? `${LAYER} ${className}` : LAYER} style={vars}>\n      <path\n        key={phase}\n        className={OUTLINE[phase]}\n        d={d}\n        pathLength={1}\n        onAnimationEnd={phase === 'holding' ? () => onHeld?.() : undefined}\n      />\n    </svg>\n  );\n}\n"
    }
  ],
  "docs": "Agent guide: https://metalui.dev/r/perfect-preview.md. SwiftUI: MetalPerfectPreview in the MetalUI Swift package."
}
