{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "animated-line-chart",
  "title": "Animated Line Chart",
  "description": "Line chart whose SVG path draws on from left to right with a leading dot.",
  "dependencies": [
    "remotion"
  ],
  "files": [
    {
      "path": "registry/bases/editframe/components/animated-line-chart/index.tsx",
      "content": "\"use client\";\n\nimport { Timegroup } from \"@editframe/react\";\nimport type { CSSProperties } from \"react\";\n\nexport interface AnimatedLineChartProps {\n  data?: number[];\n  width?: number;\n  height?: number;\n  strokeColor?: string;\n  strokeWidth?: number;\n  background?: string;\n  gridColor?: string;\n  showDot?: boolean;\n  speed?: number;\n  fps?: number;\n  durationInFrames?: number;\n  className?: string;\n}\n\nexport const AnimatedLineChart = ({\n  data = [12, 19, 8, 15, 22, 18, 28, 25, 32],\n  width = 1000,\n  height = 500,\n  strokeColor = \"#22c55e\",\n  strokeWidth = 4,\n  background = \"#0a0a0a\",\n  gridColor = \"#27272a\",\n  showDot = true,\n  speed = 1,\n  fps = 30,\n  durationInFrames = 90,\n  className,\n}: AnimatedLineChartProps) => {\n  const safeSpeed = Math.max(0.01, speed);\n  const durationMs = ((durationInFrames / fps) * 1000) / safeSpeed;\n  const lineDurationMs = (((durationInFrames * 0.85) / fps) * 1000) / safeSpeed;\n\n  const padding = 60;\n  const innerWidth = width - padding * 2;\n  const innerHeight = height - padding * 2;\n\n  const min = Math.min(...data);\n  const max = Math.max(...data);\n  const range = max - min || 1;\n\n  const points = data.map((value, index) => {\n    const x = padding + (index / (data.length - 1)) * innerWidth;\n    const y = padding + innerHeight - ((value - min) / range) * innerHeight;\n    return { x, y };\n  });\n\n  let pathLength = 0;\n  for (let i = 1; i < points.length; i += 1) {\n    const dx = points[i].x - points[i - 1].x;\n    const dy = points[i].y - points[i - 1].y;\n    pathLength += Math.hypot(dx, dy);\n  }\n\n  const d = points\n    .map((p, i) => `${i === 0 ? \"M\" : \"L\"}${p.x.toFixed(2)},${p.y.toFixed(2)}`)\n    .join(\" \");\n\n  const gridRows = 4;\n  const gridCols = data.length - 1;\n\n  const chartStyle: CSSProperties = {\n    alignItems: \"center\",\n    background,\n    display: \"flex\",\n    fontFamily:\n      \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\",\n    height,\n    justifyContent: \"center\",\n    overflow: \"hidden\",\n    position: \"relative\",\n    width,\n  };\n\n  return (\n    <Timegroup\n      className={className}\n      duration={`${durationMs}ms`}\n      mode=\"fixed\"\n      style={chartStyle}\n    >\n      <>\n        <style>{`\n          @keyframes framecn-line-draw {\n            from {\n              stroke-dashoffset: ${pathLength};\n              opacity: 0.7;\n            }\n            to {\n              stroke-dashoffset: 0;\n              opacity: 1;\n            }\n          }\n          @keyframes framecn-line-dot {\n            0% {\n              offset-distance: 0%;\n              opacity: 0;\n            }\n            5% {\n              opacity: 1;\n            }\n            100% {\n              offset-distance: 100%;\n              opacity: 1;\n            }\n          }\n        `}</style>\n        <svg\n          width={width}\n          height={height}\n          viewBox={`0 0 ${width} ${height}`}\n          style={{ overflow: \"visible\" }}\n        >\n          {/* Horizontal grid */}\n          {Array.from({ length: gridRows + 1 }).map((_, i) => {\n            const y = padding + (i / gridRows) * innerHeight;\n            return (\n              <line\n                key={`h-${i}`}\n                x1={padding}\n                x2={padding + innerWidth}\n                y1={y}\n                y2={y}\n                stroke={gridColor}\n                strokeWidth={1}\n              />\n            );\n          })}\n          {/* Vertical grid */}\n          {Array.from({ length: gridCols + 1 }).map((_, i) => {\n            const x = padding + (i / gridCols) * innerWidth;\n            return (\n              <line\n                key={`v-${i}`}\n                x1={x}\n                x2={x}\n                y1={padding}\n                y2={padding + innerHeight}\n                stroke={gridColor}\n                strokeWidth={1}\n              />\n            );\n          })}\n          {/* Axis */}\n          <line\n            x1={padding}\n            x2={padding}\n            y1={padding}\n            y2={padding + innerHeight}\n            stroke={gridColor}\n            strokeWidth={2}\n          />\n          <line\n            x1={padding}\n            x2={padding + innerWidth}\n            y1={padding + innerHeight}\n            y2={padding + innerHeight}\n            stroke={gridColor}\n            strokeWidth={2}\n          />\n\n          {/* Animated line */}\n          <path\n            d={d}\n            fill=\"none\"\n            stroke={strokeColor}\n            strokeWidth={strokeWidth}\n            strokeLinecap=\"round\"\n            strokeLinejoin=\"round\"\n            strokeDasharray={pathLength}\n            style={{\n              animation: `framecn-line-draw ${lineDurationMs}ms cubic-bezier(0.16, 1, 0.3, 1) backwards`,\n              filter: `drop-shadow(0 0 12px ${strokeColor}55)`,\n            }}\n          />\n\n          {showDot && (\n            <circle\n              r={strokeWidth * 2}\n              fill={strokeColor}\n              style={{\n                animation: `framecn-line-dot ${lineDurationMs}ms cubic-bezier(0.16, 1, 0.3, 1) backwards`,\n                filter: `drop-shadow(0 0 8px ${strokeColor})`,\n                offsetPath: `path(\"${d}\")`,\n              }}\n            />\n          )}\n        </svg>\n      </>\n    </Timegroup>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/framecn/animated-line-chart.tsx"
    }
  ],
  "type": "registry:component"
}