A city of code, painted in real time.
xity.dev is a developer portal where documentation is not a static artifact but a living surface. Every section you read summons its own generative algorithm to the canvas on the right — particles, tessellations, flow fields, recursive trees, automata.
The aesthetic borrows from creative coding (Processing, p5.js, shadertoy), the diagrammatic precision of circuit-board trace routing, and the clean austerity of early NeXT computer interfaces. The codebase paints on the screen as you read it.
This first section is paired with Particle
Constellation — 200 nodes drifting through the canvas,
connected when proximate, forming an ever-shifting graph of
relationships. It is what every dependency tree wishes it
looked like.
Tessellation as architecture.
The second neighborhood of the city is a Voronoi diagram — thirty-eight seed points partitioning the plane into cells whose boundaries are equidistant from their nearest neighbors. As you scroll, the seeds drift; as the seeds drift, the boundaries recompute. The cell nearest the viewport center is illuminated.
// each cell = one closest seed
for (const px of pixels) {
let nearest = seeds[0];
for (const s of seeds) {
if (dist(px, s) < dist(px, nearest)) {
nearest = s;
}
}
paint(px, nearest.color);
}
The naive O(n·m) algorithm is replaced here with a spatial-hash sweep — a tradeoff of memory for the smoothness of motion. The result is structural without being rigid, ordered without being grid-like.
Perlin noise as a field of intent.
Flow fields turn a scalar noise function into a vector field — every point on the canvas is assigned a direction, and short line segments trace the lines of force. The output looks like wind through a wheat field, or iron filings around a hidden magnet.
Five hundred segments are rendered in #8A9BB0
at low opacity; ten "tracers" in Signal Blue follow the field in
real time, leaving short comet trails. Together they describe a
terrain that is invisible until something moves through it.
const angle = noise(x * 0.005, y * 0.005, t) * TAU * 2;
const vec = { dx: cos(angle), dy: sin(angle) };
Recursion, photosynthesised.
An L-system grows from the bottom of the canvas. The recursion depth is governed by your scroll position — the further you read, the deeper the branching, the denser the canopy. Branch angles wobble with a tiny stochastic offset so no two renders are identical.
Branches are drawn in Trace Green; leaf nodes appear at the terminal segments as 3px circles in Warning Amber. The tree is not an illustration of a tree — it is a small, deterministic program that happens to look like one.
function branch(x, y, len, angle, depth) {
if (depth === 0 || len < 2) {
leaf(x, y);
return;
}
const x2 = x + cos(angle) * len;
const y2 = y + sin(angle) * len;
line(x, y, x2, y2);
branch(x2, y2, len * 0.72, angle - 0.42, depth - 1);
branch(x2, y2, len * 0.72, angle + 0.42, depth - 1);
}
A two-state universe, accreting downward.
The final algorithm is a 1D elementary cellular automaton — Wolfram's Rule 110 — rendered as a tapestry that grows downward, one row per scroll event. Rule 110 is Turing-complete; in principle this little tile of pixels can compute anything that any computer can compute. In practice, it makes triangles.
Every horizontal rule between sections of this document is its own four-pixel-tall automaton, each running a different rule number — 30, 90, 110, 150, 184 — so the same primitive renders a different micro-pattern each time you cross a boundary.
const RULE = 110;
function next(prev) {
const out = new Uint8Array(prev.length);
for (let i = 1; i < prev.length - 1; i++) {
const idx = (prev[i-1] << 2) | (prev[i] << 1) | prev[i+1];
out[i] = (RULE >> idx) & 1;
}
return out;
}
Five algorithms, one canvas, one document. The visual is the margin annotation. The text is the program comment. The site is the city.