"use client"; // A GitHub-style contribution grid for an agent: a year of day-squares whose // colour denotes how much the agent did that day (commits/activity). It's drawn // on a canvas via requestAnimationFrame so it stays lively without re-rendering // React: every active cell breathes, a highlight wave sweeps left→right, and // "hot" days (>100) glow gold and pulse harder. Data is seeded per-agent and // simulated for now — swap `generate()` for real telemetry later. import { useEffect, useMemo, useRef } from "react"; const mono = "'JetBrains Mono', ui-monospace, monospace"; const WEEKS = 53; const DAYS = 7; // 0 = empty, 1..4 = the classic green ramp, 5 = a "hot" (>100) gold day. const COLORS = [ "rgba(255,255,255,.05)", "#0e4d2e", "#1c854c", "#2fbf6e", "#54e892", "#ffc24b", ]; function levelOf(c: number): number { if (c <= 0) return 0; if (c < 8) return 1; if (c < 25) return 2; if (c < 60) return 3; if (c < 100) return 4; return 5; // hot } // Small seeded PRNG so each agent gets a stable-but-distinct year. function hashStr(s: string): number { let h = 2166136261; for (let i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 16777619); } return h >>> 0; } function mulberry32(a: number) { return () => { a |= 0; a = (a + 0x6d2b79f5) | 0; let t = Math.imul(a ^ (a >>> 15), 1 | a); t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; } function generate(seed: string) { const rnd = mulberry32(hashStr(seed || "agent")); const commits: number[] = []; const levels: number[] = []; let total = 0; let hot = 0; // Per-week "momentum" makes streaky busy/quiet stretches instead of pure noise. for (let w = 0; w < WEEKS; w++) { const weekBoost = rnd() < 0.22 ? rnd() * 45 : 0; const quietWeek = rnd() < 0.16; for (let d = 0; d < DAYS; d++) { const weekend = d === 0 || d === 6; let v = (weekend ? 3 : 16) + rnd() * (weekend ? 8 : 26) + weekBoost; if (quietWeek) v *= 0.25; if (rnd() < 0.035) v += 95 + rnd() * 85; // occasional hot day if (rnd() < 0.12) v = rnd() * 3; // an off day const c = Math.max(0, Math.round(v)); commits.push(c); const lv = levelOf(c); levels.push(lv); total += c; if (lv === 5) hot++; } } return { commits, levels, total, hot }; } function roundRect(ctx: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, r: number) { ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); } export function VitalsCard({ seed = "agent" }: { seed?: string }) { const canvasRef = useRef(null); const wrapRef = useRef(null); const data = useMemo(() => generate(seed), [seed]); useEffect(() => { const cv = canvasRef.current; const wrap = wrapRef.current; if (!cv || !wrap) return; const ctx = cv.getContext("2d"); if (!ctx) return; const { levels } = data; const dpr = Math.min(window.devicePixelRatio || 1, 2); let cssW = 0, cssH = 0, step = 16, cell = 13, cols = WEEKS, padX = 0, padY = 2; let t = 0, raf = 0; const resize = () => { const r = wrap.getBoundingClientRect(); cssW = r.width; cssH = r.height; cv.width = Math.max(1, Math.round(cssW * dpr)); cv.height = Math.max(1, Math.round(cssH * dpr)); ctx.setTransform(dpr, 0, 0, dpr, 0, 0); // Size cells to the available height (7 rows) and cap, then fit the columns. step = Math.max(11, Math.min(17, Math.floor((cssH - padY * 2) / DAYS))); cell = step - 3; cols = Math.max(8, Math.min(WEEKS, Math.floor((cssW - 2) / step))); padX = Math.max(0, Math.round((cssW - cols * step) / 2)); padY = Math.max(0, Math.round((cssH - DAYS * step) / 2)); }; resize(); const ro = new ResizeObserver(resize); ro.observe(wrap); const draw = () => { t += 1; const time = t * 0.016; const wavePos = ((time * 8) % (cols + 12)) - 6; // sweeping highlight const offset = WEEKS - cols; // show the most recent weeks ctx.clearRect(0, 0, cssW, cssH); for (let w = 0; w < cols; w++) { for (let d = 0; d < DAYS; d++) { const lv = levels[(offset + w) * DAYS + d]; const x = padX + w * step; const y = padY + d * step; const phase = w * 0.5 + d * 0.85; const dx = w - wavePos; const wave = Math.exp(-(dx * dx) / 5) * (lv === 0 ? 0.1 : 0.5); let alpha: number; if (lv === 0) { alpha = 0.55 + wave; } else if (lv === 5) { const hp = 0.7 + 0.3 * Math.sin(time * 4 + phase); ctx.shadowColor = COLORS[5]; ctx.shadowBlur = 7 + 7 * hp; alpha = Math.min(1, 0.82 + 0.18 * hp + wave); } else { const pulse = (0.5 + 0.5 * Math.sin(time * 1.8 + phase)) * (0.1 + lv * 0.035); alpha = Math.min(1, 0.58 + pulse + wave); } ctx.globalAlpha = alpha; ctx.fillStyle = COLORS[lv]; roundRect(ctx, x, y, cell, cell, 2.5); ctx.fill(); ctx.shadowBlur = 0; // Crest of the wave flashes a faint white highlight over lit cells. if (wave > 0.32 && lv > 0) { ctx.globalAlpha = (wave - 0.32) * 0.7; ctx.fillStyle = "#ffffff"; roundRect(ctx, x, y, cell, cell, 2.5); ctx.fill(); } } } ctx.globalAlpha = 1; raf = requestAnimationFrame(draw); }; raf = requestAnimationFrame(draw); return () => { cancelAnimationFrame(raf); ro.disconnect(); }; }, [data]); return (
ACTIVITY · LIVE {data.total.toLocaleString()} commits {data.hot > 0 ? · {data.hot} hot : null}
past year · simulated, not yet wired to live telemetry Less {COLORS.slice(1).map((c) => ())} More
); }