themes-y2k/BUILD_REPORT.md
Alex Dunmow 49f9c90589 initial: theme plugin y2k
Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously
an unversioned directory inside ~/src/blockninja-themes/y2k.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 14:11:46 +08:00

238 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Y2K theme — build report
Implementation pass: 2026-06-06.
Reference style: templ (gotham-shaped, per spec §11 "Tech choice").
## What landed
### Registration (`registration.go`, `register.go`)
- `Registration` exported, `Name: "y2k"`, `Version: plugin.ParseModVersion(pluginModBytes)`.
- `tr.RegisterSystemTemplate(Key: "y2k", ...)` — exactly one call.
- `tr.RegisterPageTemplate("y2k", ...)` called four times with slots verbatim:
- `default``["header", "main", "footer"]`
- `landing``["hero", "marquee", "main", "cta", "footer"]`
- `article``["header", "main", "aside", "footer"]`
- `full-width``["header", "main", "footer"]`
- `br.LoadSchemasFromFS(Schemas())` invoked once, before any `br.Register(...)`.
- 10 theme blocks registered (unqualified keys, `Source: "y2k"`):
`chrome_navbar`, `metaball_hero`, `waveform_player`, `marquee`,
`tracklist`, `merch_card`, `webring_badge`, `glitter_divider`,
`footer_chrome`, `nft_gallery`.
- 4 overrides registered: `heading`, `text`, `button`, `image` via
`br.RegisterTemplateOverride("y2k", ...)`.
- `tr.RegisterEmailWrapper("y2k", Y2KEmailWrapper)` wired.
- `DefaultMasterPages()` seeds `y2k:default-master` (applies to `default`,
`article`) and `y2k:landing-master` (applies to `landing`, `full-width`)
with the exact block order from spec §"Master pages".
### Plugin metadata (`plugin.mod`)
- `name = "y2k"`, `display_name = "Y2K"` (3 chars, ≤40), `scope = "@themes"`.
- `kind = "theme"` (per global rule, not "plugin").
- `categories = ["templates", "media"]` — both whitelisted.
- `tags` — 8 entries (within the 59 UAT range).
- `version = "0.1.0"`.
- `[compatibility] block_core = ">=0.11.0 <0.12.0"` verbatim.
- Description 157 chars (≤240).
### Schemas (`schemas/*.schema.json`)
- 10 JSON Schema files, all draft-07.
- Property names match `content["…"]` reads in the Go files one-to-one (no
orphans either direction; verified by script during build).
- All `x-editor` values are members of the whitelist
`{text, richtext, media, color, select, number, slug, textarea, array,
collection, bucket-picker, menu-select, template-select, link}`.
### Presets (`presets.json`)
- Exactly 3 entries with `id` values `chrome-dream`, `cd-rom-after-hours`,
`bubblegum-trapper`.
- `chrome-dream` declares `mode: "both"` with both `lightColors` and
`darkColors` blocks (38 tokens across both).
- `cd-rom-after-hours` declares `mode: "dark"` with `darkColors` only.
- `bubblegum-trapper` declares `mode: "light"` with `lightColors` only.
- All 19 tokens present per colour block.
- Every value matches the regex `^\d+ \d+% \d+%$` (HSL triples, no `hsl()`
wrapper). Verified via Python regex check.
- Values copied verbatim from spec §4 tables.
### Fonts (`fonts.json`, `RECOMMENDED_FONTS.md`)
- `fonts.json` is `[]` per the wave-1 policy in `themes/docs/FONTS.md`.
- `RECOMMENDED_FONTS.md` lists the spec §5 fonts as Google Fonts picker
recommendations (Inter Tight via Google; VT323 via Google as the
open-licensed fallback for Stretch Pro; Departure Mono and Stretch Pro as
admin uploads).
- All `font-family` references in templates and CSS go through
`var(--font-heading|body|mono, <fallback-stack>)`. The headline heavy
fallback stack is `"Stretch Pro", "VT323", "Courier New", monospace`.
### CSS (`css.go` via `CSSManifest.InputCSSAppend`)
- Declares `--chrome-1..4`, `--mesh-a/b/c`, `--bevel-light/dark` custom
properties on `:root` and `.dark` (UAT 13.2, 13.3, 13.4).
- Defines exactly one `@keyframes marquee-x`, one `@keyframes sparkle`, one
`@keyframes metaball-morph` block (UAT 13.5).
- Provides utility classes:
- `.y2k-chrome-bg` (layered linear gradient through `--chrome-1..4`).
- `.y2k-mesh-bg` (radial-gradient mesh through `--mesh-a/b/c`).
- `.y2k-bevel` (`border: 2px solid hsl(var(--border))` + inset shadows
using `--bevel-light/dark`; UAT 13.4).
- `.y2k-button` (3D plastic bevel with `border-style: solid`,
`border-width: 2px`, `box-shadow` containing `inset` — UAT 13.9).
- `.y2k-marquee` + `.y2k-marquee-track` with `overflow: hidden` and the
`marquee-x` animation; `animation-play-state: paused` on hover/focus
(UAT 13.10, 6.7).
- `.y2k-webring-badge` at the canonical `width: 88px; height: 31px`
(UAT 13.11).
- `.y2k-foil::after` with `conic-gradient(` and `filter: hue-rotate(`
that activates on `:hover` (UAT 13.12).
- `.y2k-heading`, `.y2k-text`, `.y2k-image-frame`, `.y2k-sparkle`,
`.y2k-metaball`, `.y2k-glow`.
- Honors `prefers-reduced-motion: reduce` by disabling marquee, sparkle,
and metaball-morph animations (UAT 6.6).
- All colour references go through `hsl(var(--token))`; no hardcoded
hex/rgb appears in any `.go` or `.templ` file outside the email wrapper
(which uses hex fallbacks that translate the chrome-dream dark preset for
Gmail/Outlook compatibility, exactly as gotham does).
### Email wrapper
- `tr.RegisterEmailWrapper("y2k", Y2KEmailWrapper)` registered exactly once.
- 600px centred chrome-bordered card on a near-black background
(`#0c0820`-equivalent sourced from `emailCtx.Colors.Background` when set,
otherwise the chrome-dream dark token value).
- Gradient header bar uses `linear-gradient(90deg, primary, secondary)`.
- Inter Tight body with system fallback stack.
- Marquee footer pill renders the same items as the in-page marquee.
- Plain-text fallback is deferred to the CMS-default stripping (the wrapper
receives `body` already rendered; the marquee items are duplicated into a
visible string so a plain-text view still surfaces them).
## Build output
```
$ cd /home/alex/src/blockninja/themes/y2k && go mod tidy
(exit 0)
$ cd /home/alex/src/blockninja/themes/y2k && /home/alex/go/bin/templ generate
(✓) Complete [ updates=16 duration=10ms ]
$ cd /home/alex/src/blockninja/themes/y2k && make
CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w" -o y2k.so .
(exit 0, no warnings)
$ ls -la y2k.so
21,543,872 bytes (≈21 MB) ELF 64-bit LSB shared object, stripped
```
`make` exits 0 with zero `warning` lines in stdout/stderr (UAT 2.1).
## Safety check
```
$ /tmp/check-safety . --plugin-dir /home/alex/src/blockninja/themes/y2k
(... 22 checks, all OK or SKIP for "no frontend sources" ...)
exit=0
```
NOTE: the task brief references `cd ~/src/blockninja/backend && go run
./cmd/check-safety …`. The actual command path on this host is
`~/src/blockninja/check-safety/` (no `/backend/cmd/` subpath). The
invocation above is the host-local equivalent and exits 0.
Specifically verified:
- Check 21 (presets.json validation): OK — single preset file validated.
- Check 22 (no hand-rolled HTML sanitization): OK.
- No `git.dev.alexdunmow.com/block/cms/...` import boundary violations.
- No `^replace ` directives in `go.mod`.
- `block/core v0.11.1` pinned to match `cms/backend/go.mod`.
## Open items / deferred
The following spec/UAT requirements are intentionally deferred to a later
wave and would block sign-off on the running container but do not block
this build pass:
- **Bundled woff2 files**. Per `themes/docs/FONTS.md` wave-1 policy this
pass ships `fonts.json = []`. UAT §11 file-existence checks pass
trivially. Wave-2 will commission/licence Stretch Pro and Departure Mono
and bundle them.
- **`LICENSES.md`** — explicitly skipped per FONTS.md wave-1 policy
("No `LICENSES.md` needed in this pass").
- **Marketplace screenshots** (`marketplace/screenshots/*.png`, 1440×900).
Not produced in this pass — gated by a running container with deployed
CSS.
- **Demo content seed** ("Static Lagoon" fictional artist with 6 tracks,
4 merch items, 2 zine articles, 5 webring entries). Not produced — the
data plane is out of scope for the .so build pass.
- **Container-level UAT items**: §2.72.8 (`make rebuild`, log scrape),
§5.7 (no console errors at the rendered URL), §6.16.7 (Lighthouse /
computed-style assertions on a running site), §7.17.6 (responsive
viewport checks), §8.* (rendering each block in three states in the
browser), §9.7 (admin-replace round-trip), §10.210.4 (Litmus / Gmail /
Apple Mail / Outlook 365 previews), §11.411.5 (network-tab font 200
checks, FOUT trace), §12.* (marketplace assets, demo seed), §13.1, 13.6
(computed-style assertions on rendered pages), §14.* (three-theme
install regression), §15.* (three named reviewer sign-offs).
- **Waveform peak-data source**. The block ships with a placeholder
`<canvas data-y2k-waveform>` element that the CMS' client runtime can
populate via WebAudio decode (deferred to v0.2 per spec open question).
- **Cursor-trail sparkle script**. Only the CSS classes are shipped; the
document-level cursor-trail script is deferred and gated by
`data-editor-mode` on `<html>` per the spec's open question.
- **Mobile menu drawer JS**. The chrome navbar exposes the
`[aria-controls]` toggle button required by UAT §7.4 but the
drawer-open behaviour is owned by the host menu script.
## File inventory
```
y2k/
├── BUILD_REPORT.md (this file)
├── Makefile
├── RECOMMENDED_FONTS.md
├── assets/
│ └── placeholder.txt
├── button_override.{go,templ,_templ.go}
├── chrome_navbar.{go,templ,_templ.go}
├── css.go
├── email_wrapper.{go,templ,_templ.go}
├── embed.go
├── fonts.json
├── footer_chrome.{go,templ,_templ.go}
├── glitter_divider.{go,templ,_templ.go}
├── go.mod
├── go.sum
├── heading_override.{go,templ,_templ.go}
├── helpers.go
├── image_override.{go,templ,_templ.go}
├── marquee.{go,templ,_templ.go}
├── merch_card.{go,templ,_templ.go}
├── metaball_hero.{go,templ,_templ.go}
├── nft_gallery.{go,templ,_templ.go}
├── plugin.mod
├── presets.json
├── register.go
├── registration.go
├── schemas/
│ ├── chrome_navbar.schema.json
│ ├── footer_chrome.schema.json
│ ├── glitter_divider.schema.json
│ ├── marquee.schema.json
│ ├── merch_card.schema.json
│ ├── metaball_hero.schema.json
│ ├── nft_gallery.schema.json
│ ├── tracklist.schema.json
│ ├── waveform_player.schema.json
│ └── webring_badge.schema.json
├── template.{templ,_templ.go}
├── text_override.{go,templ,_templ.go}
├── tracklist.{go,templ,_templ.go}
├── waveform_player.{go,templ,_templ.go}
├── webring_badge.{go,templ,_templ.go}
└── y2k.so (21 MB)
```