Commit 7a49174
Add game engine landing page (#25)
* Add game engine landing page
* Fix review findings: contrast, mobile headline, landmarks, diagram label
Two accessibility defects, one contrast failure, one typography regression at
320px, and four smaller items from the spec review.
Landmarks: header and footer sat inside <main>, which strips their banner and
contentinfo roles -- those apply only when not nested in main. Both moved out.
Diagram text alternative: aria-label was on a bare <div>, whose implicit role is
generic, so the description was announced by nothing. Added role="group", hid
the decorative relationship words from assistive technology, and made the kind
branches a real list.
Contrast: --landing-border-strong was rgba(255,255,255,0.24), which composites
to rgb(68,69,71) over #090a0d for 2.06:1 -- under the 3:1 minimum for the
meaning-bearing borders it exists to serve. Raised to 0.35 (3.14:1); computed
that 0.34 is the floor.
Mobile headline: the clamp floor of 3.6rem rendered the hero as one word per
line at 320px -- six lines. It never overflowed, so it passed the letter of the
320px rule while losing the composed line. Floor dropped to 2.1rem and the
deliberate <br> is now suppressed below the mobile breakpoint, so the break is
an enhancement rather than a fixture. Verified in a browser: three lines at
320px, the composed two at 1280px, zero horizontal overflow at both.
Also: refusals and capabilities no longer render as matched ledgers, since two
identical blocks read as one and cancel the contrast the pairing exists for;
Campaigns links to content-packs rather than vision, which was a semantic
mismatch; documentation links navigate in place instead of each opening a tab,
with the repository link keeping target=_blank and announcing it; the ledger
index uses padStart rather than a hardcoded zero; and one duplicated noun run
was trimmed.
Route inventory gains content-packs and clients, both valid routes it had
simply omitted -- it is the only check on these cross-site links.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Add the motion pass and reconcile AGENTS.md
Motion (Phase 5), which had never been implemented -- the page shipped with no
animation at all. Everything added here is additive: delete css/motion.css and
the page is unchanged in content, only in timing.
Reveal safety is the design constraint, not an afterthought. Content is visible
by default; the hiding rule is scoped to .js-reveal, which the hook adds only
once an IntersectionObserver actually exists. So the page reads when JavaScript
never runs, throws early, or the browser lacks the API. Two further guards:
elements already in view are revealed on the observer's first callback, and a
three-second failsafe reveals everything regardless, so a bailed-out observer
costs a delay rather than a blank section.
The hero deliberately does not stagger its headline. The page is client-rendered
and already starts blank waiting for the bundle; animating the eyebrow, headline
and ellipsis on top of that would put over a second of nothing in front of the
most important words. Only the signature and scroll invitation stagger, because
their timing is the joke.
Reduced motion neutralises reveals at the source -- opacity 1, no transform, no
transition -- rather than shortening them, so nothing waits on an intersection
event. Hover and focus states survive, since they carry state rather than
motion.
Also restores the signature easter egg, desktop-only and deliberately so: touch
has no hover, and making a decorative line focusable would add a tab stop that
announces nothing. Both variants share one grid cell, so the swap costs no
layout shift, and the alternate is absent from layout entirely on mobile.
AGENTS.md was a copy of CLAUDE.md with one assistant's name mechanically
replaced by another's, which rewrote nine real references into paths and
packages that do not exist -- ~/.Codex/skills/graphify/, npx Codex-mem doctor,
/Codex-mem:learn-codebase -- while leaving 14 KB free to drift from its source.
Replaced with a pointer to CLAUDE.md and agent.md. A duplicate that can disagree
with its original is the failure mode CLAUDE.md itself tracks.
Verified in a browser at 320px and 1280px: five reveal targets, hero paints
immediately, all five reduced-motion rules resolve, signature spans stack in one
cell, zero horizontal overflow.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Decide landing/docs routing, chain anchors through every section, tighten type and spacing
Three unrelated fixes, requested together.
Routing: the landing page is packaged to be served at "/", with the docs at
"/docs" on the same origin. That is a decision about path structure, not a full
hosting choice -- narrower than the "hosting: not decided" question this bundle
has deliberately left open twice already. So the six /docs/engine/... routes
and the docs index move from absolute cross-site URLs to root-relative paths.
Which host or platform serves the combined output, and how this project's
dist/ and the docs build get assembled into one deployable tree, remain open
and untouched -- docs/docusaurus.config.ts and docs/sidebar.ts are unchanged,
per instruction, since that build process is expected to be reworked and
wiring an assembly step against it now would be effort spent twice.
00-repository-reality.md and the bundle README are updated to state the split
plainly: routing decided, platform not.
Anchors: the hero's "Scroll. It escalates." was the only anchor on the page,
reaching exactly one section further -- origin, and no other section had an id
at all. Every section now has one, and a small "Continue" link at the end of
each (except the last) chains to the next, extending the hero's own device the
whole way down instead of leaving it as a one-off. Two sections use two-column
grids (contract, ledgers); the link goes inside the second column/article in
both so it doesn't become a stray third grid item.
Type and spacing: h1's clamp ceiling was 8.6rem (137.6px), h2's was 4.7rem
(75.2px) -- both cut roughly in half (5.5rem, 3rem) to match an editorial page
rather than a poster. Section padding-block ceiling dropped from 10rem to
6rem, hero padding from 8rem to 5rem, and every large margin-top/gap in
between (ledgers, architecture diagram, cta-actions, footer) scaled down by a
similar third to a half.
Verified in a browser: h1 88px / h2 46px at 1280px (was 137.6/75.2), zero
horizontal overflow at 320px, all ten section ids and eight Continue link
targets present and correctly chained (also asserted in a new test). Anchor
navigation itself was confirmed with a real dispatched click after synthetic
.click() calls misleadingly failed to scroll in this automation harness --
that turned out to be a property of the test tool, reproducing identically on
the pre-existing, untouched hero anchor, not a page defect.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Decide hosting: GitHub Pages, same domain as the docs
Corrects "Hosting platform: Not decided. Not GitHub Pages" across the bundle.
That reflected an instruction given earlier in this working session; a later
one in the same session confirmed GitHub Pages, so the documentation was
stating something already superseded.
This is not a new deployment target -- it is the existing one, now serving
both projects. docs-deploy.yml already deploys the docs site to GitHub Pages
at game-engine.subzerodev.com (docs/docusaurus.config.ts, .config/
DocumentationRules.psd1). Pages serves exactly one site per repository, so
"hosting = GitHub Pages" was never going to mean a second Pages site -- it
means this repo's one deployment, at this one domain, covering "/" (landing)
and "/docs" (documentation) together. That is exactly the shape the routing
decision from the previous commit already assumed, which is why settling the
platform changes nothing about the routes themselves.
Unblocked: the domain was the one fact standing between "wait on a hosting
decision" and a real canonical URL / Open Graph URL. Both are now set in
site/index.html (https://game-engine.subzerodev.com/) and enforced by
scripts/verify-build.mjs the same way the other social tags already are, so
a future edit that drops them fails the build rather than failing silently.
Still not built: the mechanism that merges this project's dist/ and the docs
site's own build output into the one artifact tree docs-deploy.yml uploads.
Neither docs/docusaurus.config.ts, docs/sidebar.ts nor docs-deploy.yml is
touched -- that stays deferred, not because the platform is unclear (it no
longer is), but because the docs build process is expected to be reworked,
and wiring an assembly step against a process about to change would be
effort spent twice.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Wire the landing page into the GitHub Pages deploy: build/Merge-LandingPage.ps1
Builds the assembly step that was the one remaining gap between "PR #25
merges" and "the site is actually live" -- landing at "/", docs at "/docs",
one GitHub Pages deployment.
The mechanism: docs-build.ps1 runs as before, unmodified; the landing page
(site/) builds independently; a new script, build/Merge-LandingPage.ps1,
overlays it onto the docs output -- overwriting only the docs build's
generated-from-README root index.html and adding the landing page's assets.
docs/docusaurus.config.ts and docs/sidebar.ts are untouched.
The collision question -- do the two builds' assets/ folders step on each
other -- was the one real unknown, and it was verified rather than assumed:
pulled ghcr.io/the-running-dev/docs-template, ran the actual docs build, and
inspected the real output. Docusaurus nests its bundle under assets/css/ and
assets/js/; Vite writes flat hashed files directly into assets/. They never
write the same path. The script also refuses to proceed if the merge changes
anything under the docs build's own docs/ subtree, as a second, mechanical
guard on top of the verified fact.
Wired into both docs-ci.yml's verify job -- so every PR builds and merges both
projects and proves the combined artifact, the same way it already proved the
docs-only build -- and docs-deploy.yml itself. Ran the full pipeline locally
end to end against the real container before pushing: real docs build, real
landing build, real merge, root index.html correctly becomes the landing page,
docs/engine/* unchanged, canonical and og:url URLs present in the merged
output.
Nothing here executes against the live site until this PR is reviewed and
merged -- docs-deploy.yml only triggers on push to main.
Updated plans/06-landing-page/00-repository-reality.md, its README, and
14-content-inventory.md to record the build-assembly step as built rather than
open, and agent.md with the verified collision fact and the pending change to
what "/" serves once this merges.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Address PR review: enable strict TS, explicit ReactNode import, enforce site/ checks in CI
Three findings from automated review. Two real, one verified false.
1. site/tsconfig.app.json and tsconfig.node.json did not set
compilerOptions.strict. Real gap -- added to both. Ran typecheck fresh
with the build-info cache cleared: zero errors surfaced, so this was a
missing safeguard, not a mask over existing problems.
2. Claimed App.tsx's `children: React.ReactNode` (no import) should fail
`tsc -b` with "Cannot find namespace 'React'", given the app tsconfig
restricts `types` to vite/client only. Checked before touching anything:
cleared the build-info cache and ran `npm run typecheck` fresh -- it
passed, both locally and in every prior CI run including the one that
just landed. The claim doesn't hold: any .tsx file using the automatic
JSX runtime (jsx: "react-jsx") implicitly resolves react/jsx-runtime's
types, which pulls in @types/react's global declarations regardless of
the restricted `types` array -- a real but non-obvious TypeScript
behavior a static reviewer wouldn't see. Not a bug. Made the import
explicit anyway (`import type { ReactNode } from "react"`), since relying
on an implicit global without saying so is fair to flag even when it
isn't broken -- a future reader shouldn't need to know the JSX-runtime
quirk to understand the type.
3. Real gap: docs-ci.yml and docs-deploy.yml both ran
`npm --prefix site run build`, which only proves the bundle compiles.
Vitest and the Open Graph tag verifier (site/scripts/verify-build.mjs)
were defined but not enforced by either required check -- a broken
component test or a missing meta tag could merge and deploy as long as
`vite build` itself succeeded. Both workflows now run
`npm --prefix site run check` instead, the same command run locally
before every push in this PR: format, lint, typecheck, vitest, build,
verify-build.mjs.
Verified end to end against the real container before pushing, same as the
merge script: `check` passes clean with strict mode on (format, lint,
typecheck, 10 tests, build, OG-tag verification), then the merge onto the
docs build still succeeds and leaves docs/ untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>1 parent a57f5c2 commit 7a49174
28 files changed
Lines changed: 6116 additions & 48 deletions
File tree
- .github/workflows
- build
- plans/06-landing-page
- specifications
- site
- scripts
- src
- css
- hooks
- test
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
5 | | - | |
6 | | - | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
13 | 15 | | |
14 | 16 | | |
15 | 17 | | |
| |||
64 | 66 | | |
65 | 67 | | |
66 | 68 | | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
67 | 92 | | |
68 | 93 | | |
69 | 94 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
56 | 77 | | |
57 | 78 | | |
58 | 79 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
38 | 45 | | |
39 | 46 | | |
40 | 47 | | |
| |||
84 | 91 | | |
85 | 92 | | |
86 | 93 | | |
87 | | - | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
88 | 99 | | |
89 | 100 | | |
90 | 101 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
0 commit comments