Most websites have a few decorative shapes somewhere: a texture behind the hero, some lines under a heading, a pattern in the footer. They are rarely anyone's priority. They arrive as a stock download or a one-off export from a design tool, and when the layout changes, nobody can make another one that matches.

I wanted those shapes to behave like the rest of a build: generated from rules, kept in the repo and easy to make again. So I built a pattern toolkit. Then, to find out whether it held up, I built a whole site around it.

What the toolkit is

It is one HTML file. It opens by double-click in any browser, with no server, no build step and no network requests. That was deliberate: it is a working tool I open in the middle of a build, and I didn't want it to depend on anything that could break or disappear.

Each kind of pattern is a generator, and each generator is a tab. There are seven so far:

Generator What it draws On Datum
ContoursTopographic lines traced from a noise fieldYes
Dither1-bit ordered ditherYes
HairlinesFine parallel or radiating linesYes
GrainA texture overlayYes
CellsSquares on a grid with circles and curved connectorsRebuilt
DotsDot fields, halftone, scatter with falloffNo
BlobsSmooth organic shapesNo
The toolkit's generators at v0.2, and which ones the Datum site uses Scroll horizontally to compare

Each generator has five to eight controls and no colour pickers. Colour comes from the client's palette, not from whatever looked nice on the day.

Same seed, same pattern

The rule everything rests on is that a pattern is deterministic. The same seed, settings and size always give exactly the same drawing. The randomness comes from a small seeded number generator, never from the browser's own, so "randomise" really means "try another seed", and any seed I like can be written down and drawn again.

Redrawing with the seed unlocked, then locked

That is what makes the patterns maintainable. When I save one, the toolkit records which generator drew it, the seed, the size and every setting. If the hero gets taller six months later, I redraw the same pattern at the new size instead of hunting for an old file.

One preset per client

Each client gets a preset: a small JSON file in their repo that holds their palette, stroke weights, grid unit and motion timing, plus every pattern saved for their site. The palette has five named slots: ink, accent, a second accent, muted and paper.

Generators pick colours by slot name, never by hex value. When the preset maps those slots to the site's CSS variables, the exported patterns use the variables too, so they follow the site's theme, dark mode included, without being redrawn.

Variety comes from the seed. Consistency comes from the preset.

Code the client owns

The main export is an Astro component. The generator runs inside the component when the site is built, so the page gets plain inline SVG and ships no JavaScript for it. Every setting becomes a typed prop with its range written beside it, and the defaults are whatever was on screen when I exported. Dropping in the component with no props reproduces exactly what I designed.

---
import PatternCellsHomeHero from '../components/patterns/PatternCellsHomeHero.astro';
---
<section class="hero">
  <PatternCellsHomeHero seed={777} opacity={0.6} align="top right" />
  <div class="hero__content">…</div>
</section>

The component has no imports and no dependencies. It works in any Astro project, and it belongs to the client: there is no hosted service, licence or library to keep paying for. The same pattern can also leave the toolkit as a standalone SVG, a CSS snippet for a background image, or a PNG for a presentation. Animated patterns stand still for anyone who has asked their device for reduced motion.

Testing it on Datum

A toolkit is easy to like on its own. The real question is whether it holds up across a whole site with a strong idea behind it. So I built Datum.

Datum is a fictional architecture studio that builds in impossible places: a sea cliff in the Faroe Islands, an Antarctic ice shelf, a high plateau in Chile, a knife-edge ridge on Mont Blanc. It is a portfolio piece, not a real practice. Its idea comes from surveying, where the datum is the reference every height is measured from. Every building begins with its ground.

That gave the patterns a job. Each project's seed is its latitude and longitude, rounded to four decimal places (about 11 metres) and hashed. Nothing else feeds it. Each project's contours are the signature of that piece of ground, and the same coordinates always draw the same land. The logo never changes; the ground under it does.

Each pattern has one job. The contours carry identity: every project's hero, its card on the work page, the link to the next project and its share image. The dither handles arrival: every render rests on a tiny 1-bit version of itself, made at build time, until the full image loads. The hairlines are the measuring marks around key images (crop corners, dimension lines, a scale bar, a north point), and the grain sits over the whole page so flat colour reads as paper.

What changed when it met a real site

The generators moved into the site's code. Every generator is a pure function that returns a string, with no browser code inside. That meant I could lift the contours, the noise field and the seeding straight into Datum as plain TypeScript and run them at build time from each project's own file. I wrote that rule with exported components in mind. It turned out to matter more for this.

Cells became something else. The toolkit's Cells generator draws grid squares joined by circles. Datum needed building skins: a perforated screen for each project's facade. So I grew a new version from the same seeds. Each screen is cut into irregular cells, and each opening is sized by the height of the ground it stands over. On the cliff house the screen opens towards the sea, where the ground falls away. On the ice station, where the ground is almost flat, it stays almost closed.

Two generators stayed out. Dots and blobs are useful elsewhere, but they had no job on a site about measured ground. A toolkit with seven generators doesn't mean a site should use seven.

Striking, and still fast

Decoration is often where a site's weight hides: large background images, animation libraries, canvas scripts. Because these patterns are drawn into inline SVG when the site is built, most of them cost a few kilobytes of markup and no JavaScript at all. Only the parts that react to the visitor run pattern code in the browser.

Datum is built to a strict mobile budget: the main image in under 1.5 seconds on 4G, no layout shift, under 40 KB of JavaScript on a project page, and 95 or above on all four Lighthouse scores. The Lab page sets out the full stack and the budget, and what came from the toolkit.

What it means for client work

On a client build, the toolkit gives a site its own set of shapes, made for its palette, with no stock texture in sight. The patterns live in the client's repo as ordinary code. They can be redrawn at a new size, recoloured by changing the palette or replaced with a new seed, and none of it depends on me or on a service staying online.

Datum shows how far the idea stretches when a site has a strong thesis. Most client sites need far less: a texture, a hero shape, a few lines that belong to them. The approach is the same either way. Write down the rules, draw from a seed, and keep the result where the client can find it.