# 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/.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, )`. - 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, )` 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.