GodUIGodUI
85

Anatomy of Topographic Drift

How an 18px noise grid, a 16-case marching-squares switch, and a creeping z-offset redraw living contour lines every frame — then freeze under reduced motion.

TopographicDrift is not an SVG map you morph. Every frame it samples a value-noise field onto a coarse grid, connects isolines with marching squares, and nudges the noise's z-offset so the terrain slowly drifts. The canvas clears and redraws — there is no retained path geometry.

Sample the field

Corners sit on an ~18px lattice. Each corner stores one noise value:

tsx
 
field[j * stride + i] = valueNoise(
  i * cell * noiseScale,       // default noiseScale = 0.004
  j * cell * noiseScale + z,
);

lineCount (default 9) is how many elevation levels you stroke afterward — not how many grid cells you have.

Sample gridcell ≈ 18px · noiseScale 0.004

Each corner is valueNoise(i·cell·scale, j·cell·scale + z). Contour count is separate — lineCount levels get stroked later.

Grid
cell ≈ 18px sample spacing
Field
noiseScale = 0.004
Levels
lineCount default 9

The dots in the diagram are those sample corners. Darker / lighter is just noise amplitude so you can see the field before any lines are drawn.

Marching squares → isolines

For every cell and every level l / (lineCount + 1), the four corners become a 4-bit mask (tl|tr|br|bl). Mask 0 and 15 skip (all below / all above). Everything else picks edge midpoints by linear interpolation and strokes one or two segments — the classic 16-case table.

tsx
 
let id = 0;
if (tl > level) id |= 8;
if (tr > level) id |= 4;
if (br > level) id |= 2;
if (bl > level) id |= 1;
if (id === 0 || id === 15) continue;

const top = x + cell * ((level - tl) / (tr - tl || 1e-6));
// …right, bottom, left — then switch (id) { case 1: seg(…); … }

Stroke alpha peaks on mid-levels and falls off toward the extremes:

tsx
 
0.1 + 0.25 * (1 - Math.abs(0.5 - level) * 2)
Marching squares4-bit mask · 16 edge cases
one cell · bitmask
levels · mid alpha peak

Filled corners are above the level. The segment is the isoline — interpolated where the field crosses level on each edge.

Cases
16 configs · skip 0 and 15
Alpha
0.1 + 0.25×(1−|0.5−level|×2)

Drift is just z

The "living map" feeling is one line in the tick:

tsx
 
const tick = () => {
  z += 0.0015 * speed;
  draw(); // sampleField() + marching squares again
  rafId = requestAnimationFrame(tick);
};

Same lifecycle as the other canvas backgrounds: ResizeObserver rebuilds the grid, IntersectionObserver and visibilitychange pause offscreen / when the tab hides, and prefers-reduced-motion stops the loop on a still frame.

Driftz += 0.0015 × speed each frame

No path morphing — the tick advances z, sampleField() runs again, and marching squares redraw. Offscreen / hidden / reduced motion stop the loop.

z-offset
z += 0.0015 × speed
Lifecycle
IO · visibility · reduced freeze

Color comes from --foreground (or a color prop), re-probed when the document theme mutates — so light and dark both stay legible without a baked palette.

The result

Resultthe real component — drifting contours

Sample → march → nudge z. Contours without a mesh, motion without morphing paths.

On this page

Built with GodUI

Beautifully crafted motion components for modern interfaces.

Star on GitHub