Colophon
What is a colophon?
In the world of print, a colophon was a note at the back of a book listing the typefaces, paper, and printing press used. On the web, it has become an indulgence I love: a peek behind the curtain at the tools and decisions that shape a site, and a sign of a kind of pride of the details in one’s craft that I admire and share.
The logo
The original “The Office of Greg Turner” logo was designed by Pat Armstrong. I took Pat’s Illustrator design and stuffed it with animated gadgets rendered in Canvas2D and WebGL. Each widget runs its own animation loop, driven by simplex noise or physics simulations, and responds to the site’s colour scheme in real time. Some highlights:
- “The” — a WebGL2 fragment shader applies a BadTV distortion effect (scanlines, RGB channel splitting, and simplex noise warping) over the word, making it look like it is being displayed on a dodgy CRT monitor. The shader is based on Felix Turner’s original BadTV shader for Three.js.
- The moiré discs — two overlapping line-pattern layers clipped to a circle, based on some laser-cut coasters I own. The patterns are randomly chosen from a catalogue of thirteen designs on each page load, inspired by laser-cut coaster patterns.
- The particle field — a swarm of dots cycling through four behaviour modes: Boids flocking, Vortex, Orbit, and Phyllotaxis. Click it to cycle the mode.
- The network — an isometric grid of cubes (solid and outlined) connected by dashed line segments. The view auto-rotates slowly, wobbles in response to mouse movement, and snaps back to its default angle when idle. Clicking shuffles the cubes into adjacent cells and re-rolls the connections.
All of these animations are written in TypeScript and bundled with webpack.
The colour system
One of the more idiosyncratic features of this site is its rotating colour scheme. Each day at midnight your time, the site picks a new palette from a curated set using OKLCH (colour space for perceptually uniform transformations). These colours apply in realtime to the CSS, the SVG, and the canvas elements which all took quite a bit of hand-tweaking. You can also cycle through schemes by clicking the leaves on the plant in the logo. It is entirely unnecessary, mildly self-indulgent, and exactly the kind of thing my brain wants this site to have.
The backend: Django and Wagtail
This site is built on Django, the Python web framework that has been my trusty companion for two decades now. This site’s been through hand-coded static HTML, Hugo and I think maybe a Flask version, but I keep coming back to my boo.
For content management on Django, I pretty much always choose Wagtail. It gives me a decent editing experience without fighting the restrictions of a single rich text editor. Wagtail’s StreamField system lets me compose pages from reusable blocks (rich text, markdown, images, slideshows) while keeping the data model clean and the templates sane and maintainable.
This all runs on Python, managed with uv. A few Python libraries deserve a mention:
- wagtail-markdown — lets me write content in Markdown when rich text feels like overkill
- wagtail-metadata — handles the tedious but important but tedious business of OpenGraph and SEO meta tags
- coloraide — powers the site’s colour scheme system, doing colour space conversions between OKLCH, hex, and other formats
- smartypants — transforms straight quotes into curly quotes, hyphens into proper em dashes, and Picky Greg into Happy Greg.
- scour — optimises SVG files, keeping them lean.
Styling and typography
The styling is handled by Tailwind CSS (v4), which I have come to enjoy after an initial period of aesthetic horror at all the unconcealed utility classes. The typography uses from Tailwind’s excellent typography plugin, which makes prose content look good without custom CSS for every element (I’m not getting those 20 years back).
I chose the typefaces to highlight the warm Art Deco vacuum tube aesthetic of Pat’s logo, but leaning more towards readability and heart than period-correctness or pretension. They are Josefin Sans for headings, designed by Santiago Orozco and inspired by geometric sans-serif designs from the 1920s (with a nod to Futura and Kabel). Body text is set in Lora, a contemporary serif designed by Olga Karpushina and Alexei Vanyashin of Cyreal, with roots in calligraphy and optimised for screen reading. Both are served via Google Fonts.
Icons come from Font Awesome 5. I know, I know, an entire icon library for a handful of icons. It is on the list.
Infrastructure
My development environment is orchestrated by mise, which manages Python versions, Node.js versions, and provides a decent task runner. I pretty much add mise to every project I work on now.
The site runs on Fly.io, deployed in Docker containers. Fly’s tooling is just enough for me. The deployment pipeline is just a single command from a mise task.
The database is PostgreSQL, because of course it is. For static assets, WhiteNoise serves them in production, and media files live on Backblaze B2.
Code quality is maintained by a solid lineup:
- ruff for general linting and formatting
- djlint to keep Django templates tidy
- mypy for type checking that catches bugs before they hatch
- pytest with pytest-django for testing
- pre-commit to runs all this automatically so I can’t forget
- ESLint and Prettier for TypeScript hygiene
One more thing: I use Cursor as my IDE, which you might know means I vibrationally-coded some of the features of this site in order to make it nicer to visit and to use. I have made previous versions of this site entirely by hand, and my perfectionism gets in the way and I end up disappointed. At the time of writing I feel like this result is still hand-made by me as an expression of me, and something to be proud of—at least enough to write a colophon this time!