Three D3.js charts built like product interfaces. A live FPS monitor, an interactive scatter plot, a force-directed graph with drag and hover. Real data, real interaction, designed with intention.
D3.js is a decision engine disguised as a charting library. Every visual property — axis color, label size, transition timing — is a manual call. The brief forced the question: three chart types, live data, one visual language. What are the actual decisions?
The constraint: D3 uses presentation attributes, not CSS. Design tokens don't inherit. Every color, every opacity, every stroke width had to be applied at the render layer — not the style sheet. The result is a tighter coupling between data and design than most component libraries allow.
The force graph was the hardest. Nodes, links, labels, and drag state updating at 60fps while staying legible. That's the one worth looking at.
Frame rate over time. Live simulation — 60fps target, realistic jank spikes. Hover for exact values.
Every design decision from this portfolio mapped by implementation complexity and perceived impact. Size = lines of code. Hover any point for details.
All 12 nodes of the AI Interface Pattern set. Hover to highlight connections. Drag to explore. The topology is the architecture.
The portfolio in raw numbers. Every line earned.
45fps and 52fps. Same data, three meanings — green lane, yellow lane, red lane. You read the health from the color, not the number.√loc × 1.4. Linear sizing buries small items; log sizing exaggerates. Square-root keeps hierarchy readable across 16 points.1 - (1-t)³. Numbers slow as they approach the target. Linear counters feel mechanical; this lands.requestAnimationFrame — different design problem, harder spikes to read.