{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "dashboard-populate", "title": "Dashboard Populate", "description": "An empty dashboard cascades to life with KPI count-ups, bar bounces, line traces, and a donut fill.", "dependencies": [ "remotion" ], "files": [ { "path": "registry/remocn/dashboard-populate/index.tsx", "content": "\"use client\";\n\nimport { interpolate, spring, useCurrentFrame, useVideoConfig } from \"remotion\";\n\nexport interface DashboardPopulateProps {\n accentColor?: string;\n kpiTarget?: number;\n speed?: number;\n className?: string;\n}\n\nconst FONT_FAMILY =\n \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\";\nconst MONO_FAMILY =\n \"var(--font-geist-mono), ui-monospace, SFMono-Regular, Menlo, monospace\";\n\nconst STRUCTURE_END = 15;\n\nfunction formatNumber(n: number) {\n return n.toLocaleString(\"en-US\");\n}\n\nconst BAR_VALUES = [0.55, 0.78, 0.42, 0.92, 0.66];\n\n// Hand-coded line chart points (in 0..100 viewBox space)\nconst LINE_POINTS: Array<[number, number]> = [\n [0, 70],\n [16, 55],\n [32, 62],\n [48, 38],\n [64, 45],\n [80, 22],\n [100, 12],\n];\n\nfunction buildLinePath() {\n return LINE_POINTS.map(([x, y], i) => `${i === 0 ? \"M\" : \"L\"}${x},${y}`).join(\n \" \",\n );\n}\n\nfunction Tile({\n title,\n children,\n structureOpacity,\n}: {\n title: string;\n children: React.ReactNode;\n structureOpacity: number;\n}) {\n return (\n \n \n {title}\n \n
{children}
\n \n );\n}\n\nexport function DashboardPopulate({\n accentColor = \"#22c55e\",\n kpiTarget = 128400,\n speed = 1,\n className,\n}: DashboardPopulateProps) {\n const frame = useCurrentFrame() * speed;\n const { fps } = useVideoConfig();\n\n // Phase 1: structure fade in 0..15\n const structureOpacity = interpolate(frame, [0, STRUCTURE_END], [0, 1], {\n extrapolateLeft: \"clamp\",\n extrapolateRight: \"clamp\",\n });\n\n // KPI count up\n const kpiSpring = spring({\n frame: frame - STRUCTURE_END,\n fps,\n config: { damping: 20, stiffness: 80, mass: 1 },\n durationInFrames: 60,\n });\n const kpiValue = Math.floor(kpiSpring * kpiTarget);\n const kpiDelta = interpolate(kpiSpring, [0, 1], [0, 12.4]);\n\n // Bar chart springs (staggered)\n const barProgress = BAR_VALUES.map((_, i) =>\n spring({\n frame: frame - STRUCTURE_END - i * 4,\n fps,\n config: { damping: 11, stiffness: 140, mass: 1 },\n durationInFrames: 40,\n }),\n );\n\n // Line chart stroke-dashoffset\n const linePath = buildLinePath();\n // approx length for viewBox 100x100 — use a generous constant; we set\n // pathLength on the path so dashoffset works in normalized units\n const lineProgress = interpolate(\n frame,\n [STRUCTURE_END + 4, STRUCTURE_END + 50],\n [0, 1],\n { extrapolateLeft: \"clamp\", extrapolateRight: \"clamp\" },\n );\n\n // Donut\n const donutTarget = 0.72;\n const donutSpring = spring({\n frame: frame - STRUCTURE_END - 6,\n fps,\n config: { damping: 13, stiffness: 110, mass: 1 },\n durationInFrames: 50,\n });\n const donutValue = donutSpring * donutTarget;\n const donutR = 70;\n const donutCircum = 2 * Math.PI * donutR;\n\n return (\n \n {/* Subtle grid bg */}\n \n \n
\n \n Overview\n
\n \n Last 30 days\n \n \n \n {[\"1D\", \"7D\", \"30D\", \"ALL\"].map((l, i) => (\n \n {l}\n \n ))}\n \n \n\n \n {/* KPI */}\n \n \n \n ${formatNumber(kpiValue)}\n \n \n +{kpiDelta.toFixed(1)}%\n \n vs last month\n \n \n \n \n\n {/* Bar chart */}\n \n \n {/* axes */}\n \n {[25, 50, 75].map((y) => (\n \n ))}\n {BAR_VALUES.map((v, i) => {\n const barH = v * 90 * barProgress[i];\n const barW = 24;\n const x = 16 + i * 36;\n const y = 100 - barH;\n return (\n \n );\n })}\n \n \n\n {/* Line chart */}\n \n \n \n {[20, 40, 60, 80].map((y) => (\n \n ))}\n \n {/* dots */}\n {LINE_POINTS.map(([px, py], i) => {\n const dotProgress = interpolate(\n lineProgress,\n [\n i / (LINE_POINTS.length - 1),\n i / (LINE_POINTS.length - 1) + 0.05,\n ],\n [0, 1],\n { extrapolateLeft: \"clamp\", extrapolateRight: \"clamp\" },\n );\n return (\n \n );\n })}\n \n \n\n {/* Donut */}\n \n \n \n \n \n \n \n {(donutValue * 100).toFixed(1)}%\n \n \n \n \n \n );\n}\n", "type": "registry:component", "target": "components/remocn/dashboard-populate.tsx" } ], "type": "registry:component" }