The theme behind this site and behind timsiggins.com. Monospace-accented or editorial depending on the persona, keyboard-friendly, light and dark, small enough to serve from a potato. No framework in the consumer repo. JavaScript off? Everything still works except the command palette and the comment embeds.
Source lives at codeberg.org/ttsigg/basalt. The README has install notes; the announcement post covers what shipped in v1.
What you get
- btop-inspired panes on the homepage and
/now, with a live uptime clock, a reading list, and a tinkering-with card driven by a singledata/now.json. - Command palette on
/. Searches titles and body text via Zola's built-in index, ships at about 3kb, lazy-loads on first keypress. Ctrl+K works too. - Light and dark themes with no flash of wrong theme, ever. Press t to toggle.
- Eleven shortcodes with full no-JS fallbacks: alert, collapsible, em, toc, image (with float + lightbox), carousel, asciinema, katex, mermaid (markdown fence), project, pullquote, epigraph.
- Asciinema embeds with a titlebar that matches the site. Player loads only on pages that use the shortcode.
- KaTeX for math. Loaded only on pages that contain math.
- Mastodon and Bluesky comments, opt-in per post, lazy-loaded on scroll-into-view.
- Responsive images via Zola's
resize_image()with multi-width WebPsrcsetout of the box. - MPA View Transitions for smooth navigation in browsers that support them, gated on
prefers-reduced-motion. - Persona token system. Two sites running on this theme look completely different — they swap fonts, colours, ornaments, and editorial chrome via a
[extra.persona.*]table. - Under 40kb per page on almost every route, fonts included.


Two personas, one engine
The part that took six rewrites is the persona system. Both consumer sites import basalt's SCSS aggregator once, then layer their own token table:
| Token | auxdev (this site) | timsiggins.com |
|---|---|---|
--font-text | Inter | Public Sans |
--font-display | Space Grotesk | Newsreader |
--ornament | ▍ ▍ ▍ | ⁂ |
--anchor-glyph | ❯ | § |
| Accent | terminal green | editorial indigo |
| Pullquote chrome | mono italic, centered | serif italic, large |
Same Tera templates, same Vite bundle, two wildly different identities. Adding a third consumer site is a config.toml away.
A blog post, light and dark


Mobile
Same content, narrower viewport. Sidebar collapses to a top bar; panes stack; the command palette still works on phones with a hardware keyboard.
A terminal recording, because why not
The asciinema shortcode renders a scaled player with a themed titlebar. The player and runtime are lazy-loaded only on pages that have a cast.
Math, lazy-loaded
Inline KaTeX: . Display mode:
KaTeX is loaded only on pages whose content contains a math element. Pages without math never pay the cost.
Comments, two flavours
Opt-in per post via front-matter:
+++
comments = "bluesky"
bluesky = "https://bsky.app/profile/handle/post/id"
+++Both renderers lazy-load the platform's public API when the reader scrolls to the bottom. No cookies, no third-party script until then, no consent banner. Live demos: Mastodon, Bluesky.
Tech
- Zola 0.22.1 — static generator and built-in Sass.
- Tera — templates, because Zola ships Tera.
- Sass with CSS custom properties for theming.
- Vite + Rollup — JS bundle. Output ships as a committed artifact in the theme repo, so consumer sites don't need npm.
- Playwright — cross-site visual-consistency suite.
Using it
Clone the repo, drop your content into content/, point config.toml at yourself, run just setup once to fetch Zola, then just serve. Production builds go to public/ via just build. The auxdev repo's DEPLOY notes walk through Cloudflare Workers from scratch.
If you hit something busted, file a Codeberg issue. I read them.