The site doesn't use resources from other domains and there are no referral links or cookies. Most pages only load two resources by default: the HTML itself and the stylesheet. The logo and other icons are stored as SVG data URIs in the CSS.
The only analytics are from my hosting provider, Netlify, which ostensibly uses log scraping. JavaScript is only run on-demand after clicking on the search icon.
Internals
This site is generated from folders containing Markdown files. The structure looks like this:
/pages/colophon.md
/pages/...
/articles/index.md
/articles/<year>/<month>-<day-<time>-<short-name>.md
/articles/...
/series/now/index.md
/series/now/<year>-<month>-<day-<time>-<short-name>.md
/series/...
/notes/<subtopic>/<note>.md
/notes/...
/static/style.css
/static/...
It's easy to update this site with a basic text editor, as opposed to a web interface normally found in blog engines.
Markdown makes adding emphasis, code, headings, and links easy. The notes have a front-matter section that provide the date they were last updated and the epistemic status and effort metadata. I wish they didn't need this (it's a bit clunky to have this information "above the fold"), but I haven't come up with a better way to assign metadata yet.
The site generator is called lift11 Because it converts Markdown to markup..
It's written in Zig with zero dependencies outside of the standard library.
Instead of a full-fledged Markdown parser, it supports a subset of Markdown called "Mindown."
Processing the most expensive note into HTML takes about 300µs on my MacBook Air M2 (1.2ms with search indexing).
The entire build takes roughly 40ms using a single CPU on my machine (60ms with search indexing), with no effort to issue I/Os concurrently or parallelize any computation, like the previous Rust version did.
Here's the output of lift when run on this site with search indexing:
notes: 95 ( 391.399KiB) 55.756 ms ( 86.8%) : 1.704 ms/elt, 7.020 KiBps
/ md: 95 ( 391.399KiB) 27.988 ms ( 50.2%) : 3.394 ms/elt, 13.985 KiBps
entries: 2 ( 2.221KiB) 0.886 ms ( 1.4%) : 2.258 ms/elt, 2.507 KiBps
pages: 6 ( 21.258KiB) 0.879 ms ( 1.4%) : 6.827 ms/elt, 24.189 KiBps
static: 5 ( 28.823KiB) 0.485 ms ( 0.8%) : 10.304 ms/elt, 59.399 KiBps
search: 97 ( 393.620KiB) 6.141 ms ( 9.6%) : 15.794 ms/elt, 64.093 KiBps
total: 108 ( 443.701KiB) 64.198 ms (100.0%) : 1.682 ms/elt, 6.911 KiBps
uCPU: 26.075 ms ( 38.0%)
0.713 ms / 15.098 KiB: /notes/bicycle-safety
0.731 ms / 14.352 KiB: /notes/monitoring-electricity-usage-at-the-meter
0.758 ms / 14.904 KiB: /notes/books-i-want-to-read
0.815 ms / 11.758 KiB: /notes/the-rheem-proterra-hybrid-heat-pump-water-heater
1.221 ms / 13.387 KiB: /notes/web-reading-list
The site-out directory holds the HTML and CSS results of generating the website and is pushed to GitHub, which Netlify makes available across the internet.
The HTML and CSS are small enough to leave un-minified, so it's easier to inspect for curious visitors.
Search
Search is implemented with framework-less JavaScript that's injected into the document in the search icon's onclick handler.
If JavaScript is disabled, the search icon is hidden.
The handler then presents the <dialog> search pane modally and loads a JSON list of all the documents available on the site.
As the user types in the dialog form, the JavaScript uses the Porter stemming algorithm to find its stem.
It also loads JSON with all stems with the same initial letter mapped to a list of documents and their rankings.
The rankings use the BM25 ranking algorithm and are generated by lift while parsing the Mindown documents.
Here's the pattern of JSON files in the search/ subdirectory:
/search/documents.json
/search/a.json
/search/b.json
/search/...
The 404 page also includes this HTML for a JavaScript-free site-specific search:
<form class="search" action="https://www.duckduckgo.com/" method="GET">
<input name="sites" type="hidden" value="mattwidmann.net">
<input name="q" type="text">
<input type="submit" value="Search">
</form>
Updated on 4 December 2025.