{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "outline-fill-track-text",
  "title": "Outline Fill Track Text",
  "description": "A rising lead word gives way to an outlined value that fills from left to right while both travel on one continuous track.",
  "dependencies": ["remotion"],
  "files": [
    {
      "path": "registry/remocn/outline-fill-track-text/index.tsx",
      "content": "\"use client\";\n\nimport { useMemo } from \"react\";\nimport { Easing, interpolate, useCurrentFrame, useVideoConfig } from \"remotion\";\n\nexport interface OutlineFillTrackTextProps {\n  leadText?: string;\n  valueText?: string;\n  fontSize?: number;\n  fontWeight?: number;\n  color?: string;\n  outlineColor?: string;\n  outlineWidth?: number;\n  backgroundColor?: string;\n  glowColor?: string;\n  enterOffset?: number;\n  anchorOffsetX?: number;\n  trackDistance?: number;\n  wordGap?: number;\n  endPadding?: number;\n  fillDuration?: number;\n  speed?: number;\n  className?: string;\n}\n\nexport const outlineFillTrackTextLength = 80;\n\nconst ENTER_END = 16;\nconst TRACK_START = 16;\nconst TRACK_END = 72;\nconst FILL_START = 34;\nconst FILL_PREFILL = 10;\nconst FONT_FAMILY = \"Arial, Helvetica, sans-serif\";\nconst clamp = {\n  extrapolateLeft: \"clamp\" as const,\n  extrapolateRight: \"clamp\" as const,\n};\n\nfunction estimateTextWidth(\n  text: string,\n  fontSize: number,\n  fontWeight: number,\n): number {\n  if (typeof document === \"undefined\") {\n    return text.length * fontSize * 0.56;\n  }\n\n  const context = document.createElement(\"canvas\").getContext(\"2d\");\n  if (!context) return text.length * fontSize * 0.56;\n  context.font = `${fontWeight} ${fontSize}px Arial`;\n  return context.measureText(text).width;\n}\n\nexport function OutlineFillTrackText({\n  leadText = \"Keep\",\n  valueText = \"1000000000%\",\n  fontSize = 368,\n  fontWeight = 700,\n  color = \"#f4f3f6\",\n  outlineColor = \"#e6e2ed\",\n  outlineWidth = 3,\n  backgroundColor = \"#030012\",\n  glowColor = \"#64109a\",\n  enterOffset = 240,\n  anchorOffsetX = -84,\n  trackDistance = 0,\n  wordGap = 220,\n  endPadding = 96,\n  fillDuration = 38,\n  speed = 1,\n  className,\n}: OutlineFillTrackTextProps) {\n  const frame = useCurrentFrame() * Math.max(speed, 0);\n  const { width: compositionWidth } = useVideoConfig();\n  const safeFontSize = Math.max(fontSize, 1);\n  const safeFontWeight = Math.max(fontWeight, 1);\n  const safeOutlineWidth = Math.max(outlineWidth, 0);\n  const safeGap = Math.max(wordGap, 0);\n  const safeEndPadding = Math.max(endPadding, 0);\n  const safeFillDuration = Math.max(fillDuration, 1);\n\n  const measurements = useMemo(() => {\n    const leadWidth = estimateTextWidth(leadText, safeFontSize, safeFontWeight);\n    const valueWidth = estimateTextWidth(\n      valueText,\n      safeFontSize,\n      safeFontWeight,\n    );\n    return {\n      valueWidth,\n      distance: leadWidth / 2 + safeGap + valueWidth / 2,\n    };\n  }, [leadText, safeFontSize, safeFontWeight, safeGap, valueText]);\n\n  const valueOffset = trackDistance > 0 ? trackDistance : measurements.distance;\n  const anchorX = compositionWidth / 2 + anchorOffsetX;\n  const trailingOverflow = Math.max(\n    0,\n    anchorX + measurements.valueWidth / 2 - (compositionWidth - safeEndPadding),\n  );\n  const travelDistance = valueOffset + trailingOverflow;\n  const enterProgress = interpolate(frame, [0, ENTER_END], [0, 1], {\n    ...clamp,\n    easing: Easing.bezier(0.16, 0.84, 0.24, 1),\n  });\n  const trackProgress = interpolate(frame, [TRACK_START, TRACK_END], [0, 1], {\n    ...clamp,\n    easing: Easing.bezier(0.42, 0, 0.58, 1),\n  });\n  const fillProgress = interpolate(\n    frame,\n    [FILL_START - FILL_PREFILL, FILL_START + safeFillDuration],\n    [0, 1],\n    clamp,\n  );\n  const leadY = enterOffset * (1 - enterProgress);\n  const revealEdge = enterProgress * 112 - 8;\n  const revealSolid = Math.max(0, Math.min(100, revealEdge - 10));\n  const revealFade = Math.max(0, Math.min(100, revealEdge + 10));\n  const leadMask = `linear-gradient(180deg, #000 0%, #000 ${revealSolid}%, transparent ${revealFade}%, transparent 100%)`;\n  const glowOpacity = interpolate(\n    enterProgress,\n    [0, 0.18, 0.72, 1],\n    [0.92, 1, 0.52, 0],\n    clamp,\n  );\n  const fieldY = interpolate(enterProgress, [0, 1], [-42, -210], clamp);\n  const textStyle = {\n    display: \"block\",\n    fontFamily: FONT_FAMILY,\n    fontSize: safeFontSize,\n    fontWeight: safeFontWeight,\n    letterSpacing: 0,\n    lineHeight: 0.86,\n    whiteSpace: \"nowrap\" as const,\n  };\n\n  return (\n    <div\n      className={className}\n      style={{\n        position: \"absolute\",\n        inset: 0,\n        overflow: \"hidden\",\n        backgroundColor,\n      }}\n    >\n      <div\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          background: `radial-gradient(ellipse 118% 66% at 50% -12%, ${glowColor} 0%, ${glowColor} 14%, transparent 76%)`,\n          filter: `blur(${safeFontSize * 0.15}px)`,\n          opacity: glowOpacity,\n          pointerEvents: \"none\",\n          transform: \"translateZ(0)\",\n        }}\n      />\n\n      <div\n        style={{\n          position: \"absolute\",\n          top: \"50%\",\n          left: `calc(50% + ${anchorOffsetX}px)`,\n          transform: `translate3d(${-travelDistance * trackProgress}px, -50%, 0)`,\n        }}\n      >\n        <div\n          style={{\n            position: \"absolute\",\n            top: 0,\n            left: 0,\n            color,\n            maskImage: leadMask,\n            maskRepeat: \"no-repeat\",\n            opacity: 1,\n            transform: `translate3d(-50%, calc(-50% + ${leadY}px), 0)`,\n            WebkitMaskImage: leadMask,\n            WebkitMaskRepeat: \"no-repeat\",\n            ...textStyle,\n          }}\n        >\n          {leadText}\n        </div>\n\n        <div\n          style={{\n            position: \"absolute\",\n            top: 0,\n            left: valueOffset,\n            transform: \"translate3d(-50%, -50%, 0)\",\n            visibility: frame < FILL_START ? \"hidden\" : \"visible\",\n          }}\n        >\n          <span\n            style={{\n              ...textStyle,\n              color: \"transparent\",\n              paintOrder: \"stroke fill\",\n              WebkitTextStroke: `${safeOutlineWidth}px ${outlineColor}`,\n            }}\n          >\n            {valueText}\n          </span>\n          <span\n            style={{\n              ...textStyle,\n              position: \"absolute\",\n              inset: 0,\n              clipPath: `inset(0 ${100 - fillProgress * 100}% 0 0)`,\n              color,\n              opacity: 1,\n            }}\n          >\n            {valueText}\n          </span>\n        </div>\n\n        <div\n          style={{\n            position: \"absolute\",\n            top: fieldY,\n            left: 0,\n            width: safeFontSize * 2.8,\n            height: safeFontSize * 0.72,\n            background: `radial-gradient(ellipse at center, ${backgroundColor} 0%, ${backgroundColor} 18%, transparent 74%)`,\n            filter: `blur(${safeFontSize * 0.07}px)`,\n            opacity: glowOpacity,\n            pointerEvents: \"none\",\n            transform: \"translate3d(-50%, -50%, 0)\",\n          }}\n        />\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/outline-fill-track-text.tsx"
    }
  ],
  "type": "registry:component"
}
