{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "extrude-pop",
  "title": "Extrude Pop",
  "description": "A flat word pops up out of the plane on a solid colored 3D body, no camera involved.",
  "dependencies": ["remotion"],
  "files": [
    {
      "path": "registry/remocn/extrude-pop/index.tsx",
      "content": "\"use client\";\n\nimport { useMemo } from \"react\";\nimport { Easing, interpolate, useCurrentFrame } from \"remotion\";\n\nexport interface ExtrudePopProps {\n  className?: string;\n  width?: number;\n  height?: number;\n  letter?: string;\n  fontFamily?: string;\n  fontWeight?: number | string;\n  fontSize?: number;\n  basePosition?: [number, number];\n  maxTextWidth?: number;\n  minimaxRadius?: number;\n  extrudeAngleDeg?: number;\n  extrudeSteps?: number;\n  extrudeStartFrame?: number;\n  extrudeEndFrame?: number;\n  bodyColor?: string;\n  faceColor?: string;\n}\n\nexport function ExtrudePop({\n  className,\n  width = 1920,\n  height = 1080,\n  letter = \"WIN\",\n  fontFamily = \"'Helvetica Neue', Helvetica, Arial, sans-serif\",\n  fontWeight = 700,\n  fontSize = 603,\n  basePosition = [959.2, 752.5],\n  maxTextWidth = 1660,\n  minimaxRadius = 80,\n  extrudeAngleDeg = -58.6,\n  extrudeSteps = 200,\n  extrudeStartFrame = 0,\n  extrudeEndFrame = 48,\n  bodyColor = \"#e8192b\",\n  faceColor = \"#ffffff\",\n}: ExtrudePopProps) {\n  const frame = useCurrentFrame();\n\n  const fit = useMemo(() => {\n    if (typeof document === \"undefined\") return 1;\n    const ctx = document.createElement(\"canvas\").getContext(\"2d\");\n    if (!ctx) return 1;\n    ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n    const measured = ctx.measureText(letter).width;\n    if (measured <= 0) return 1;\n    return Math.min(1, maxTextWidth / measured);\n  }, [letter, fontFamily, fontWeight, fontSize, maxTextWidth]);\n\n  const fitFontSize = fontSize * fit;\n  const fitRadius = minimaxRadius * fit;\n\n  const radius = interpolate(\n    frame,\n    [extrudeStartFrame, extrudeEndFrame],\n    [0, fitRadius],\n    {\n      extrapolateLeft: \"clamp\",\n      extrapolateRight: \"clamp\",\n      easing: Easing.bezier(0.16, 1, 0.3, 1),\n    },\n  );\n\n  const depth = radius * 2;\n\n  const theta = (extrudeAngleDeg * Math.PI) / 180;\n  const stepX = (depth * Math.sin(theta)) / extrudeSteps;\n  const stepY = (depth * Math.cos(theta)) / extrudeSteps;\n\n  const glyph = (fill: string, dx: number, dy: number, key?: string) => (\n    <text\n      key={key}\n      x={basePosition[0] + dx}\n      y={basePosition[1] + dy}\n      textAnchor=\"middle\"\n      fontFamily={fontFamily}\n      fontWeight={fontWeight}\n      fontSize={fitFontSize}\n      fill={fill}\n    >\n      {letter}\n    </text>\n  );\n\n  return (\n    <div\n      className={className}\n      style={{ position: \"absolute\", inset: 0, overflow: \"hidden\" }}\n    >\n      <svg\n        width=\"100%\"\n        height=\"100%\"\n        viewBox={`0 0 ${width} ${height}`}\n        preserveAspectRatio=\"xMidYMid meet\"\n        style={{ display: \"block\" }}\n      >\n        <g>\n          {Array.from(\n            { length: extrudeSteps + 1 },\n            (_, i) => extrudeSteps - i,\n          ).map((i) => glyph(bodyColor, stepX * i, stepY * i, `body-${i}`))}\n        </g>\n\n        {glyph(faceColor, stepX * extrudeSteps, stepY * extrudeSteps)}\n      </svg>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/extrude-pop.tsx"
    }
  ],
  "type": "registry:component"
}
