{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "blueprint",
  "title": "Blueprint",
  "description": "The product wipes left to right into a technical drawing: blueprint grid, white linework, dimension lines with ticks, labels and a red callout.",
  "dependencies": ["remotion"],
  "files": [
    {
      "path": "registry/remocn/blueprint/index.tsx",
      "content": "\"use client\";\n\nimport { type ReactNode, useId } from \"react\";\nimport {\n  AbsoluteFill,\n  Easing,\n  interpolate,\n  useCurrentFrame,\n  useVideoConfig,\n} from \"remotion\";\n\nexport type BlueprintLabels = {\n  width: string;\n  height: string;\n  callout: string;\n  title: string;\n};\n\nexport type BlueprintProps = {\n  /** Product to convert. Its silhouette and dark details become white linework. Defaults to a red device. */\n  children?: ReactNode;\n  /** Measured box around the product, as fractions of the frame [width, height]. */\n  box?: [number, number];\n  /** Point the red callout points at, as fractions of the box [x, y]. */\n  calloutAt?: [number, number];\n  blueprintColor?: string;\n  lineColor?: string;\n  calloutColor?: string;\n  /** Ground behind the product before the wipe. */\n  background?: string;\n  productColor?: string;\n  labels?: Partial<BlueprintLabels>;\n  speed?: number;\n};\n\nexport const blueprintDefaults = {\n  box: [0.17, 0.6] as [number, number],\n  calloutAt: [0.5, 0.11] as [number, number],\n  blueprintColor: \"#173C8F\",\n  lineColor: \"#FFFFFF\",\n  calloutColor: \"#E5322D\",\n  background: \"#FFFFFF\",\n  productColor: \"#E5322D\",\n  labels: {\n    width: \"71.6 mm\",\n    height: \"147.5 mm\",\n    callout: \"SENSOR\",\n    title: \"DWG A-01  SCALE 1:1\",\n  } as BlueprintLabels,\n  speed: 1,\n};\n\nexport const blueprintLength = 45;\n\nconst MONO = \"ui-monospace, 'SF Mono', Menlo, Consolas, monospace\";\nconst clamp = {\n  extrapolateLeft: \"clamp\" as const,\n  extrapolateRight: \"clamp\" as const,\n};\nconst ease = (t: number, from: number, to: number) =>\n  interpolate(t, [from, to], [0, 1], {\n    ...clamp,\n    easing: Easing.inOut(Easing.cubic),\n  });\n\nexport function Blueprint({\n  children,\n  box = blueprintDefaults.box,\n  calloutAt = blueprintDefaults.calloutAt,\n  blueprintColor = blueprintDefaults.blueprintColor,\n  lineColor = blueprintDefaults.lineColor,\n  calloutColor = blueprintDefaults.calloutColor,\n  background = blueprintDefaults.background,\n  productColor = blueprintDefaults.productColor,\n  labels,\n  speed = blueprintDefaults.speed,\n}: BlueprintProps) {\n  const frame = useCurrentFrame();\n  const { width, height, fps } = useVideoConfig();\n  const id = useId().replace(/[^a-zA-Z0-9_-]/g, \"\");\n  const text = { ...blueprintDefaults.labels, ...labels };\n  const t = (frame / fps) * 30 * speed;\n  const u = Math.min(width, height) / 720;\n\n  const cx = width * 0.47;\n  const cy = height * 0.46;\n  const bw = box[0] * width;\n  const bh = box[1] * height;\n  const x0 = cx - bw / 2;\n  const x1 = cx + bw / 2;\n  const y0 = cy - bh / 2;\n  const y1 = cy + bh / 2;\n  const radius = Math.min(bw, bh) * 0.16;\n  const dot = { x: x0 + calloutAt[0] * bw, y: y0 + calloutAt[1] * bh };\n\n  const wipe = interpolate(t, [6, 24], [-0.04, 1.04], {\n    ...clamp,\n    easing: Easing.inOut(Easing.cubic),\n  });\n  const wipeX = wipe * width;\n  const outline = ease(t, 8, 28);\n  const extension = ease(t, 22, 28);\n  const dims = ease(t, 24, 32);\n  const label = ease(t, 30, 36);\n  const leader = ease(t, 32, 40);\n  const bubble = interpolate(t, [36, 42], [0, 1], {\n    ...clamp,\n    easing: Easing.out(Easing.back(2)),\n  });\n  const calloutText = ease(t, 38, 44);\n\n  const stroke = 2.4 * u;\n  const thin = 1.2 * u;\n  const tick = 7 * u;\n  const dimY = y1 + 0.08 * height;\n  const dimX = x1 + 0.06 * width;\n  const half = (a: number, b: number, p: number) => [\n    (a + b) / 2 - ((b - a) / 2) * p,\n    (a + b) / 2 + ((b - a) / 2) * p,\n  ];\n  const [hx0, hx1] = half(x0, x1, dims);\n  const [vy0, vy1] = half(y0, y1, dims);\n  // Callout goes left of the product when the label fits, otherwise above it.\n  const ring = Math.min(bw, bh) * 0.11;\n  const labelWidth = text.callout.length * 11.8 * u + 26 * u;\n  const sideways = x0 - 0.14 * width - labelWidth > 0.03 * width;\n  const lead = sideways\n    ? { x: x0 - 0.14 * width, y: y0 + 0.06 * height }\n    : {\n        x: Math.max(0.06 * width, dot.x - 0.1 * width),\n        y: Math.max(0.08 * height, y0 - 0.1 * height),\n      };\n  const elbow = sideways\n    ? `L ${lead.x + 0.06 * width} ${lead.y} H ${lead.x}`\n    : `L ${lead.x} ${lead.y}`;\n  const draw = (p: number) => ({\n    pathLength: 1,\n    strokeDasharray: 1,\n    strokeDashoffset: 1 - p,\n    opacity: p > 0 ? 1 : 0,\n  });\n  const minor = 22 * u;\n\n  return (\n    <AbsoluteFill style={{ backgroundColor: background, overflow: \"hidden\" }}>\n      <svg width={0} height={0} style={{ position: \"absolute\" }} aria-hidden>\n        <defs>\n          <filter\n            id={`${id}-lines`}\n            x=\"0\"\n            y=\"0\"\n            width=\"1\"\n            height=\"1\"\n            colorInterpolationFilters=\"sRGB\"\n          >\n            <feMorphology\n              in=\"SourceAlpha\"\n              operator=\"dilate\"\n              radius={1.6 * u}\n              result=\"grown\"\n            />\n            <feComposite\n              in=\"grown\"\n              in2=\"SourceAlpha\"\n              operator=\"out\"\n              result=\"edge\"\n            />\n            <feColorMatrix\n              in=\"SourceGraphic\"\n              type=\"matrix\"\n              values=\"0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  -3 -6 -1 4 -1.2\"\n              result=\"dark\"\n            />\n            <feMorphology\n              in=\"dark\"\n              operator=\"dilate\"\n              radius={1.6 * u}\n              result=\"darkGrown\"\n            />\n            <feComposite\n              in=\"darkGrown\"\n              in2=\"dark\"\n              operator=\"out\"\n              result=\"darkEdge\"\n            />\n            <feMerge result=\"all\">\n              <feMergeNode in=\"edge\" />\n              <feMergeNode in=\"darkEdge\" />\n            </feMerge>\n            <feFlood floodColor={lineColor} />\n            <feComposite in2=\"all\" operator=\"in\" />\n          </filter>\n        </defs>\n      </svg>\n\n      {/* Product, before the wipe. */}\n      <AbsoluteFill>\n        {children ? (\n          <AbsoluteFill\n            style={{ alignItems: \"center\", justifyContent: \"center\" }}\n          >\n            <div\n              style={{\n                transform: `translate(${cx - width / 2}px, ${cy - height / 2}px)`,\n              }}\n            >\n              {children}\n            </div>\n          </AbsoluteFill>\n        ) : (\n          <svg width={width} height={height} aria-hidden>\n            <rect\n              x={x0}\n              y={y0 + 10 * u}\n              width={bw}\n              height={bh}\n              rx={radius}\n              fill=\"#000\"\n              opacity={0.12}\n              style={{ filter: `blur(${14 * u}px)` }}\n            />\n            <rect\n              x={x0}\n              y={y0}\n              width={bw}\n              height={bh}\n              rx={radius}\n              fill={productColor}\n            />\n            <circle cx={dot.x} cy={dot.y} r={bw * 0.06} fill=\"#111111\" />\n          </svg>\n        )}\n      </AbsoluteFill>\n\n      {/* Technical drawing, revealed left to right. */}\n      <AbsoluteFill style={{ clipPath: `inset(0 ${width - wipeX}px 0 0)` }}>\n        <svg width={width} height={height} aria-hidden>\n          <defs>\n            <pattern\n              id={`${id}-grid`}\n              width={minor * 5}\n              height={minor * 5}\n              patternUnits=\"userSpaceOnUse\"\n            >\n              <path\n                d={Array.from(\n                  { length: 5 },\n                  (_, i) =>\n                    `M ${i * minor} 0 V ${minor * 5} M 0 ${i * minor} H ${minor * 5}`,\n                ).join(\" \")}\n                stroke={lineColor}\n                strokeOpacity={0.09}\n                strokeWidth={u}\n              />\n              <path\n                d={`M 0 0 V ${minor * 5} M 0 0 H ${minor * 5}`}\n                stroke={lineColor}\n                strokeOpacity={0.22}\n                strokeWidth={u}\n              />\n            </pattern>\n          </defs>\n          <rect width={width} height={height} fill={blueprintColor} />\n          <rect width={width} height={height} fill={`url(#${id}-grid)`} />\n        </svg>\n        {children ? (\n          <AbsoluteFill\n            style={{\n              alignItems: \"center\",\n              justifyContent: \"center\",\n              filter: `url(#${id}-lines)`,\n              clipPath: `inset(0 ${width * (1 - outline)}px 0 0)`,\n            }}\n          >\n            <div\n              style={{\n                transform: `translate(${cx - width / 2}px, ${cy - height / 2}px)`,\n              }}\n            >\n              {children}\n            </div>\n          </AbsoluteFill>\n        ) : null}\n        <svg\n          width={width}\n          height={height}\n          style={{ position: \"absolute\", inset: 0 }}\n          aria-hidden\n        >\n          <g fill=\"none\" stroke={lineColor} strokeLinecap=\"round\">\n            {children ? null : (\n              <>\n                <rect\n                  x={x0}\n                  y={y0}\n                  width={bw}\n                  height={bh}\n                  rx={radius}\n                  strokeWidth={stroke}\n                  {...draw(outline)}\n                />\n                <rect\n                  x={x0 + bw * 0.07}\n                  y={y0 + bw * 0.07}\n                  width={bw * 0.86}\n                  height={bh - bw * 0.14}\n                  rx={radius * 0.7}\n                  strokeWidth={thin}\n                  strokeOpacity={0.7}\n                  {...draw(outline)}\n                />\n                <circle\n                  cx={dot.x}\n                  cy={dot.y}\n                  r={bw * 0.06}\n                  strokeWidth={stroke}\n                  {...draw(outline)}\n                />\n              </>\n            )}\n            {/* Center lines */}\n            <path\n              d={`M ${cx} ${y0 - 0.05 * height} V ${y1 + 0.05 * height} M ${x0 - 0.04 * width} ${cy} H ${x1 + 0.04 * width}`}\n              strokeWidth={thin}\n              strokeOpacity={0.55 * outline}\n              strokeDasharray={`${14 * u} ${4 * u} ${3 * u} ${4 * u}`}\n            />\n            {/* Extension lines */}\n            <path\n              d={`M ${x0} ${y1 + 8 * u} V ${y1 + 8 * u + (dimY - y1) * extension} M ${x1} ${y1 + 8 * u} V ${y1 + 8 * u + (dimY - y1) * extension} M ${x1 + 8 * u} ${y0} H ${x1 + 8 * u + (dimX - x1) * extension} M ${x1 + 8 * u} ${y1} H ${x1 + 8 * u + (dimX - x1) * extension}`}\n              strokeWidth={thin}\n              strokeOpacity={0.8}\n            />\n            {/* Dimension lines with architectural ticks */}\n            <path\n              d={`M ${hx0} ${dimY} H ${hx1} M ${dimX} ${vy0} V ${vy1}`}\n              strokeWidth={thin * 1.3}\n            />\n            {dims > 0.98\n              ? [\n                  [x0, dimY],\n                  [x1, dimY],\n                  [dimX, y0],\n                  [dimX, y1],\n                ].map(([x, y]) => (\n                  <line\n                    key={`${x}-${y}`}\n                    x1={x - tick}\n                    y1={y + tick}\n                    x2={x + tick}\n                    y2={y - tick}\n                    strokeWidth={stroke}\n                  />\n                ))\n              : null}\n          </g>\n          <g\n            fontFamily={MONO}\n            fontSize={17 * u}\n            letterSpacing={1.5 * u}\n            fill={lineColor}\n            opacity={label}\n          >\n            <rect\n              x={cx - 62 * u}\n              y={dimY - 12 * u}\n              width={124 * u}\n              height={24 * u}\n              fill={blueprintColor}\n            />\n            <text x={cx} y={dimY + 6 * u} textAnchor=\"middle\">\n              {text.width}\n            </text>\n            {bh > 190 * u ? (\n              <g transform={`translate(${dimX} ${cy}) rotate(-90)`}>\n                <rect\n                  x={-66 * u}\n                  y={-12 * u}\n                  width={132 * u}\n                  height={24 * u}\n                  fill={blueprintColor}\n                />\n                <text y={6 * u} textAnchor=\"middle\">\n                  {text.height}\n                </text>\n              </g>\n            ) : (\n              <text x={dimX + 16 * u} y={cy + 6 * u}>\n                {text.height}\n              </text>\n            )}\n            <g\n              transform={`translate(${width - 0.05 * width} ${height - 0.06 * height})`}\n            >\n              <rect\n                x={-290 * u}\n                y={-40 * u}\n                width={290 * u}\n                height={40 * u}\n                fill=\"none\"\n                stroke={lineColor}\n                strokeWidth={thin}\n              />\n              <text x={-276 * u} y={-14 * u} fontSize={14 * u}>\n                {text.title}\n              </text>\n            </g>\n          </g>\n          {/* Red callout */}\n          <g\n            stroke={calloutColor}\n            fill=\"none\"\n            strokeWidth={stroke}\n            strokeLinecap=\"round\"\n          >\n            <circle cx={dot.x} cy={dot.y} r={ring} {...draw(leader)} />\n            <path\n              d={`M ${dot.x - ring * 0.72} ${dot.y - ring * 0.72} ${elbow}`}\n              {...draw(leader)}\n            />\n            <circle\n              cx={lead.x}\n              cy={lead.y}\n              r={16 * u * bubble}\n              fill={calloutColor}\n              stroke=\"none\"\n            />\n          </g>\n          <g fontFamily={MONO} opacity={calloutText}>\n            <text\n              x={lead.x}\n              y={lead.y + 6 * u}\n              textAnchor=\"middle\"\n              fontSize={16 * u}\n              fontWeight={700}\n              fill={lineColor}\n            >\n              A\n            </text>\n            <text\n              x={sideways ? lead.x - 26 * u : lead.x + 26 * u}\n              y={lead.y + 6 * u}\n              textAnchor={sideways ? \"end\" : \"start\"}\n              fontSize={17 * u}\n              letterSpacing={1.5 * u}\n              fill={lineColor}\n            >\n              {text.callout}\n            </text>\n          </g>\n        </svg>\n      </AbsoluteFill>\n\n      {/* Scan edge */}\n      <AbsoluteFill\n        style={{\n          left: wipeX - 2 * u,\n          width: 4 * u,\n          backgroundColor: lineColor,\n          boxShadow: `0 0 ${24 * u}px ${6 * u}px ${lineColor}`,\n          opacity: wipe > 0 && wipe < 1 ? 0.9 : 0,\n        }}\n      />\n    </AbsoluteFill>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/blueprint.tsx"
    }
  ],
  "type": "registry:component"
}
