A warp-speed Eleventy blog starter powered by Tachyons utility classes. It ships with theme switching, accessible navigation, and a flexible layout that adapts to small and large viewports.
https://subspace-builder.nicholas.clooney.io/
- Powered by Eleventy 3 with Markdown-it and auto-generated heading anchors
- Tachyons-based, theme-aware typography and color palettes with preview buttons
- Recursive Eleventy Navigation sidebar with responsive hamburger toggle
- Reusable post list macro that trims excerpts and formats dates
- Responsive image pipeline powered by
@11ty/eleventy-img(see Responsive Images with Eleventy Img) - YAML-driven site metadata, theme presets, animation timing controls, and optional Umami analytics configuration managed in
_data/site.yml - Social preview images generated at build times
- GitHub snippet embedding via a
{% github %}shortcode that fetches, highlights, and caches remote code
- Node.js 18 or newer
npm installnpm run devThis sets ELEVENTY_ENV=development and starts Eleventy in watch/serve mode. Visit http://localhost:8080 (default) to browse the site. Theme selections persist in localStorage so you can preview skins as you work.
npm run prodRuns the site with ELEVENTY_ENV=production while keeping Eleventy’s dev server running so you can QA the published experience without deploying.
npm run buildThis sets ELEVENTY_ENV=production and writes the static output to the _site/ directory. Deploy those files to any static host or CDN.
compose.ymluses the stocknode:25-bookworm-slimimage and installs dependencies at container start.- Default mode (public ports):
docker compose up -d - Dev:
http://127.0.0.1:8080 - Prod:
http://127.0.0.1:8090 - Shared-edge mode (no host ports; for reverse proxy via Caddy on the
edgenetwork):docker network create edge 2>/dev/null || true - Run:
docker compose -f compose.yml -f compose.edge.yml up -d - Caddy (in the ingress stack) should
reverse_proxyto thedevorprodcontainer names on theedgenetwork.
scripts/generate-og-images.jsruns before each Eleventy build to produce 1200×630 Open Graph cards using Satori (HTML template) and Resvg. We stick with Satori’s HTML helper instead of JSX so the pipeline stays zero-transpile and works out-of-the-box in Node.- Templates blend Lexend (heading) + Inter (body) from the
@fontsource/*packages and use the Sun theme palette (soft yellow gradient, amber accents, black typography); tweakbuildTemplateto adjust the look. - Headlines/excerpts auto-resize and truncate when needed so long titles (e.g. “The Joy (and Frustrations) of Building Small Sites with GPT-5 Codex”) stay legible without breaking the layout.
- Content hashing keeps regeneration cheap—changes to a post’s title, excerpt, or the template version trigger a refresh, otherwise cached PNGs in
.cache/og/are reused. - Use
npm run ogto generate cards manually,npm run og -- --force(orOG_FORCE=true npx @11ty/eleventy) to rebuild everything, and check the emitted file map in_data/ogImages.json. - Posts automatically receive an
ogImagefield via computed data, so layouts and feeds can reference{{ ogImage }}without manual front matter tweaks.
_data/- Global data files (site.ymlandthemes.yaml) that drive metadata, theme options, and animation settings._includes/layouts/- Base and page layouts, including the responsive navigation + theme selector UI inhome.njk._includes/components/- Shareable Nunjucks macros likepost-list.njkfor rendering excerpts.posts/- Blog posts and collection defaults (posts.jsonassigns the home layout to the collection).eleventy.config.js- Eleventy configuration, Markdown-it setup, the Eleventy Img transform, and custom filters (readableDate,machineDate,excerpt).index.md- Home page content that also uses thehomelayout.
title,url, and author contact details.themeblock toggles the selector (showSelectors), controls animation timings, and sets the default theme (defaultId).umamiblock (optional) controls the analytics script URL (source) and trackingid; remove or comment it out to disable tracking.
- Giscus is optional and configured via the
giscusblock in_data/site.yml. - Visit giscus.app with your GitHub repository selected to generate the
repo,repoId,category, andcategoryIdvalues—replace the defaults before enabling comments on your site. - If you do not plan to use Giscus, delete or comment out the
giscusblock so any clones of this starter do not point comment traffic at someone else’s repository. - The remaining attributes (
mapping,lang, etc.) can stay at their defaults unless you want to tweak how threads are created or which language the widget uses.
Add, remove, or tweak Tachyons class pairs here. Each theme entry accepts:
id- Unique identifier used for persistence and data attributes.classes- Tachyons classes applied tohtmlwhen the theme is active.midtoneClass- Optional class used to recolor elements tagged with.theme-midtone.
Create a new Markdown file in posts/ with front matter similar to:
---
title: My Next Adventure
date: 2025-02-01
eleventyNavigation:
key: my-next-adventure
parent: posts
excerpt: |
A quick teaser paragraph that appears in post lists.
---
Your post content starts here. Eleventy handles Markdown -> HTML conversion.Posts automatically pick up the layout defined in posts/posts.json. The excerpt field is optional; without it, the excerpt filter trims the rendered HTML.
- Use
{% from "components/post-list.njk" import renderPostList %}inside a template to render a list of collection items with consistent styling. - The
home.njklayout wraps page content in a<heading-anchors>element to enable anchored headings and theme-aware typography.
- Set
ELEVENTY_ENV=productionwhen building for production to leverage Eleventy’s environment-based defaults. - Because Tachyons is loaded from a CDN, ensure outbound requests are allowed by your host or replace the
<link>inbase.njkwith a bundled stylesheet.
The home page runs renderPostList(collections.posts, ...) and Eleventy only adds templates to collections.posts when they are tagged posts. Make sure your post defaults include "tags": ["posts"]—for example, set it once in posts/posts.json so every Markdown file under posts/ inherits the tag.
Eleventy builds collections.posts in ascending date order by default (oldest first). The homepage reverses that list inside renderPostList, but any other consumer—like the navigation tree fed by collections.all | eleventyNavigation—will keep the oldest-first ordering unless you reverse it or define a custom collection that sorts newest-to-oldest.
MIT License - see LICENSE.