Skip to main content

Colophon

What this site is made of

Last updated September 9, 2026

What this site is made of, what it costs, and what we decided against. Versions come out of the lockfile rather than being typed here, so this page cannot claim a version the site is not running.

What it is built with

Ten packages are runtime dependencies, and three of those are the framework. Tailwind is in the table below because it produces every style on the site, but it is a build tool — none of it ships.

Runtime dependencies, their versions, and what each one does on this site
PackageVersionWhat it does here
next16.3.4The whole site. Server components, so most pages ship no component JavaScript at all. Every route is server-rendered per request rather than cached, which is the price of a per-request Content-Security-Policy nonce.
react19.2.4With react-dom at the same version. The contact form is a server action, so it works before any JavaScript arrives and gets better after.
tailwindcss4.3.0Every style. The scale lives in one @theme block — see below. CSS is inlined into the HTML, so there is no stylesheet request blocking the first paint.
framer-motion12.38.0Scroll reveals below the fold, and nothing above it. Loaded as domAnimation rather than domMax, which is roughly half the size and the reason the nav underline is a native view transition instead.
lenis1.3.23Smooth scrolling. Switched off entirely when the visitor asks for reduced motion, which also hands scrolling back to the browser.
@base-ui/react1.4.1One component: the mobile menu. A dialog needs a focus trap, Escape, outside-click and the right ARIA — the hand-built version here got four of six right, which is the dangerous number.
zod4.4.3Contact form validation, on the server. The browser never sees it.
clsx + tailwind-merge2.1.1 + 3.5.0Composing class names so a later utility beats an earlier one instead of both landing in the DOM.
class-variance-authority0.7.1One component. It stays because it is honest about being a variant table; the buttons it used to be proposed for are plain strings in lib/button.ts instead.

There is no analytics package, no tag manager, no font service, no cookie banner and nothing to consent to. That is not a privacy posture bolted on afterwards — the page makes no third-party requests at all, and a test fails the build if one appears.

What runs it

Services this site depends on at runtime
ServiceForWhat happens if it is down
VercelHosting and the server functions behind every page.The site is down. There is no static fallback, because every response carries a fresh CSP nonce.
ResendDelivering the contact form to a mailbox.The form tells you it failed and gives you the email address directly, rather than pretending it sent.
Managed Redis, over HTTPCounting contact form submissions per address so the form cannot be used as a mail cannon.The limiter falls back to a per-instance counter, says so in the logs, and the message still goes through. Losing a real enquiry is worse than letting an extra one past.

Neither the mail service nor the rate limiter has a client library here. Both speak plain HTTP, so both are a fetch call. Adding two packages to make nine lines of code look tidier would be an odd thing to do on a site that argues about payload.

What came out

This is the more useful half of a colophon. Everything below was built, worked, and was removed anyway.

Things removed from this site, why, and what removing them cost
RemovedWhyWhat it cost
A WebGL hero object236 KB compressed, no device gate, and the headline could not paint until it rendered its first frame. Largest Contentful Paint measured 9.8 seconds on a throttled phone against a 2.5 second threshold.The hero has no moving object in it. The code is kept, with notes, rather than deleted.
A loading screenIt held a 2,500 millisecond minimum over a page the server had already delivered, and gated the headline behind five separate conditions.There is no branded entrance on a first visit. The page just arrives.
A rotating word in the headlineEvery longer word became a new largest paint, and the measurement only stops when you touch the page. It also meant the sentence describing the work changed while you read it.The headline says one thing.
tw-animate-cssImported in the stylesheet, used nowhere. The one animate- class on the site is Tailwind's own.1,797 bytes of CSS, 247 of them compressed.
A component library buttonIt was dead code while the exact class list it would have replaced was hand-copied seventeen times.Nothing. The classes moved to lib/button.ts, which is where they should have been.
Five described client projectsThey were not real.The work page now has this site on it and the numbers it can prove, which is a smaller claim and a checkable one.

Decisions that went the other way

GSAP was asked for and not used. The site already carries two things that move elements; a third animation runtime on a page whose measured problem was JavaScript-gated rendering would have made the number worse. If something specific needs ScrollTrigger later, that is the moment to revisit it.

Base UI was added on purpose, and it is the one dependency added rather than removed during this rebuild. Hand-building a modal is a rule worth keeping: the version it replaced moved focus correctly on open, locked scroll correctly, set aria-expanded correctly — and let five Tab presses walk a keyboard user into the page behind the overlay, with Escape doing nothing.

Structured data for a FAQ was considered and declined. The process and services pages read like questions and answers but are not; marking up prose as a Q&A because it would be eligible for a rich result is the kind of thing that is technically allowed and quietly dishonest.

Every page is server-rendered on demand rather than cached at the edge. A per-request nonce and a static file are mutually exclusive, and a strict Content-Security-Policy is worth more here than a cache hit on a site this size — the server answers in about 40 milliseconds.

The three-dimensional object was parked, not deleted. It sits in docs/parked with its dependency line, the two API changes that have landed since, and the three conditions any future home has to meet: it cannot block the headline from painting, it cannot ship to a phone without a device gate, and it cannot need a caption explaining what it does.

Where the decisions live

If you are reading this to work out how the site is put together, these are the files that matter.

The files that hold each part of the design system
FileHolds
app/globals.cssColour, type scale, tracking, radius and easing as theme tokens; the hero keyframes; one focus rule for the whole site.
docs/tokens.mdGenerated from the stylesheet above, including a count of the values that are still not on the scale.
lib/button.tsFour button sizes, with a 44 pixel floor on the tap target.
lib/field.tsEvery form field, label and error.
lib/metadata.tsTitles, descriptions and share images, per page.
lib/site-metrics.tsEvery number this site publishes about itself, each one next to the test that would fail if it stopped being true.

How to check any of this

The claims on this site are guarded by tests rather than by good intentions, because the tests are the only part that keeps working after everyone has stopped paying attention.

Test suites in this repository and what each one proves
SuiteProves
no-third-party.spec.tsNo request leaves this origin. Injecting one off-site script fails it by name.
a11y.spec.tsaxe-core against WCAG 2.0, 2.1 and 2.2 at A and AA, on every route, at three widths.
no-javascript.spec.tsEvery page renders, and the contact form submits, with JavaScript switched off.
largest-paint.spec.tsThe headline is the first thing eligible to be the largest paint on every page that has one.
zoom-and-contrast.spec.tsNo sideways scrolling at 400 percent zoom, and the primary button is still distinguishable in Windows High Contrast.
motion.spec.tsReduced motion is actually honoured, and the one animation between routes actually runs.
published-claims.spec.tsEvery number rendered on the work page is one this repository can back up.

Each suite also runs against the deployed site rather than a local copy, by pointing one environment variable at it. That matters more than it sounds: before this rebuild, every claim about the live site rested on a separate script that nobody ran.

What this page does not tell you

It is about the site, not the desk. There is no editor, keyboard or monitor list here, because that is not what anyone is trying to find out when they land on a studio's colophon.

The numbers this site publishes, and the conditions each one was measured under, are on the work page. What has been tested for accessibility, what passed, and what has not been looked at yet are on the accessibility page.

Questions about this page? Email info@gbtn.studio.