feat(home): phase 3 — the homepage #6
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/phase-3-homepage"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Phase 3 of
PLAN.md§13. Replaces phase 1's scaffold with the real homepage: hero, the data path as inline SVG, the self-hosted argument, all five capability groups, the get-started CTA, and the reserved demo slot.Branched from
mainafter phase 2 (#5) merged.The three decisions, taken before any of it was written
Recorded in
PLAN.md§10 as D17–D19.D17 — the data path is drawn generically, and captioned specifically. The nodes read "your game server", "sidecar", "Runic Gateway", "browser and app", because §10 says a reader should not need to know this org's repository layout to understand the picture. It does not hide what ships: the sub-labels and the caption name ServUO and uo-link outright, since there is exactly one implementation of the shape today.
D18 — all five groups on the homepage, named only. Not three with a link out: Integration and Infrastructure carry the module and self-hosted arguments, and hiding them until phase 4 would make the front page look smaller than the product. The per-capability argument stays
/features/'s job, so there is one copy of it.D19 — the hero leads with the emblem rather than type alone. It costs what D16 already accepted — raster art a mounted
theme.csscannot recolour — but every size is derived from whicheverlogo.pngis in force (D14), so the hero, header, tab icon and installed icon still change together from one file.The capability list is now checked end to end
src/data/capabilities.mjsholds the five groups as data, and every Game-intelligence item names themodule-uocapability slug it comes from. The build fails if the page andplatform.jsondisagree in either direction — an unlisted slug means the site is under-selling, an unknown one means it is advertising something that is gone (§1).Closing that loop needed a fifteenth fact in
checkFacts.mjs. §12 names the capability list as an externally-sourced fact and nothing re-read it, so the whole chain rested on someone remembering. It is nowModule-uomain:module.json→capabilities, sorted before comparing, so a reordered manifest is not a failure but an added or removed slug is.It immediately found something: the site was omitting two of the module's eight capabilities.
guildsandgovernorswere absent from §10's grouping. Both are real and documented (shard_guilds,shard_governors,shard_governor_terms), so they are now on the page and inPLAN.md.Two defects found by standing the build up, not by reading it
The demo slot's markup contract had no guard.
applyBrand.mjsreveals the demo link by replacing an exact pair of empty attributes in built HTML. An attribute inserted between them, orhrefwritten second, produces a build where the mount sets a demo URL, the boot log says nothing, and the link is simply never there.checkBrand.mjsnow checks both halves — the slot exists, and nothing writesdata-demo-urloutside the exact pair — and derives the literal from the same expressionapplyBrand.mjsuses, so the two cannot drift.The header nav overflowed on every phone. Rendering the homepage in a 390px frame measured
scrollWidth433 against a 390px viewport: four links plus the lockup do not fit, so the whole page scrolled horizontally. This is pre-existing from phase 1, whose own comment inglobal.csssays "the nav collapses to the docs link alone until phase 3 gives it a real disclosure control" — so it is phase 3's by assignment, not scope creep. It got a wrap rather than a disclosure, deliberately: with four links there is nothing to disclose, and a hamburger costs state, script and duplicate markup for no gain. The lockup keeps the first row, the links take the second, and it stays four keyboard stops. Flagging the deviation rather than making it quietly.Things worth a second opinion
aria-hidden. Not because it is decorative — it is the opposite — but because the four numbered steps beside it carry the same path in prose at real font sizes. Arole="img"with a<desc>would make a screen reader read the path twice, and the second telling would be the worse one. The consequence is a rule: the diagram must never gain a fact the list does not have./docs/, not at a page inside the journey. The marketing routes are written in their final form (/features/,/modules/,/integrations/) and 404 until phases 4–6, which is what the header and footer have done since phase 1 and costs nothing given nothing deploys until phase 12. Documentation slugs are different — phases 7 and 8 own them, and a guessed one would be a stale URL nothing checks.astro checkreports one pre-existing hint, an unusedstatSyncimport inscripts/applyBrand.mjsfrom phase 2. One word, in a file this PR does not otherwise touch — say the word and it goes in, otherwise it can ride with phase 10.Verification
Every new check was negative-tested before being trusted, as in phases 1 and 2:
pets) and with one the module dropped (cliloc) — both throw, with the right messageplatform.jsonedited to claim a ninth capability —FAIL, naming both sidesThen, on a clean checkout of this commit (
git archive HEAD,npm ci, not the working tree):checkTokens22 files ·checkBrand19/brand/URLs ·checkFacts15 facts ·astro check0 errors · production build/and/docs/200; every hero derivative resolves (X-Brand-Source: derived:default)And in a real browser at 1440px and in a 390px frame: no horizontal overflow at either, the long group takes both remaining slots on the top row so the five-group grid has no hole, and the diagram, cards and header all stack.
🤖 Generated with Claude Code
https://claude.ai/code/session_01WnDSWzpUjw8t8C2hghysNz
Replaces phase 1's scaffold with the real homepage: hero, the data path as inline SVG, the self-hosted argument, all five capability groups, and the get-started CTA. Three decisions the org lead took first are recorded in PLAN.md as D17-D19. The data path is drawn generically and captioned specifically (D17): the nodes say "your game server" and "sidecar", the sub-labels and caption name ServUO and uo-link. The SVG is aria-hidden because the four numbered steps beside it carry the same path in prose — one telling, not two. The capability list is data with a check behind it (D18). Every Game-intelligence item names the module-uo capability slug it comes from, and the build fails if the page and platform.json disagree either way. That needed a fifteenth fact in checkFacts.mjs: §12 named the capability list as an externally-sourced fact and nothing re-read it, so the chain rested on someone remembering. It also found that the site was omitting two of the module's eight capabilities — guilds and city governors are now listed, in the page and in §10. The hero leads with the emblem (D19), derived from whichever logo.png is in force so one file still changes the hero, header, tab icon and app icon together. Also here, both found by standing the build up rather than by review: - checkBrand.mjs now enforces the demo slot's markup contract. applyBrand.mjs reveals the demo link by replacing an exact pair of empty attributes; an attribute inserted between them produces a build where the mount sets a demo URL, the boot log says nothing and the link never appears. Both halves are checked and the literal is derived from the expression applyBrand.mjs uses, so they cannot drift. - The header nav overflowed at 390px — four links plus the lockup measured 433px against a 390px viewport, so every phone got a horizontally scrolling page. Phase 1 left this to phase 3 expecting a disclosure control; it got a wrap instead, because with four links there is nothing to disclose and a hamburger costs state, script and duplicate markup. Verified on a clean checkout of this commit: all four checks, astro check, a production build, a live /brand/* smoke, and a demo URL mounted and reverted. Co-Authored-By: Claude <noreply@anthropic.com>