{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ink-underline",
  "title": "Ink Underline",
  "description": "A hand-dragged brush underline that sweeps itself across in a few stop-motion poses, thinning to a dry tail.",
  "dependencies": ["remotion"],
  "registryDependencies": ["@remocn/stop-motion", "@remocn/brush"],
  "files": [
    {
      "path": "registry/remocn/ink-underline/index.tsx",
      "content": "\"use client\";\n\nimport { useCurrentFrame } from \"remotion\";\nimport {\n  BrushGrain,\n  type BrushPoint,\n  brushFilterId,\n  brushReach,\n  brushRibbon,\n  sampleCubic,\n} from \"@/components/remocn/brush\";\nimport { DEFAULT_STEP, hashRange, steppedRamp } from \"@/lib/remocn/stop-motion\";\n\nconst SAMPLES = 40;\n\nexport function inkUnderlineSpine(\n  width: number,\n  thickness: number,\n  seed: string,\n): BrushPoint[] {\n  const wobble = hashRange(`${seed}:w`, -1.2, 1.2);\n  const mid = thickness / 2 + 2;\n  return sampleCubic(\n    { x: 2, y: mid },\n    { x: width * 0.3, y: mid + wobble },\n    { x: width * 0.7, y: mid - wobble },\n    { x: width - 2, y: mid + wobble * 0.6 },\n    SAMPLES,\n  );\n}\n\nexport interface InkUnderlineProps {\n  width: number;\n  color?: string;\n  thickness?: number;\n  pressure?: number;\n  release?: number;\n  grain?: number;\n  delay?: number;\n  durationSteps?: number;\n  seed?: string;\n  step?: number;\n}\n\nexport function InkUnderline({\n  width,\n  color = \"#6f7f35\",\n  thickness = 9,\n  pressure = 1,\n  release = 0.15,\n  grain = 1,\n  delay = 0,\n  durationSteps = 5,\n  seed = \"ink\",\n  step = DEFAULT_STEP,\n}: InkUnderlineProps) {\n  const frame = useCurrentFrame();\n  const progress = steppedRamp(frame, delay, delay + durationSteps * step, {\n    step,\n  });\n\n  const reach = brushReach(thickness, grain);\n  const height = thickness + 4;\n  const d = brushRibbon(inkUnderlineSpine(width, thickness, seed), {\n    strokeWidth: thickness,\n    pressure,\n    release,\n    progress,\n  });\n\n  return (\n    <div\n      style={{\n        width,\n        height,\n        position: \"relative\",\n        opacity: progress > 0 ? 1 : 0,\n      }}\n    >\n      <svg\n        width={width + reach * 2}\n        height={height + reach * 2}\n        viewBox={`${-reach} ${-reach} ${width + reach * 2} ${height + reach * 2}`}\n        style={{\n          position: \"absolute\",\n          left: -reach,\n          top: -reach,\n          display: \"block\",\n          overflow: \"visible\",\n        }}\n      >\n        <title>Ink underline</title>\n        <BrushGrain seed={seed} strokeWidth={thickness} grain={grain} />\n        <path\n          d={d}\n          fill={color}\n          opacity={0.85}\n          filter={\n            grain > 0\n              ? `url(#${brushFilterId(seed, thickness, grain)})`\n              : undefined\n          }\n        />\n      </svg>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/ink-underline.tsx"
    }
  ],
  "type": "registry:component"
}
