{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "per-word-crossfade",
  "title": "Per-Word Crossfade",
  "description": "Words gently fade into place one after another, with a short vertical drift for a calm keynote rhythm.",
  "dependencies": ["remotion"],
  "files": [
    {
      "path": "registry/remocn/per-word-crossfade/index.tsx",
      "content": "\"use client\";\n\nimport { Easing, interpolate, useCurrentFrame } from \"remotion\";\n\nexport interface PerWordCrossfadeProps {\n  fromText: string;\n  toText: string;\n  fontSize?: number;\n  color?: string;\n  fontWeight?: number;\n  speed?: number;\n  className?: string;\n}\n\nexport function PerWordCrossfade({\n  fromText,\n  toText,\n  fontSize = 72,\n  color = \"#171717\",\n  fontWeight = 600,\n  speed = 1,\n  className,\n}: PerWordCrossfadeProps) {\n  const frame = useCurrentFrame() * speed;\n\n  const fromWords = fromText.split(\" \");\n  const toWords = toText.split(\" \");\n\n  const enterDur = 21;\n  const enterTravel = 5;\n  const exitDur = 15;\n  const exitTravelFrom = 6;\n  const enterStagger = 2;\n  const exitStagger = 1;\n  const overlapF = 5;\n  const microDelayF = 2;\n\n  const enterEasing = Easing.bezier(0.16, 1, 0.3, 1);\n  const exitEasing = Easing.bezier(0.7, 0, 0.84, 0);\n\n  const exitTotal = exitDur + (fromWords.length - 1) * exitStagger;\n  const newStart = Math.max(0, exitTotal - overlapF + microDelayF);\n\n  const fontStack =\n    \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\";\n\n  return (\n    <div\n      className={className}\n      style={{\n        position: \"absolute\",\n        inset: 0,\n        background: \"transparent\",\n      }}\n    >\n      <div\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n        }}\n      >\n        <span\n          style={{\n            fontSize,\n            fontWeight,\n            color,\n            letterSpacing: \"-0.03em\",\n            fontFamily: fontStack,\n          }}\n        >\n          {fromWords.map((word, i) => {\n            const local = frame - i * exitStagger;\n            const opacity = interpolate(local, [0, exitDur], [1, 0], {\n              extrapolateLeft: \"clamp\",\n              extrapolateRight: \"clamp\",\n              easing: exitEasing,\n            });\n            const y = interpolate(local, [exitTravelFrom, exitDur], [0, -6], {\n              extrapolateLeft: \"clamp\",\n              extrapolateRight: \"clamp\",\n              easing: exitEasing,\n            });\n            return (\n              <span\n                key={i}\n                style={{\n                  display: \"inline-block\",\n                  marginRight: \"0.25em\",\n                  transformOrigin: \"50% 55%\",\n                  opacity,\n                  translate: `0 ${y}px`,\n                }}\n              >\n                {word}\n              </span>\n            );\n          })}\n        </span>\n      </div>\n\n      <div\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n        }}\n      >\n        <span\n          style={{\n            fontSize,\n            fontWeight,\n            color,\n            letterSpacing: \"-0.03em\",\n            fontFamily: fontStack,\n          }}\n        >\n          {toWords.map((word, j) => {\n            const local = frame - newStart - j * enterStagger;\n            const opacity = interpolate(local, [0, enterDur], [0, 1], {\n              extrapolateLeft: \"clamp\",\n              extrapolateRight: \"clamp\",\n              easing: enterEasing,\n            });\n            const y = interpolate(local, [0, enterTravel], [8, 0], {\n              extrapolateLeft: \"clamp\",\n              extrapolateRight: \"clamp\",\n              easing: enterEasing,\n            });\n            return (\n              <span\n                key={j}\n                style={{\n                  display: \"inline-block\",\n                  marginRight: \"0.25em\",\n                  transformOrigin: \"50% 55%\",\n                  opacity,\n                  translate: `0 ${y}px`,\n                }}\n              >\n                {word}\n              </span>\n            );\n          })}\n        </span>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/per-word-crossfade.tsx"
    }
  ],
  "type": "registry:component"
}
