Github Pages website.
Always a work-in-progress :).
blog/*.adoc— post sources (AsciiDoc);blog/*.html— generated bymake, committedblog/index.html— hand-maintained post table;blog/docinfo.html— shared<head>fragment- everything else (
index.html,links/,course_notes/,library/) — hand-written HTML, no build step
GitHub Pages serves these files as-is; no CI, no server-side build.
Rebuild and commit the .html with every .adoc change or the published site goes stale.
make # build all posts
./scripts/serve.sh # http://localhost:8080/ (PORT=9000 to override)
./scripts/watch.sh # rebuild on save; Ctrl-C to stop
make clean # delete generated blog/*.htmlTypical loop: watch.sh in one terminal, serve.sh in another.
Hot reloading: rebuild only.
watch.sh regenerates HTML on save (via entr, or inotifywait on Linux); nothing pushes to the browser, so reload
the page yourself. make is incremental.
Gems are managed by bundler and pinned in Gemfile.lock, so every machine builds with identical versions.
You supply the ruby; the repo supplies the rest.
bundle install # installs into ./vendor/bundle (gitignored)What your environment must provide:
- ruby >= 2.7 and bundler. p620 runs 3.2.3 (EOL 2026-04-01); this Mac runs MacPorts 4.0.7.
- a JavaScript runtime —
asciidoctor-katexrenders math throughexecjs. Node, or macOS’s built-in JavaScriptCore, will do; without one, only posts containing math fail. - a UTF-8 locale (
LANG=en_US.UTF-8or similar). Under a US-ASCII locale execjs dies on posts with non-ASCII characters. - optional:
entr, or Linuxinotify-tools— forwatch.shonly
.bundle/config (committed) sets BUNDLE_PATH=vendor/bundle, so gems land in the repo rather than in a system gem dir
you may not own. make invokes bundle exec asciidoctor.
Two notes on the pins, both learned the hard way:
- rouge must be 4+. rouge 3 ships different
githubtheme CSS, which is inlined into every post with a source block, so building with it rewrites all of them. The lockfile makes this moot; the Gemfile constraint keeps it so. loggeris declared explicitly. Ruby 4.0 moved it out of the default gems, but asciidoctor 2.0.26 still requires it without declaring the dependency, sobundle exec asciidoctordies without it.
KaTeX math and rouge highlighting render at build time, so posts need no JavaScript to view. Only the KaTeX stylesheet
comes from a CDN, via blog/docinfo.html.
Builds are reproducible (-a reproducible), so rebuilding a post with no source change produces no diff.
Without it asciidoctor stamps the build time into every footer.
pre-commit install- flowmark — formats
.mdat 120 columns - build blog — runs
make -B all. If that changes any generated HTML, pre-commit fails the commit with “files were modified by this hook”; the rebuilt files are already there, sogit add blog/*.htmland commit again.-Bforces the rebuild because git does not preserve mtimes, which makes make’s staleness check unreliable here.
-
Create
blog/<snake_case_name>.adoc:= Post Title :title: Post Title | Arthur Ozga :author: Arthur Ozga :revdate: yyyy-mm-dd :docinfo: shared
-
Add a row to
blog/index.html(newest first,yyyymmdd). -
make, check with./scripts/serve.sh, commit the.adocand the.html.
.md files are formatted by flowmark at 120 columns via a pre-commit hook.
Install it with pre-commit install.