Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously an unversioned directory inside ~/src/blockninja-themes/brutalist. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
184 lines
9.5 KiB
Markdown
184 lines
9.5 KiB
Markdown
# Brutalist — Build Report
|
||
|
||
Theme slug: `brutalist`
|
||
Module path: `git.dev.alexdunmow.com/block/themes/brutalist`
|
||
Tech: templ-style (gotham-pattern), per spec §11.
|
||
Implementation pass: wave-1 (fonts policy applies — `fonts.json = []`).
|
||
|
||
## What landed
|
||
|
||
### Module + metadata
|
||
- `plugin.mod` per spec §2 verbatim: `kind = "theme"`, `scope = "@themes"`, `version = "0.1.0"`, `categories = ["templates"]`, tags array exactly the 8 spec values, `[compatibility] block_core = ">=0.11.0 <0.12.0"`.
|
||
- `go.mod` pinned to `git.dev.alexdunmow.com/block/core v0.11.1`, `go 1.26.4`, no `replace` directives.
|
||
- `Makefile` default target builds `brutalist.so` via `CGO_ENABLED=1 go build -buildmode=plugin`. No `rebuild` target (per agent scope; deploy is explicit).
|
||
|
||
### System / page templates / blocks
|
||
- System template registered: `brutalist` ("Brutalist", spec description verbatim).
|
||
- 4 page templates registered with exact spec slot arrays:
|
||
- `default` → `{header, main, footer}` → `RenderBrutalist`
|
||
- `landing` ("Index Sheet") → `{hero, ledger, footer}` → `RenderBrutalistLanding`
|
||
- `article` ("Case Study") → `{header, meta, main, footer}` → `RenderBrutalistArticle`
|
||
- `full-width` ("Full Bleed") → `{header, main, footer}` → `RenderBrutalistFullWidth`
|
||
- 7 theme blocks registered (all `Source: "brutalist"`):
|
||
- `masthead`, `project_ledger`, `concrete_hero`, `meta_strip`, `caption_image`, `pull_quote`, `colophon`
|
||
- 4 built-in block overrides via `RegisterTemplateOverride("brutalist", ...)`:
|
||
- `heading`, `text`, `button`, `image` — spec §9 treatments (square corners, font-display, mono code, figure wrapping).
|
||
- Email wrapper registered via `tr.RegisterEmailWrapper("brutalist", BrutalistEmailWrapper)`.
|
||
|
||
### Master pages
|
||
3 master pages in `DefaultMasterPages()` per spec §7 row-by-row:
|
||
- `brutalist:default-master` → templates `[default, article]`, blocks navbar/masthead/slot(main)/colophon(showAddress=true)
|
||
- `brutalist:index-master` → template `[landing]`, blocks masthead(hero)/slot(ledger)/colophon(showAddress=true)
|
||
- `brutalist:fullbleed-master` → template `[full-width]`, blocks navbar/slot(main)/colophon(showAddress=false)
|
||
|
||
### Schemas
|
||
7 draft-07 schemas in `schemas/<key>.schema.json`. `x-editor` values used: `text`, `richtext`, `media`, `select`, `textarea`, `collection`, `link`. All inside the allowed set per CLAUDE.md.
|
||
- `br.LoadSchemasFromFS(Schemas())` is called BEFORE any `br.Register(...)` in `register.go` — verified by reading top-to-bottom.
|
||
|
||
### Presets
|
||
`presets.json` ships two presets:
|
||
- `concrete-red` (mode `both`) with `lightColors` + `darkColors`, all 19 tokens each, HSL triple strings only.
|
||
- `hazard-yellow` (mode `dark`) with both `darkColors` and a mirror `lightColors` for editor preview, all 19 tokens each.
|
||
- Spot values from spec verbatim: `concrete-red.lightColors.background = "40 14% 93%"`, `concrete-red.lightColors.primary = "4 86% 48%"`, `hazard-yellow.darkColors.primary = "48 100% 50%"`, `hazard-yellow.darkColors.background = "0 0% 6%"`.
|
||
- check-safety presets check (Check 21): OK.
|
||
|
||
### CSS
|
||
`CSSManifest.InputCSSAppend` ships utility CSS via `ThemeCSSManifest()`:
|
||
- `:where(.brutalist-page, .brutalist-page *) { border-radius: 0 !important; }` (kills rounding theme-wide).
|
||
- `.brutalist-display`, `.brutalist-mono` font utilities flowing through `var(--font-heading|body|mono, <fallback-stack>)`.
|
||
- Hairline / thick rule utilities (`.brutalist-rule-ink`, `.brutalist-rule-thick`, `.brutalist-divider`).
|
||
- 12-column grid scaffolding (`.brutalist-grid-12`, `.brutalist-col-span-8`).
|
||
- Block-specific styles for `.brutalist-masthead`, `.brutalist-hero`, `.brutalist-ledger-row`, `.brutalist-meta-strip`, `.brutalist-pullquote`, `.brutalist-figure figcaption`, `.brutalist-colophon`.
|
||
- Square buttons + hover-invert-to-accent (spec §9 button override surface).
|
||
- Togglable `body.brutalist-grid-debug` 12-col overlay (UAT §13.11).
|
||
- All color references go through `hsl(var(--token))`; no hex/rgb/named colors anywhere in `*.go`, `*.templ`, or the appended CSS (Check 6 OK).
|
||
|
||
### Fonts (wave-1 policy)
|
||
- `fonts.json = []` (per FONTS.md override of spec §5 / UAT §11).
|
||
- `assets/` contains only a `.gitkeep`; no woff2 bundled.
|
||
- All `font-family` declarations in templates and CSS go through `var(--font-heading|body|mono, <fallback>)` with fallback stacks derived from the spec typography list (Space Grotesk → Inter Tight → Helvetica; Inter → -apple-system → Segoe UI; JetBrains Mono → IBM Plex Mono → ui-monospace).
|
||
- `RECOMMENDED_FONTS.md` written at the theme root listing the spec §5 fonts as Google Fonts picker recommendations with admin instructions.
|
||
|
||
## Build output
|
||
|
||
```
|
||
$ make
|
||
CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w" -o brutalist.so .
|
||
|
||
$ ls -la brutalist.so
|
||
-rw-rw-r-- 1 alex alex 21522624 brutalist.so
|
||
```
|
||
|
||
- File: `brutalist.so` (~20.5 MB; gotham reference `.so` is 21.1 MB, lcars is similar).
|
||
- No stderr warnings.
|
||
- `templ generate` produced 13 `_templ.go` files (committed alongside `.templ` sources).
|
||
|
||
## Safety check
|
||
|
||
Run from the actual check-safety location (the path in the spec's instructions points at `~/src/blockninja/backend/cmd/check-safety` but the real tool lives at `~/src/blockninja/check-safety/`).
|
||
|
||
```
|
||
$ cd /home/alex/src/blockninja/check-safety
|
||
$ go run . /home/alex/src/blockninja/themes/brutalist --plugin-dir /home/alex/src/blockninja/themes/brutalist
|
||
... (all 22 checks)
|
||
exit=0
|
||
```
|
||
|
||
Key results:
|
||
- **Check 2c** (Standalone plugin SDK import boundaries): OK — pinned to v0.11.1, no `replace` directives.
|
||
- **Check 3** (Go lint pipeline): OK after dropping unused `brutalistAccent`, `brutalistAccentFg`, `brutalistEmailCTAStyle`, and `renderPage` helpers.
|
||
- **Check 6** (No hardcoded colors in .templ): OK — all color references use `hsl(var(--token))`.
|
||
- **Check 11** (No placeholder code): OK.
|
||
- **Check 17** (No TODO markers): OK.
|
||
- **Check 21** (presets.json validation): OK.
|
||
- **Check 22** (No hand-rolled HTML sanitization): OK.
|
||
|
||
Warnings (non-fatal):
|
||
- **Check 2e** (`any` usage): 30 warnings, all from the required SDK signature `func(ctx context.Context, content map[string]any) string` and `MasterPageBlock.Content map[string]any`. Cannot be removed without breaking the SDK contract; same surface gotham exposes.
|
||
|
||
Overall: **exit 0, plugin builds, safety passes.**
|
||
|
||
## Open items / deferred
|
||
|
||
These items are explicitly deferred per the agent's hard scope rules ("local-build only, no woff2 bundling, no live deploy, no screenshots") and the FONTS.md wave-1 policy:
|
||
|
||
1. **Bundled woff2 files** — wave-2 follow-up. Currently `fonts.json = []`; `RECOMMENDED_FONTS.md` covers the admin path until Space Grotesk, Inter, and JetBrains Mono are bundled.
|
||
2. **`LICENSES.md`** — not written this pass (FONTS.md §"Wave-1 implementation policy" explicitly says "No `LICENSES.md` needed in this pass").
|
||
3. **Marketplace screenshots (spec §13.1)** — 6 frames at 1440×900 deferred until a running CMS instance is available; agent scope says "no `make rebuild`".
|
||
4. **Demo-content seed (spec §13.2)** — not implemented in this pass.
|
||
5. **`make rebuild` against running CMS** — UAT §2 "instance-brutalist Up within 15s" check cannot run from this agent's scope; needs a live instance.
|
||
6. **UAT §6, §7, §13 runtime checks** — accessibility, responsive, and aesthetic gates require a running container and visual verification; out of scope for the build agent.
|
||
7. **Email wrapper Litmus/cross-client verification (UAT §10)** — wrapper compiles and registers; live capture testing deferred.
|
||
8. **`concrete_hero.media` video support** (spec open question) — schema is `media` (image only) per the spec, deferred to v0.2 if the media type needs to widen.
|
||
|
||
## File inventory
|
||
|
||
```
|
||
brutalist/
|
||
├── BUILD_REPORT.md
|
||
├── Makefile
|
||
├── RECOMMENDED_FONTS.md
|
||
├── assets/
|
||
│ └── .gitkeep
|
||
├── brutalist.so
|
||
├── button_override.go
|
||
├── button_override.templ
|
||
├── button_override_templ.go
|
||
├── caption_image.go
|
||
├── caption_image.templ
|
||
├── caption_image_templ.go
|
||
├── colophon.go
|
||
├── colophon.templ
|
||
├── colophon_templ.go
|
||
├── concrete_hero.go
|
||
├── concrete_hero.templ
|
||
├── concrete_hero_templ.go
|
||
├── css_append.go
|
||
├── email_wrapper.go
|
||
├── email_wrapper.templ
|
||
├── email_wrapper_templ.go
|
||
├── embed.go
|
||
├── fonts.json
|
||
├── go.mod
|
||
├── go.sum
|
||
├── heading_override.go
|
||
├── heading_override.templ
|
||
├── heading_override_templ.go
|
||
├── helpers.go
|
||
├── image_override.go
|
||
├── image_override.templ
|
||
├── image_override_templ.go
|
||
├── masthead.go
|
||
├── masthead.templ
|
||
├── masthead_templ.go
|
||
├── meta_strip.go
|
||
├── meta_strip.templ
|
||
├── meta_strip_templ.go
|
||
├── page_data.go
|
||
├── plugin.mod
|
||
├── presets.json
|
||
├── project_ledger.go
|
||
├── project_ledger.templ
|
||
├── project_ledger_templ.go
|
||
├── pull_quote.go
|
||
├── pull_quote.templ
|
||
├── pull_quote_templ.go
|
||
├── register.go
|
||
├── registration.go
|
||
├── schemas/
|
||
│ ├── caption_image.schema.json
|
||
│ ├── colophon.schema.json
|
||
│ ├── concrete_hero.schema.json
|
||
│ ├── masthead.schema.json
|
||
│ ├── meta_strip.schema.json
|
||
│ ├── project_ledger.schema.json
|
||
│ └── pull_quote.schema.json
|
||
├── template.templ
|
||
├── template_templ.go
|
||
├── text_override.go
|
||
├── text_override.templ
|
||
└── text_override_templ.go
|
||
```
|
||
|
||
7 blocks, 7 schemas, 4 page templates, 4 built-in overrides, 1 email wrapper, 3 master pages, 2 presets. brutalist.so 21.5 MB. Safety check exit 0.
|