UI mockups, dashboards, advanced interactivity, generative art, simulations, math visualizations, and design system rules for producing rich HTML widget output.
Prerequisite: Volume 1 (SVG diagrams, basic interactive widgets, Chart.js, Mermaid). This volume covers: UI mockups, dashboards, advanced interactivity, generative art, simulations, math visualizations, and the design system that ties everything together.
Every visual you produce should feel native to the host interface — not like an embedded iframe from somewhere else. These rules apply to ALL output types.
/* Backgrounds */
--color-background-primary /* white in light, near-black in dark */
--color-background-secondary /* surface cards */
--color-background-tertiary /* page background */
--color-background-info /* blue tint */
--color-background-danger /* red tint */
--color-background-success /* green tint */
--color-background-warning /* amber tint */
/* Text */
--color-text-primary /* main text */
--color-text-secondary /* muted / labels */
--color-text-tertiary /* hints / placeholders */
--color-text-info / -danger / -success / -warning
/* Borders */
--color-border-tertiary /* default: 0.15 alpha */
--color-border-secondary /* hover: 0.3 alpha */
--color-border-primary /* active: 0.4 alpha */
/* Typography */
--font-sans /* default body font */
--font-serif /* editorial / blockquote only */
--font-mono /* code */
/* Layout */
--border-radius-md /* 8px - most elements */
--border-radius-lg /* 12px - cards */
--border-radius-xl /* 16px - large containers */
Critical rule: Never hardcode colors like #333 or #fff in HTML.
They break in the opposite mode. Always use CSS variables.
code style for entity/class/function names.0.5px solid var(--color-border-tertiary)background: var(--color-background-primary),
border: 0.5px solid var(--color-border-tertiary),
border-radius: var(--border-radius-lg), padding: 1rem 1.25remAlways round displayed numbers. JavaScript float math leaks artifacts:
0.1 + 0.2 = 0.30000000000000004. Every number on screen must go through
Math.round(), .toFixed(n), or Intl.NumberFormat.
For when the user asks you to design or prototype a UI.
Contained mockups (mobile screens, modals, chat threads, single cards): Wrap in a background surface so they don't float naked:
<div style="background: var(--color-background-secondary);
border-radius: var(--border-radius-lg);
padding: 2rem; display: flex; justify-content: center;">
<!-- Your mockup inside -->
</div>
Full-width mockups (dashboards, settings pages, data tables): No wrapper needed — they naturally fill the viewport.
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 12px; margin-bottom: 1.5rem;">
<div style="background: var(--color-background-secondary);
border-radius: var(--border-radius-md); padding: 1rem;">
<div style="font-size: 13px; color: var(--color-text-secondary);
margin-bottom: 4px;">Total revenue</div>
<div style="font-size: 24px; font-weight: 500;">$142,800</div>
</div>
<div style="background: var(--color-background-secondary);
border-radius: var(--border-radius-md); padding: 1rem;">
<div style="font-size: 13px; color: var(--color-text-secondary);
margin-bottom: 4px;">Active users</div>
<div style="font-size: 24px; font-weight: 500;">8,421</div>
</div>
</div>
<div style="background: var(--color-background-primary);
border-radius: var(--border-radius-lg);
border: 0.5px solid var(--color-border-tertiary);
padding: 1rem 1.25rem;">
<div style="display: flex; align-items: center; gap: 12px;
margin-bottom: 16px;">
<!-- Avatar circle with initials -->
<div style="width: 44px; height: 44px; border-radius: 50%;
background: var(--color-background-info);
display: flex; align-items: center; justify-content: center;
font-weight: 500; font-size: 14px;
color: var(--color-text-info);">JD</div>
<div>
<p style="font-weight: 500; font-size: 15px; margin: 0;">Jane Doe</p>
<p style="font-size: 13px; color: var(--color-text-secondary);
margin: 0;">Lead Engineer</p>
</div>
</div>
<div style="border-top: 0.5px solid var(--color-border-tertiary);
padding-top: 12px;">
<table style="width: 100%; font-size: 13px;">
<tr>
<td style="color: var(--color-text-secondary); padding: 4px 0;">
Email</td>
<td style="text-align: right; padding: 4px 0;
color: var(--color-text-info);">[email protected]</td>
</tr>
</table>
</div>
</div>
<!-- Status badge -->
<span style="display: inline-block; font-size: 12px; padding: 4px 12px;
border-radius: var(--border-radius-md);
background: var(--color-background-success);
color: var(--color-text-success);">Active</span>
<!-- Featured accent (the ONLY case where 2px border is allowed) -->
<div style="border: 2px solid var(--color-border-info);
border-radius: var(--border-radius-lg);
padding: 1rem 1.25rem;">
<span style="font-size: 12px; padding: 4px 12px;
border-radius: var(--border-radius-md);
background: var(--color-background-info);
color: var(--color-text-info);">Most popular</span>
</div>
Inputs, selects, textareas, buttons, and range sliders are pre-styled in the host environment. Write bare tags — they inherit correct styling:
Never use <form> tags. Use onClick / onChange handlers directly.
For "help me choose between X and Y":
<div style="display: grid; grid-template-columns:
repeat(auto-fit, minmax(160px, 1fr)); gap: 12px;">
<div style="background: var(--color-background-primary);
border: 0.5px solid var(--color-border-tertiary);
border-radius: var(--border-radius-lg);
padding: 1rem 1.25rem;">
<h3 style="font-size: 16px; font-weight: 500; margin: 0 0 8px;">
Option A</h3>
<p style="font-size: 13px; color: var(--color-text-secondary);
margin: 0;">Description here</p>
</div>
<!-- Repeat for Option B, C... -->
</div>
For teaching physics, algorithms, or systems behavior with real-time updates.
Pattern: Animation Loop with Controls
<style>
.sim-controls {
display: flex; align-items: center; gap: 16px;
margin: 12px 0; font-size: 13px;
color: var(--color-text-secondary);
}
</style>
<canvas id="sim" style="width: 100%; height: 300px;
border-radius: var(--border-radius-md);
background: var(--color-background-secondary);"></canvas>
<div class="sim-controls">
<button onclick="toggleSim()">Play / Pause</button>
<label>Speed
<input type="range" min="1" max="10" value="5" id="speed"
oninput="simSpeed=+this.value">
</label>
<button onclick="resetSim()">Reset</button>
</div>
<script>
const canvas = document.getElementById('sim');
const ctx = canvas.getContext('2d');
let running = true, simSpeed = 5, animId;
function resizeCanvas() {
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
}
resizeCanvas();
// State
let particles = [];
function init() {
particles = Array.from({length: 50}, () => ({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
vx: (Math.random() - 0.5) * 2,
vy: (Math.random() - 0.5) * 2
}));
}
function step() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const p of particles) {
p.x += p.vx * simSpeed * 0.2;
p.y += p.vy * simSpeed * 0.2;
if (p.x < 0 || p.x > canvas.width) p.vx *= -1;
if (p.y < 0 || p.y > canvas.height) p.vy *= -1;
ctx.beginPath();
ctx.arc(p.x, p.y, 4, 0, Math.PI * 2);
ctx.fillStyle = '#534AB7';
ctx.fill();
}
if (running) animId = requestAnimationFrame(step);
}
function toggleSim() { running = !running; if (running) step(); }
function resetSim() { init(); if (!running) { running = true; step(); } }
init();
step();
</script>
For plotting functions, showing geometric relationships, or exploring equations.
Pattern: Function Plotter with SVG
<svg id="plot" width="100%" viewBox="0 0 680 400">
<!-- Grid -->
<line x1="60" y1="200" x2="640" y2="200"
stroke="var(--color-border-tertiary)" stroke-width="0.5"/>
<line x1="340" y1="20" x2="340" y2="380"
stroke="var(--color-border-tertiary)" stroke-width="0.5"/>
<!-- Axes labels -->
<text x="645" y="196" font-size="12"
fill="var(--color-text-tertiary)">x</text>
<text x="345" y="16" font-size="12"
fill="var(--color-text-tertiary)">y</text>
<!-- Function path drawn by JS -->
<path id="fn-path" fill="none" stroke="#534AB7" stroke-width="2"/>
</svg>
<div style="display:flex;gap:16px;align-items:center;margin:12px 0;
font-size:13px;color:var(--color-text-secondary)">
<label>f(x) = sin(
<input type="number" id="freq" value="1" min="0.1" max="10" step="0.1"
style="width:60px" oninput="plotFn()">x)
</label>
<label>Amplitude
<input type="range" id="amp" min="0.1" max="3" value="1" step="0.1"
style="flex:1" oninput="plotFn()">
</label>
</div>
<script>
function plotFn() {
const freq = +document.getElementById('freq').value;
const amp = +document.getElementById('amp').value;
const xMin = -5, xMax = 5, yMin = -3, yMax = 3;
const toSvgX = x => 60 + (x - xMin) / (xMax - xMin) * 580;
const toSvgY = y => 20 + (yMax - y) / (yMax - yMin) * 360;
let d = '';
for (let px = 0; px <= 580; px++) {
const x = xMin + px / 580 * (xMax - xMin);
const y = amp * Math.sin(freq * x);
d += (px === 0 ? 'M' : 'L') + toSvgX(x).toFixed(1)
+ ' ' + toSvgY(y).toFixed(1);
}
document.getElementById('fn-path').setAttribute('d', d);
}
plotFn();
</script>
<style>
.data-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.data-table th {
text-align: left; padding: 8px 12px; font-weight: 500;
border-bottom: 0.5px solid var(--color-border-secondary);
color: var(--color-text-secondary); cursor: pointer;
user-select: none; font-size: 12px;
}
.data-table th:hover { color: var(--color-text-primary); }
.data-table td {
padding: 8px 12px;
border-bottom: 0.5px solid var(--color-border-tertiary);
}
</style>
<input type="text" placeholder="Filter..."
oninput="filterTable(this.value)"
style="width: 100%; margin-bottom: 12px;">
<table class="data-table" id="table">
<thead>
<tr>
<th onclick="sortTable(0)">Name</th>
<th onclick="sortTable(1)">Value</th>
<th onclick="sortTable(2)">Status</th>
</tr>
</thead>
<tbody id="tbody">
<!-- Rows populated by JS -->
</tbody>
</table>
<script>
const data = [
['Alpha', 42, 'Active'],
['Beta', 18, 'Paused'],
['Gamma', 91, 'Active'],
];
let sortCol = -1, sortAsc = true;
function render(rows) {
document.getElementById('tbody').innerHTML = rows.map(r =>
`<tr><td>${r[0]}</td><td>${r[1]}</td>
<td><span style="font-size:12px;padding:2px 10px;
border-radius:var(--border-radius-md);
background:var(--color-background-${r[2]==='Active'?'success':'warning'});
color:var(--color-text-${r[2]==='Active'?'success':'warning'})">${r[2]}</span>
</td></tr>`
).join('');
}
function sortTable(col) {
sortAsc = sortCol === col ? !sortAsc : true;
sortCol = col;
data.sort((a, b) => {
if (a[col] < b[col]) return sortAsc ? -1 : 1;
if (a[col] > b[col]) return sortAsc ? 1 : -1;
return 0;
});
render(data);
}
function filterTable(q) {
const low = q.toLowerCase();
render(data.filter(r => r.some(c => String(c).toLowerCase().includes(low))));
}
render(data);
</script>
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const textColor = isDark ? '#c2c0b6' : '#3d3d3a';
const gridColor = isDark ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.06)';
const tooltipBg = isDark ? '#2C2C2A' : '#fff';
Canvas cannot read CSS variables — always detect dark mode and use hardcoded hex values.
<div style="position: relative; width: 100%; height: 300px;">
<canvas id="chart"></canvas>
</div>
responsive: true, maintainAspectRatio: false.Disable Chart.js default legend and build HTML: