A small Zola theme. Built for two real sites.

Lazy Mastodon and Bluesky comments. A command palette behind /. Glassmorphic sidebars over per-theme background images. Light and dark that follow the browser's preference. JS-optional throughout: every interactive piece has a noscript fallback that keeps the page useful.

Powers auxdev.net (informal dev blog) and timsiggins.com (editorial portfolio). Both consume basalt as a Zola theme; the difference between them is a few SCSS files and one or two template overrides.

Lazy comments from Mastodon or Bluesky

basalt post page with Mastodon comments rendered at the bottom
Comments load on scroll-into-view, not on page load.

Comments are opt-in per post. The renderer chunk dynamic-imports the first time the #comments section scrolls into view, so third-party scripts only land on pages where the reader actually gets that far. Without JavaScript, the embed falls back to a "reply on platform" link pointing at the original Mastodon or Bluesky thread.

The full mechanic, plus the API endpoints used and the markup the section emits, lives in /options/.

Command palette behind /

basalt post page with code blocks
Hit / from any page to open the palette.

Press / from any page. The palette opens, focuses, and indexes posts via Fuse.js (loaded only on first open; the search index is a separate fetch). Site code can register actions through window.basalt.palette.register({...}) for one-off shortcuts, or declare them statically in config.toml via [[extra.palette_actions]]. Group order is configurable through [[extra.palette_groups]] so you can pin "Go" above "Posts" or hide a group entirely.

Glassmorphic sidebars + per-theme backgrounds

basalt sidebar with backdrop image and glass overlay
Per-theme background images with backdrop blur in one config block.

Drop two image paths into config.toml under sidebar_bg_image_light and sidebar_bg_image_dark and the sidebar gets a backdrop with backdrop-filter: blur(…) over a token-driven overlay. Page-level backgrounds work the same way through front-matter. Images run through Zola's resize_image at build time (WebP, srcset, sane defaults). https://… URLs pass through unchanged.

Editorial layer for portfolios

timsiggins.com homepage built on basalt
timsiggins.com: editorial layer over the same theme as auxdev.net.

basalt ships an opt-in _editorial.scss partial that exposes .editorial-{hero,pane,card,row,project,about-page} classes, an em shortcode for hero italic accents, and a font-stack swap via --font-{display,mono,text} CSS variables. timsiggins.com uses these for a magazine look on top of the same theme that auxdev.net renders as a btop-styled status board. Two sites, one theme, no fork.

No build step for consumers

The Vite + Rollup bundles ship pre-built under themes/basalt/static/dist/ and are committed to git. A consuming site needs only a Zola binary. No Node, no pnpm install, no CI step. Heavy dependencies (Fuse, KaTeX, asciinema-player, DOMPurify) are split into vendor chunks; a page that doesn't need a chunk doesn't download it.

Pages stay under 512kb.club thresholds without tuning.

Get started

cd your-zola-site
git submodule add https://codeberg.org/ttsigg/basalt themes/basalt

Minimum config:

theme = "basalt"
build_search_index = true

[search]
index_format = "fuse_json"

[extra]
author          = "Your Name"
author_display  = "You"
tag             = "yoursite.com"
default_theme   = "light"

Full schema in /options/. Setup, contributing, and the roadmap in the README.

Where to next

  • demo — panes layout, with /projects/ and /now/ underneath
  • options — config tables, design tokens, JS hooks. shortcodes walks every shortcode with a live demo
  • blog — release notes and the two comment-system demos