When engineering browser-based simulation tools for mechanical engineering and building science, UI responsiveness is non-negotiable. HVAC design calculations (such as Darcy-Weisbach friction gradients, psychrometric moist-air state points, and multi-zone heat loss distributions) require continuous visual feedback as engineers manipulate sliders and numeric inputs.
In early iterations of our open-access engineering suite at HVACLogic, our instinct was to drop in standard React charting libraries (Recharts, Chart.js, or D3 wrappers). The resulting architecture worked, but it introduced severe engineering trade-offs:
- Bundle Overhead: Adding Recharts and its associated dependencies introduced over 280kB of minified JavaScript to the initial bundle.
- Hydration Jank & INP Penalties: Heavy virtual DOM reconciliations across canvas/SVG wrapper nodes degraded Core Web Vitals, causing Interaction to Next Paint (INP) to climb above 120ms during continuous slider drags.
- Domain Constraint Mismatch: Generic charting libraries expect standard Cartesian bar or line series. They fight you when you need exact physical aspect ratios, fluid velocity vectors, or thermodynamic pressure gradients.
In this article, we break down how we architected 100% reactive, zero-dependency SVG visualizers in Next.js 15 and React 19, demonstrating real code patterns from production.
The Architecture: Pure Mathematical State to SVG Mapping
The core philosophy is simple: Math functions produce geometric coordinates; React merely binds them to native SVG elements.
Instead of importing a monolithic charting library, we write deterministic projection functions that convert numerical engineering outputs directly into SVG path strings (d="M ... A ..." or <circle /> coordinates).
[User Input State]
│
▼
[Deterministic Physics Solver (Pure TS)]
│
▼
[SVG Coordinate Normalization]
│
▼
[Native Next.js 15 SVG Component (Zero Runtime Deps)]
Because native SVG elements are standard DOM nodes, the browser hardware-accelerates rendering via the GPU, completely eliminating third-party runtime overhead.
Example 1: Real-Time Trigonometric Donut Visualizer Without D3
Consider a multi-component building envelope heat loss breakdown (walls, fenestration, ceiling, infiltration). Rather than pulling in D3-shape or Pie charts to render a distribution donut, we compute the SVG arc paths using elementary trigonometry:
// src/components/calculator/visualizers/HeatLossDonutVisualizer.tsx
"use client";
import React from "react";
export interface LoadBreakdownItem {
label: string;
btu: number;
percentage: number;
color: string;
}
export function HeatLossDonutVisualizer({ breakdown }: { breakdown: LoadBreakdownItem[] }) {
let cumulativePercentage = 0;
const segments = breakdown.map((item) => {
const startAngle = (cumulativePercentage / 100) * 360;
cumulativePercentage += item.percentage;
const endAngle = (cumulativePercentage / 100) * 360;
// Convert polar degrees to Cartesian radians (-90deg offset for 12 o'clock top start)
const startRad = ((startAngle - 90) * Math.PI) / 180;
const endRad = ((endAngle - 90) * Math.PI) / 180;
const r = 70;
const cx = 100;
const cy = 100;
const x1 = cx + r * Math.cos(startRad);
const y1 = cy + r * Math.sin(startRad);
const x2 = cx + r * Math.cos(endRad);
const y2 = cy + r * Math.sin(endRad);
const largeArcFlag = item.percentage > 50 ? 1 : 0;
const d = `M ${x1} ${y1} A ${r} ${r} 0 ${largeArcFlag} 1 ${x2} ${y2}`;
return { ...item, d };
});
return (
<div className="donut-container">
<svg viewBox="0 0 200 200" width="100%" height="100%" aria-label="Heat Load Distribution Donut">
<circle cx="100" cy="100" r="70" fill="none" stroke="var(--surface)" strokeWidth="26" />
{segments.map((seg) => (
<path
key={seg.label}
d={seg.d}
fill="none"
stroke={seg.color}
strokeWidth="24"
strokeLinecap="round"
/>
))}
</svg>
</div>
);
}
This entire component compiles down to less than 1.5kB of code, executes at 60 FPS on low-end mobile devices, and renders pixel-perfect vector curves at any screen resolution. You can inspect this live in our Heat Loss Calculator.
Example 2: Dynamic Aerodynamic Pressure Decay Gradients
In our Duct Static Pressure Drop Calculator, mechanical contractors must visualize Available Static Pressure (ASP) decay along the Total Effective Length (TEL) of an air distribution run per ACCA Manual D:
ASP = TESP - ΔP(coil) - ΔP(filter) - ΔP(supply devices)
To visualize this dynamic decay curve without Canvas or WebGL, we project normalized static pressure values directly into SVG viewBox coordinate units:
// Excerpt from src/components/calculator/visualizers/DuctFrictionVisualizer.tsx
export function DuctFrictionVisualizer({ output }: DuctFrictionVisualizerProps) {
// SVG coordinates: viewBox 0 0 460 165
const startY = 40;
// Calculate relative pressure drop slope
const aspDropY = 20 + Math.max(0, (0.50 - output.availableStaticPressureAspInWg) * 50);
return (
<svg viewBox="0 0 460 165" style={{ width: "100%", height: "100%" }}>
{/* Background Track */}
<rect x="30" y="15" width="400" height="40" fill="rgba(15, 23, 42, 0.6)" rx="4" />
{/* Blower TESP Origin */}
<circle cx="50" cy={startY} r="4" fill="#00d2ff" />
{/* Pressure Decay Gradient Path */}
<path
d={`M 50 ${startY} L 140 ${startY} L 170 32 L 280 32 L 410 ${aspDropY}`}
fill="none"
stroke={statusColor}
strokeWidth="2.5"
/>
{/* Available Static Budget Point */}
<circle cx="410" cy={aspDropY} r="4" fill={statusColor} />
</svg>
);
}
Performance Benchmarks: External Charting vs. Pure SVG
We benchmarked a continuous slider input dispatching 60 state changes per second on a simulated mobile CPU (Chrome DevTools 4x CPU Throttling):
| Metric | Recharts / Chart.js | Pure Reactive SVG (Next.js 15) | Delta |
|---|---|---|---|
| Initial JS Bundle Size | 284 kB minified | 0 kB (Native SVG) | -100% |
| Interaction to Next Paint (INP) | 114 ms | 16 ms | -86% |
| FPS During Continuous Slider Drag | 34 FPS | 60 FPS | +76% |
| Cumulative Layout Shift (CLS) | 0.042 (re-layout) | 0.000 | Zero CLS |
By relying on native SVG geometric primitives (viewBox, strokeLinecap="round", M ... A ...), the browser avoids layout thrashing and renders transitions at the native refresh rate.
Unit Testing SVG Invariants with Vitest
A common objection to hand-rolled SVG visualizers is maintainability. How do you verify that dynamic path strings do not generate NaN coordinates or broken arcs when edge-case numbers are entered?
We run deterministic unit tests using Vitest to assert SVG path geometry:
// tests/visualizers/heat-loss-donut.test.ts
import { describe, it, expect } from "vitest";
describe("HeatLossDonutVisualizer Trigonometric Invariants", () => {
it("should generate valid coordinate numbers without NaN for fractional loads", () => {
const breakdown = [
{ label: "Walls", btu: 12000, percentage: 40.5, color: "#00d2ff" },
{ label: "Windows", btu: 8000, percentage: 27.0, color: "#3b82f6" },
{ label: "Ceiling", btu: 5000, percentage: 16.9, color: "#10b981" },
{ label: "Infiltration", btu: 4600, percentage: 15.6, color: "#f59e0b" },
];
let cumulativePercentage = 0;
breakdown.forEach((item) => {
const startAngle = (cumulativePercentage / 100) * 360;
cumulativePercentage += item.percentage;
const endAngle = (cumulativePercentage / 100) * 360;
const startRad = ((startAngle - 90) * Math.PI) / 180;
const endRad = ((endAngle - 90) * Math.PI) / 180;
const x1 = 100 + 70 * Math.cos(startRad);
const y1 = 100 + 70 * Math.sin(startRad);
const x2 = 100 + 70 * Math.cos(endRad);
const y2 = 100 + 70 * Math.sin(endRad);
expect(Number.isNaN(x1)).toBe(false);
expect(Number.isNaN(y1)).toBe(false);
expect(Number.isNaN(x2)).toBe(false);
expect(Number.isNaN(y2)).toBe(false);
});
expect(Math.round(cumulativePercentage)).toBe(100);
});
});
Conclusion
Third-party charting libraries are fantastic for business dashboards with hundreds of data points and multi-axis toggles. But when building high-performance technical calculators, interactive tools, and domain-specific engineering applications:
- Drop the 250kB bundle weight.
- Embrace native SVG mathematical projections.
- Achieve sub-20ms INP and silky 60 FPS interactions.
You can explore all 21 open-access, zero-dependency engineering visualizers live in production across the HVACLogic Engineering Suite.
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.