Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously an unversioned directory inside ~/src/blockninja-themes/scifi-clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
8.8 KiB
Sci-Fi Clean — Build Report (v0.1.0, wave-1 pass)
What landed
Module scaffolding
plugin.modwithkind = "theme",scope = "@themes", all spec §2 fields verbatim (categories["templates", "developer"], 9 tags),[compatibility] block_core = ">=0.11.0 <0.12.0".go.modpinned togit.dev.alexdunmow.com/block/core v0.11.1,go 1.26.4, noreplacedirectives.Makefilewithall(default),clean,templ,helptargets. The build line isCGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w" -o scifi-clean.so ..embed.godeclares all five canonical embed directives plusThemeCSSManifest().
Registration
- One
RegisterSystemTemplate({Key: "scifi-clean", ...}). - Four page templates per spec §6:
default— slotsheader, main, footerlanding— slotshero, specs, main, cta, footerarticle— slotsheader, rail, main, footerfull-width— slotsheader, main, footer
br.LoadSchemasFromFS(Schemas())runs before anybr.Register(...). UAT §3.6.- Six theme blocks registered:
tech_spec,diagram_caption,mission_stat,status_bar,footer,schematic_hero. Each hasSource = "scifi-clean"and an unqualifiedKey. Addressed at runtime asscifi-clean:<key>. - Three overrides registered against theme key
"scifi-clean":heading → ScifiHeadingBlock(Space Grotesk via--font-heading, optional mono kicker)text → ScifiTextBlock(Inter via--font-body, tabular-nums)button → ScifiButtonBlock(mono uppercase label, literal→U+2192 chevron +data-icon="chevron-right"for UAT §13.14)
tr.RegisterEmailWrapper("scifi-clean", ScifiEmailWrapper)wires the 600px white-card email shell with Space Grotesk display lockup top-left and mono callsign top-right.
Master pages
DefaultMasterPages() returns two entries:
scifi-clean:default-master, attached todefault,article,full-width. Blocks:navbar(header, 0) +scifi-clean:status_bar(header, 10) +slot(main, 0,{"slotName": "main"}) +scifi-clean:footer(footer, 0). Matches spec §7 / UAT §9 byte-for-byte.scifi-clean:landing-master, attached tolanding. Pre-populatesherowithscifi-clean:mission_statandspecswithscifi-clean:tech_spec, both seeded with example payloads.
Schemas
Six schemas/*.schema.json files, all draft-07, x-editor values restricted to the
allowed set (text, richtext, media, select, number, array, collection,
link). Property names match the corresponding Go content reads exactly.
Presets
presets.json is a JSON array of length 3 in the order required by UAT §5.1:
flightline— modelight, onlylightColors. Declares"primary": "215 90% 45%"and"accent": "18 95% 55%"byte-exactly (UAT §13.1).mission-control— modedark, onlydarkColors. Declares"background": "220 16% 7%"and"accent": "18 100% 60%"byte-exactly (UAT §13.2).cleanroom— modeboth, bothlightColorsanddarkColors.
All three presets carry all 19 tokens in each declared color block. Every value is
an HSL triple string of the shape ^\d+ \d+% \d+%$ (no hsl() wrappers).
CSS manifest
ThemeCSSManifest() returns a *plugin.CSSManifest whose InputCSSAppend
contains the literal substrings UAT §13.4 grep-greps: 'Space Grotesk',
'JetBrains Mono', .hairline, .bg-grid. The .hairline declaration is
exactly border: 1px solid hsl(var(--border)); (UAT §13.5).
The manifest also defines:
- Root-level CSS-variable fallback stacks for
--font-heading,--font-body,--font-monoso the theme looks correct before the admin picks Google Fonts. .bg-gridblueprint grid utility..scrimutility for full-bleed hero text (UAT §6 scrim requirement)..scifi-focusoutlined focus ring derived from--ring..scifi-chevronUnicode arrow suffix for button labels.
Fonts policy (wave-1)
fonts.jsonis the literal[]. No woff2 files bundled in this pass.RECOMMENDED_FONTS.mdat the theme root lists Space Grotesk / Inter / JetBrains Mono as Google Fonts picker recommendations.- No
LICENSES.md(nothing is bundled to license).
Build output
$ cd ~/src/blockninja/themes/scifi-clean && make clean && make
rm -f scifi-clean.so
CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w" -o scifi-clean.so .
$ ls -la scifi-clean.so
-rw-rw-r-- 1 alex alex 21535264 ... scifi-clean.so (≈ 20.5 MiB)
$ file scifi-clean.so
ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped
make 2>&1 | grep -Ei 'warning|error' returns empty. go mod tidy is a no-op
after the initial run; the resolved block/core version is v0.11.1.
Safety check
Run from the standalone check-safety module (at ~/src/blockninja/check-safety/,
not backend/cmd/check-safety — that path does not exist in this tree):
$ cd ~/src/blockninja/check-safety && \
go run . ~/src/blockninja/themes/scifi-clean \
--plugin-dir ~/src/blockninja/themes/scifi-clean
...
EXIT: 0
All 22 checks PASS or SKIP. Specifically:
- Check 2c (SDK import boundary): OK on v0.11.1.
- Check 6 (no hardcoded colors in .templ/.ninjatpl files): OK.
- Check 11 (no placeholder code): OK.
- Check 17 (no TODO markers): OK.
- Check 21 (presets.json validation against
theme.Theme): OK.
The only non-OK output is Check 2e (any usage), which is a WARN, not a FAIL.
The 34 warnings are the expected map[string]any content map signature for plugin
block render funcs — that is the SDK's required block-func shape and cannot be
avoided in a standalone plugin. Same as gotham/ and lcars/.
Open items / deferred
These are intentionally out of scope for the wave-1 implementation pass:
Fonts
- No woff2 files bundled (
fonts.json = []perthemes/docs/FONTS.md). Wave-2 may bundle commercial display faces (Eurostile when licensed, otherwise stick with Space Grotesk) underassets/fonts/web/. - Section §11 of the UAT (woff2 file presence,
@font-facecount, network fetch checks) is superseded by the FONTS.md wave-1 policy, which only requiresfonts.jsonto parse as JSON,RECOMMENDED_FONTS.mdto exist, and CSS to consumevar(--font-*). All three pass.
Live instance / make rebuild
make rebuildis not wired in thisMakefile. Adding it requires theblockninja-go-builderpodman image and the live CMS at~/src/blockninja. Copy gotham'srebuild,backend,build-frontend,copy-plugin-source,build-so,sync-migrations,build-css,deploy-css,logs,statustargets when the next implementation pass needs container deployment.
Marketplace assets (UAT §12)
- No screenshots captured (
docs/uat-evidence/screenshots/). Requires a running instance. - No
Project Aurorademo content seeded. Requires admin tooling and a populated database. - No
docs/launch-copy.txt. Copy is in spec §13 verbatim; persist when the marketplace listing is created.
Versioning / git
- The theme is not under git in this scope; UAT §1.11 (
git describe --tags) cannot be evaluated until the directory is initialised as a git repo and taggedv0.1.0.
Email wrapper hex fallbacks
email_wrapper.templcarries a small set of hardcoded hex values (#F6F7F8,#FFFFFF,#D6D9DD,#16202E,#5C6776) that act as the ultimate fallback whenEmailContext.Colorsis empty. Email clients (Outlook in particular) cannot resolvehsl(var(--token)), so emails must inline hex; the runtime path always passes preset-resolved hex viaEmailContext. Check-safety §6 only scans.templfiles for the hardcoded-colors rule and currently passes (the hex literals live inside Go fallback funcs and are explicitly out of the templ-emit path). UAT §5.5 may need a clarifying note that email fallbacks are intentional.
Hidden blocks
- None of the six theme blocks set
Hidden: true; the spec did not request any. (Gotham hides itsstat_itemchild block; the scifi-clean equivalent is the in-rowscollection ontech_spec, which is schema-only and never registered as a standalone block, so noHiddenflag is needed.)
Block category metadata
- All six theme blocks set
Categoryto one of the SDK constants (CategoryContent,CategoryNavigation,CategoryLayout). The spec's §8 table lists category names likemediaandblogthat do not map to SDK constants; those are stored implicitly via the spec source rather than the BlockMeta — flag in BUILD_REPORT for future enum extension.
Slot block placeholder
- Master pages reference the built-in
slotblock with{"slotName": "main", "placeholder": "Page payload"}. Theplaceholderkey is a CMS-side convention copied verbatim from gotham; it is not the same as the check-safety §11 "no placeholder code" rule (which fires on dev-time comments like// TODO: placeholder). Check-safety passes.