Passionfruit Design

Colophon

How this site is built. It follows the same rules as the work I do for clients.

Words are data

Every word on this site lives in a few JSON files. The server checks them when it starts and refuses to run if anything is missing.

The same content is published as JSON, so you can read the whole site as data.

Made on the server

One small Node process using Express builds each page and sends it complete. There is no framework, no bundler and no build step.

It has two runtime dependencies: Express, and Nodemailer for the contact form. Everything else is a few lines written for the job.

The page works with JavaScript turned off. A few lines of JavaScript make the contact form reply without reloading the page. That is all it does.

Locked down

The server sets a strict content security policy. The browser may load nothing from anywhere but this domain, so third-party requests are impossible, not just absent.

Other headers stop the site being framed, stop the browser guessing file types, send no referrer and turn off every browser feature the site does not use.

The contact form checks where it was sent from, limits how often one address can use it and catches bots without a CAPTCHA.

Hosted on a small box

The app runs under pm2 on a Linux VPS it shares with other production apps. nginx sits in front of it and handles TLS with a Let's Encrypt certificate.

GitHub Actions lints and tests every change, checks accessibility, page weight and Lighthouse scores, then deploys. Nothing is built on the server.

Type and colour

The type is your device's own system font, so there is nothing to download. The colours come from the fruit: aubergine skin, yellow pulp, pale pith. Every pairing passes WCAG 2.2 AA contrast.