Personal Website Design

2026-07

Firstly, thank you for visiting my corner of the internet, I hope you stay a while and read a few essays. This essay is for anyone who wants to know about the layout and backend for this website. All code can be found on my github page.

This website is custom-built as a collection of static HTML files rather than using a website builder. At its core, it relies on a simple, automated pipeline built with Python that takes raw text and transforms it into the web pages you are reading now.

The Writing Environment

I write my essays as raw text files using LaTeX (via MiniTeX and TeXStudio). LaTeX was a recent discovery for me. For those unfamiliar, it is a typesetting system that uses plain-text markup to give you complete control over your document, as opposed to the drag-and-drop approach in Word. This is particularly useful for math blocks, integrating figures, and custom formatting. I am using it in a relatively simple way but the sky is the limit.

Each .tex file begins with a short block of metadata comments that the pipeline reads:

% ---
% title: My Essay
% date: 2026-07
% nodes: Reflections, Tools
% links: essays/another-essay.html
% ---

This frontmatter is how essays get tagged and connected to each other, which matters for the graph view and the version history described below.

The Build Pipeline

To get raw .tex files onto the web, I run a single Python script: python3 publish.py drafts/my-essay.tex. This triggers make4ht, a compiler that translates LaTeX syntax into HTML. The script then injects this content into a styled HTML template, which provides minimal CSS and calls MathJax to render any mathematical notation.

The script also reads the frontmatter metadata and updates a central essays.json file that tracks every essay. This JSON is then embedded directly into articles.html so the essays page works even when opened as a local file, without needing a web server.

Graph View

As I write, I tag my essays with one or more of four core themes (Tools, Work, Reflections, and Reading) and sometimes link them directly to each other. The network of connections can be explored in the Graph View on the Essays tab. This is an unabashed copy of Obsidian’s graph view, which I have been using for the past three years and highly recommend. The pipeline compiles essay metadata into a single JSON file, which is then read by force-graph to render an interactive force-directed network. Essays cluster around their themes, and edges connect related pieces of writing.

Version History

Some essays evolve significantly after their first publication. To make this visible to readers, each essay has a version history slider that appears just above the text when there is something to compare. Dragging the slider left reveals an earlier draft, and releasing it fades the content out and replaces it with the old version.

The mechanism is lightweight and requires no backend. Every meaningful revision is committed to git with a message beginning publish:, for example publish: rewrote the opening section. When a reader opens an essay, a small JavaScript block quietly queries the GitHub API for the commit history of that specific file, filters to commits with this prefix, and builds the slider from them. Fetching the actual content of an old version is done on demand by pulling the raw HTML from GitHub at the relevant commit hash, parsing it, and swapping in the body. The results are cached in memory so subsequent moves are instant.

Commits that do not carry the publish: prefix (typo fixes, formatting tweaks) are invisible to the slider. This keeps the version history intentional: it surfaces genuine drafts rather than every small edit. If no publish: commits exist for an essay at all, the slider stays hidden entirely.

A highlight changes toggle sits next to the slider label when viewing the current version. Enabling it compares the current essay against the most recently published version, wrapping added paragraphs in green and struck-through removed paragraphs in red. The underlying mechanism is a longest-common-subsequence diff run on the paragraph blocks, preserving all HTML formatting in unchanged sections.

Hosting and Analytics

Because the pipeline outputs plain, static HTML, the website requires virtually no computing power to run. There are no databases to query or servers to maintain. I host the site through Porkbun with the files served via GitHub Pages.

For viewership tracking I wanted to avoid invasive cookies. I embedded a tiny snippet from GoatCounter, an open-source, privacy-friendly analytics tool. It logs only anonymous page views with no cross-site tracking or saving of personal information.

I hope you enjoyed visiting. I found this very satisfying to build. Why not check out the graph view in the Essays tab, or go back to the Home tab to read a random essay?