+ {Array.from({ length: bars }).map((_, i) => {
+ const h = heights[(i + Math.floor(delay)) % heights.length];
+ const grow = interpolate(frame, [delay + i * 3, delay + i * 3 + 12], [0.05, 1], {
+ extrapolateLeft: "clamp", extrapolateRight: "clamp",
+ });
+ const px = Math.max(2, Math.round(h * MAX_H * grow));
+ return (
+
+ );
+ })}
+
+ );
+};
+
+/** Line chart that draws itself left→right (clip-width animation). */
+export const ChartLine: React.FC<{ delay?: number }> = ({ delay = 0 }) => {
+ const frame = useCurrentFrame();
+ const { fps } = useVideoConfig();
+ const p = interpolate(frame, [delay, delay + fps * 0.9], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
+ return (
+
+ {items.map((it, i) => {
+ const p = spring({ frame: Math.max(0, frame - delay - i * 14), fps, config: { damping: 16, stiffness: 100 } });
+ const done = p > 0.35;
+ return (
+
+ );
+ })}
+
+ );
+};
+
+/** HUD corner frame + crosshair center (tech overlay asset). */
+export const HudFrame: React.FC<{ label?: string }> = ({ label = "SYSTEM" }) => {
+ const frame = useCurrentFrame();
+ const t = frame / 60;
+ const c = 36;
+ const gap = 26;
+ return (
+