The shared-masthead change stripped the mirror page's local :root including four tokens the shell does not define (card, void-2, good, bad), leaving card backgrounds and status colours undefined on the live page. The index wrap was also narrowed to 64ch, squeezing the chapter cards; the masthead carries its own width limit so wrap returns to 56rem. Two American spellings in mirror prose corrected to artefact.
The Teaching Lab (learn.bztmon.com)
A static learning site documenting infrastructure I operate in my homelab - the decisions,
the failures, and the validation still outstanding. Dark engineering-dossier aesthetic (void #070b14, cyan #3fbaf5,
magenta #e879f9), dependency-light by design, strict security posture.
Pages
| Route | Page | Source |
|---|---|---|
/ |
The Teaching Lab - chapter directory | pilot/index.tpl.html |
/cluster |
Chapter 01: The Exploded Cluster - eleven-course container-platform teardown | pilot/arc.tpl.html + pilot/manifest-*.json |
/mirror |
Chapter 02: The Mirror - a zot pull-through registry, its failure modes and operations | pilot/mirror.tpl.html + pilot/mirror.js |
Build
bash build.sh -> dist/. The assembler (pilot/assemble-arc.mjs, plain node, no
dependencies) wraps each page in a shared document shell (canonical/OG metadata, build
revision, skip link), content-fingerprints every file under /assets/ (immutable-cached
by nginx), splits page scripts into external fingerprinted files, injects intrinsic image
dimensions (WebP and JPEG parsed from the actual bytes) with deliberate lazy/eager loading,
and runs per-page preflight gates: no inline scripts (CSP script-src 'self' with no
exceptions), exactly one h1, unique ids, no dangling anchors, no unresolved placeholders,
and page-specific content assertions. A failed gate fails the build.
Ship: podman build (multi-stage: node builds dist/, nginx-unprivileged serves it,
both digest-pinned) -> push to the estate registry -> digest-pinned deploy via GitOps.
nginx/ carries the runtime config: strict CSP, HSTS, no-cache HTML with immutable
fingerprinted assets, security headers on every location.
Accessibility and performance
Skip link on every page (hidden until keyboard focus), one h1 per page, stable section
anchors, reduced-motion honoured live (effects also pause when the tab is hidden or the
scene is off screen), intrinsic image dimensions to prevent layout shift, below-fold images
lazy-loaded, system font stacks (CSP permits no third-party fonts).
Layout
| Path | What |
|---|---|
pilot/ |
page templates, page scripts, scene manifests, the assembler |
assets/dist/ |
production heroes and diagrams for /cluster |
assets/mirror/ |
plates for /mirror |
content/ |
course source notes |
nginx/ |
runtime config baked into the image |
tools/slicer.html |
slice editor: load a hero, tune cut lines, export a scene manifest |
prompts/ |
image prompt contract for the house visual style |
exploded-cluster.html, ec2-part*.html |
v2 (parked, superseded by /cluster) |
gsap.min.js / st.min.js |
GSAP 3.13 + ScrollTrigger, fingerprinted at assemble time |
The slicing rule (load-bearing - read before touching the arc engine)
Parts occlude each other in 2D, so every slice carries a hidden notch where the part in
front covers it. Animating collapsed -> hero only ever increases occlusion, so notches
stay buried. Never overshoot past the hero layout and never fan parts sideways - either
exposes the tears. Region boundaries overlap upward by EPS; expanding downward would ghost.