{
  "name": "slot-roll",
  "type": "registry:ui",
  "description": "Characters roll like a slot reel into place",
  "dependencies": [
    "remotion"
  ],
  "registryDependencies": [
    "layout",
    "timing"
  ],
  "files": [
    {
      "path": "registry/bases/default/primitives/slot-roll.tsx",
      "type": "registry:ui",
      "content": "import { interpolate, useCurrentFrame, useVideoConfig } from \"remotion\";\nimport { scaleFont } from \"@/remotion/lib/layout\";\nimport { EASING_ENTER } from \"@/remotion/lib/timing\";\n\nexport type SlotRollProps = {\n  from: string;\n  to: string;\n  durationInFrames?: number;\n  delayInFrames?: number;\n  fontSize?: number;\n  color?: string;\n  fontWeight?: number;\n  fontFamily?: string;\n};\n\nconst CHARSET = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\nfunction rollChar(from: string, to: string, progress: number, seed: number): string {\n  if (progress >= 1) return to;\n  if (progress <= 0) return from;\n  if (from === to) return to;\n  const idx = Math.floor(\n    interpolate(progress, [0, 0.85, 1], [0, CHARSET.length - 1, 0], {\n      extrapolateLeft: \"clamp\",\n      extrapolateRight: \"clamp\",\n    }) +\n      seed * 3,\n  );\n  return CHARSET[Math.abs(idx) % CHARSET.length] ?? to;\n}\n\nexport const SlotRoll: React.FC<SlotRollProps> = ({\n  from,\n  to,\n  durationInFrames = 40,\n  delayInFrames = 0,\n  fontSize: fontSizeProp,\n  color = \"#f4f4f5\",\n  fontWeight = 700,\n  fontFamily,\n}) => {\n  const frame = useCurrentFrame();\n  const { width } = useVideoConfig();\n  const fontSize = fontSizeProp ?? scaleFont(96, width);\n  const progress = interpolate(\n    frame,\n    [delayInFrames, delayInFrames + durationInFrames],\n    [0, 1],\n    {\n      easing: EASING_ENTER,\n      extrapolateLeft: \"clamp\",\n      extrapolateRight: \"clamp\",\n    },\n  );\n  const len = Math.max(from.length, to.length);\n  const paddedFrom = from.padStart(len, \" \");\n  const paddedTo = to.padStart(len, \" \");\n  const display = Array.from({ length: len }, (_, i) =>\n    rollChar(paddedFrom[i] ?? \" \", paddedTo[i] ?? \" \", progress, i),\n  ).join(\"\");\n\n  return (\n    <span\n      style={{\n        fontSize,\n        fontWeight,\n        color,\n        fontVariantNumeric: \"tabular-nums\",\n        letterSpacing: \"0.04em\",\n        ...(fontFamily ? { fontFamily } : {}),\n      }}\n    >\n      {display.trimStart()}\n    </span>\n  );\n};\n"
    }
  ],
  "atlas": {
    "lane": "atoms",
    "drive": "time",
    "tier": "advanced",
    "tags": [
      "text"
    ]
  }
}