Written and engineered by WPAgency Studio
The first four decisions
Before a single component existed, four decisions had to be settled — including one where the brief contradicted itself, and one where following the spec would have meant lying.
This site has a rule it inherited from WPAudio Engine: every decision should be inspectable, not just trusted. That rule is uncomfortable to apply to your own homepage, which is exactly why it is worth doing.
Four decisions were made before any component existed. Three were architectural. One was about honesty.
1. The brief contradicted itself, and the reasoning won
A bootstrap script had scaffolded a monorepo — apps/website, packages/ui,
packages/config. The blueprint’s technical architecture section reached the
opposite conclusion and said so directly: Turborepo is “not needed at launch,
would add complexity a single Astro app doesn’t have yet.”
Both were in the repository. Every import path in the project would inherit from whichever won.
We went with the single app, and deleted the empty package directories rather
than leaving them. An empty packages/ui is worse than no directory at all — it
tells the next reader that shared packages exist, and they will spend ten
minutes finding out they don’t.
The migration seam is still open. A monorepo earns its cost when a second real
app appears. At that point this becomes apps/website/ and shared code gets
extracted. That is a reorganisation, not a rewrite.
2. Tokens live once, so the config file the blueprint asked for doesn’t exist
The blueprint’s folder structure lists tailwind.config.ts. It also explains
why it expected that file: so that tokens would be
the single source of truth rather than living twice (once in
tailwind.config, once in raw CSS for the R3F/canvas contexts that can’t consume Tailwind classes).
That paragraph describes a Tailwind v3 workaround — author tokens as CSS custom properties, then re-declare them in JavaScript so utilities can be generated from them. The tokens still live twice. The second copy is just kept in sync by hand.
Tailwind v4 removes the need for the workaround entirely. One @theme block
emits the custom property and generates the utility from the same declaration.
So the file the blueprint listed does not exist, in service of the principle the blueprint stated. When a document’s letter and its reasoning disagree, the reasoning wins.
3. The colour system had to survive being nested
Accents on this site are project-scoped. Studio chrome stays neutral; WPAudio Engine’s
cyan appears where WPAudio Engine does, Wings & Prayers’ amber where it does. One
component reads a generic --accent and takes its colour from context, rather
than existing three times.
The obvious implementation fails silently, which is the worst way for anything to fail.
A normal @theme block emits its tokens at :root. That means:
:root { --color-accent: var(--accent); }
computes once, against the root’s value. Descendants inherit the frozen
result. A nested [data-zone="wpaudio"] redefining --accent has no effect —
and nothing about the CSS looks wrong. The colour is simply always the default,
forever, and review will not catch it because there is nothing to catch.
The fix is one keyword, @theme inline, which compiles the utility down to
color: var(--accent) so substitution happens at the element instead of the
root. It is now the subject of its own decision record, specifically so nobody
tidies it away.
4. Following the spec would have meant inventing things
The blueprint specifies a Wings & Prayers storybook page — “presented as an experience, not a PDF download link” — and a music page linking out “via a DistroKid-powered smart link to primary streaming platforms.”
Reading the actual repository: there is no storybook. There is a complete read-aloud fairy tale script, unrecorded. There is no album on any streaming service. There are five songs with finished lyrics, BPMs, arrangement notes and a stated emotional arc — and zero recordings. No distributor is named anywhere in the source. Two source documents disagree with each other about whether a single has been released.
Building those pages as specified would have meant fabricating streaming links.
The blueprint has a rule that outranks its own module list: do not invent
content; the website reflects the repositories. So shipping status became a
required schema field rather than something an author remembers to mention.
Four values — shipped, in progress, written, planned — and a required
whatExists line stating in plain language what a visitor would find today. A
missing status fails the build.
The album is on this site, with its track listing and its lyrics, labelled written, not yet produced. That is a better story than a streaming widget would have been. A finished album bible with no recordings is genuinely interesting; the same thing presented ambiguously is just misleading.
What this cost
Roughly an afternoon, and it produced no visible interface at all. What it produced instead: a contrast table that is unit-tested against the real token file rather than asserted in a comment, a build that fails when content claims something the repositories do not support, and four decision records explaining why the code looks the way it does.
The next person to open this repository — including a version of us that has forgotten all of it — starts from documentation instead of archaeology.