A tour of the theme
Syntax highlighting, Mermaid diagrams, Swiper galleries, and everything else this blog can render.
This post exercises every part of the theme, so it doubles as a visual test page. Edit it, or delete it once you’ve seen how things look.
Backdrops
The background is a WebGL shader with four scenes: aurora, topo, nebula and halftone. Set a site default with theme_options.backdrop in _config.yml, or pick one per post with backdrop: in the front matter (this post uses nebula). Visitors can choose their own, or turn it off, from the footer.
All scenes react to scrolling and the pointer. Click or tap anywhere to send a ripple through the field. With reduced motion turned on, the shader draws a single still frame.
Callouts
Use GitHub-style alert syntax in a blockquote. They’re rendered at build time, so they work without JavaScript.
Badges
Posts get badges automatically: New for recent posts, Featured, and Updated when the front matter has an updated: date. Add your own with a badges: list.
You can also use them inline in Markdown: stable beta deprecated v2.1 Pro
<span class="badge badge--success">stable</span>
Banners and notifications
- Post banners sit above the post body. Set
banner:in the front matter, like the one at the top of this post. - Older posts get a notice automatically once they pass
theme_options.outdated_after_days. Setoutdated: falseon a post to skip it. - Announcements live in
_data/announcements.yml. Each one shows either as a bar above the header or as a toast. Visitors can dismiss them, and they can have start and end dates. - Toasts are also available from JavaScript:
toast({ title, message, variant, action }). The button below tries it.
Code
Fenced code blocks get syntax highlighting from Rouge, plus a language label and a copy button.
type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };
export async function fetchJson<T>(url: string): Promise<Result<T>> {
try {
const res = await fetch(url, { headers: { Accept: "application/json" } });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return { ok: true, value: (await res.json()) as T };
} catch (error) {
return { ok: false, error: error as Error };
}
}
use std::collections::HashMap;
fn word_counts(text: &str) -> HashMap<&str, usize> {
let mut counts = HashMap::new();
for word in text.split_whitespace() {
*counts.entry(word).or_insert(0) += 1;
}
counts
}
func worker(ctx context.Context, jobs <-chan Job, results chan<- Result) {
for {
select {
case <-ctx.Done():
return
case job := <-jobs:
results <- job.Run()
}
}
}
# Deploy a preview build
git switch -c my-feature
git commit -am "Try something" && git push -u origin my-feature
- const timeout = 1000;
+ const timeout = 5_000; // allow slow cold starts
Inline code like bundle exec jekyll serve works too.
Diagrams
Write Mermaid in a mermaid fenced block. Add accTitle and accDescr so screen readers get a description of the diagram.
flowchart LR
accTitle: Deployment pipeline
accDescr: A git push triggers a Vercel build. Main deploys to production; other branches get a preview URL.
push([git push]) --> build[Vercel build]
build --> branch{Branch?}
branch -- main --> prod[Production]
branch -- other --> preview[Preview URL]
sequenceDiagram
accTitle: Request lifecycle
accDescr: A browser requests a page from the Vercel edge, which serves the static file from its cache.
participant B as Browser
participant E as Vercel Edge
participant S as Static files
B->>E: GET /2026/10/16/theme-tour/
E->>S: Cache miss
S-->>E: index.html
E-->>B: 200 OK
Gallery
Swiper powers galleries. Swipe, drag, or use the arrow keys when the gallery has focus.
Everything else
Simplicity is prerequisite for reliability. — Edsger W. Dijkstra
| Layer | Tool | Notes |
|---|---|---|
| Content | Markdown | Lives in _posts/ |
| Build | Jekyll 4 | Runs on Vercel |
| Effects | WebGL, GSAP | Turned off for reduced motion |
| Carousels | Swiper | Loaded only where it’s used |
- Unordered lists
- Nest nicely
- Like this
That’s the tour.
-
Footnotes collect at the bottom of the post. ↩︎