A Website With Rules
The constraints behind this site, and the mistakes they caught
Abstract
This note is about the system you are currently reading. It is a static site with no framework on the client, no tracker, and about 1.3 kilobytes of JavaScript, which switches the theme. That is not the interesting part. The interesting part is that it was built under a handful of hard rules, and the rules turned out to be load-bearing: they forced design decisions I would not have reached by taste, they made one genuine misrepresentation impossible to ship, and in the one place a rule had to bend, bending it in public cost less than quietly abandoning it. Written as an engineering note rather than a tour, because a tour of one's own website is not worth anyone's time.
Status of This Document
A living document, revised as the site changes. Everything described here is running in production at the address in the footer; nothing is aspirational. The decision records this note summarises live in the site's own repository, which is private, so the summaries here are the public version.
1. Why this is worth writing down ¶
A personal website is the most-built and least-documented category of software there is. Everyone makes one; almost nobody writes down why theirs is shaped the way it is, because the honest answer is usually that a template decided.
I had a specific reason to decide deliberately. The rest of this series argues that I work to a set of standards, and standards asserted on a page are worth very little. This site is the one system I have shipped end to end where every decision was mine, which makes it the cheapest available test of whether those standards survive contact with a real build. If they do not hold here, on a project with no deadline, no client and no legacy code, the claim that they hold elsewhere is not worth much.
The site is not evidence because it looks a certain way. It is evidence because it was built under rules that could have been broken quietly, and were not.
2. The shape, and what it rejected ¶
The first decision was the genre. I mocked up five directions with real content in each, because arguing about typography in the abstract is a waste of an afternoon: a literal arXiv preprint, a journal spread, a Tufte-style page with margin notes, an RFC-style plain technical report, and a modern research-article layout.
What shipped is a fusion of two of them. The document furniture is from IETF RFCs: the header block of labelled fields, the numbered sections, the status-of-this-document box, the RFC 2119 keywords in the method section. The typographic register is from arXiv: serif prose, centred title block, an abstract, a real reference list. Prose speaks serif; apparatus speaks monospace. That single split is the whole design system, and once it was stated, most subsequent questions answered themselves.
A photograph was among the last things added, and the interesting part was where it could not go. A portrait above the title converts a technical document into a personal homepage in a single move: nothing about that layout is badly made, and the genre changes anyway. Technical publishing settled this long ago, so the site borrows the settlement. Journals close an article with an author biography, a small photograph beside a short third-person note, after the references; this site does the same at the foot of its first note, which means a reader meets the work before the person. The same photograph is deliberately absent from the CV PDF, because that file travels into hiring processes where photographs are discouraged.
Three of the five were rejected for reasons worth recording. The literal preprint was the most memorable and the most costume: justified serif at length is punishing to read on a phone, and a website pretending to be a PDF is a joke that stops being funny on the second visit. The Tufte layout is beautiful and its margin collapses on mobile, which is where most readers are. The modern research-article layout was the safest and the least distinguishable from every other technical personal site, which is a real cost when the point is to be remembered.
3. One record, two genres ¶
The hardest engineering problem on this site is not the design system. It is that a curriculum vitae has to exist twice, in two genres, and must never disagree with itself.
On the site, the CV is a document in this series: the same header, the same section numbering, the same typography. But a recruiter or an admissions committee does not want a web page. They want a one-page PDF in the format their whole field uses, which they can download, forward and skim in twenty seconds. Those are genuinely different artifacts with different conventions, and the obvious approach, maintaining both, guarantees that one drifts. The drifted one is always the copy someone forwards.
So the content lives once, in a plain data module, and is rendered twice. The site page is generated from it by the same layout as every other note. The PDF is generated by filling a LaTeX template with it and compiling with pdflatex, so the resume is a genuine LaTeX document with real paragraph breaking rather than a web page printed to paper.
4. Rules that can fail the build ¶
A rule nobody enforces is a preference. Two of the rules here are enforced by the build refusing to run.
The PDF is a committed binary, which means it can silently fall behind the data it was generated from. So a check hashes the data module and the template and compares that against what was recorded when the PDF was last built. If they differ, the build stops with a message naming the command that fixes it. This blocks deployment, including deployment of unrelated changes, which is an annoyance I accepted deliberately: a wrong CV in someone's inbox is worse than a five-minute delay, and the delay has a one-line fix.
The second is an audit that runs over the built output rather than the source, since the built output is what a reader receives. It resolves every internal link and every same-page anchor, checks that each page has exactly one top-level heading and no skipped heading levels, verifies that every image and inline diagram carries a text alternative, computes the contrast ratio of every colour pair in both themes against the WCAG threshold, and counts the JavaScript. It has caught dead links and a heading-level skip that reading the source would not have revealed.
- pages
- 10 routes, all static, counted at build time
- type
- 198 KB of self-hosted woff2, the largest thing shipped
- stylesheet
- one file, no preprocessor
- javascript
- 1,318 bytes inline, 0 external, 0 third-party
- trackers
- none, which is why the number above is exact
5. Where a rule bent ¶
The rule was no client-side JavaScript. It lasted until the first genuinely reasonable request: readers wanted to choose a theme rather than inherit whatever their operating system decided.
There is no honest way to do that without JavaScript. A theme that respects an explicit choice needs to store the choice and apply it before the first paint, and CSS cannot store anything. The options were to refuse the feature, to fake it with a CSS-only trick that loses the setting on the next page, or to bend the rule.
I bent it, and then made the bend visible. The site now carries about 1.3 kilobytes of inline JavaScript, and the colophon at the foot of every page says so in as many words: the only JavaScript on this site switches the theme. That sentence is worth more than the rule was. It converts an unverifiable claim of minimalism into a specific factual one that any reader can check with view-source, and it makes the next feature request expensive in a useful way, since adding a second script would require editing a sentence on every page.
A constraint you have to publicly amend is a constraint you will think carefully before amending again.
This is also why there is no analytics on the site, and why a piece of structured metadata that would have helped search engines was left out: it ships as a second script tag, and the credibility of the sentence in the footer was worth more than the indexing.
6. What the rules caught ¶
Four errors, none of which I would have found by looking harder.
An author list that misrepresented my position
The resume abbreviated long author lists to save space, in the ordinary academic style of naming a few authors and adding et al. The abbreviation kept the first two names and mine. On a paper where I am the eighth author, that reads as third. Nobody would have called it a lie, and it was one: author position is a claim about contribution, and dropping the people between the front of the list and my name inflates it. The rule that the PDF and the page must state the same record made the discrepancy visible the moment they were compared. The abbreviation is gone; both now carry the full list.
119 kilobytes of nothing
The site shipped two font files whose names implied different weights. A checksum showed they were byte-identical: the same variable font, duplicated. Deleting one cut the total payload by nearly a third. Investigating that also settled a question I had been guessing at, by reading the font's internal table directory to confirm it really was a variable font, which means the bold text is drawn from a weight axis rather than synthesised by the browser. On a site whose entire argument is typographic, faux-bold would have been quietly embarrassing.
Ninety-nine em dashes
A reader told me the prose read as machine-written, and pointed at the punctuation. Dense em dash usage is a recognisable tell. There were ninety-nine of them across the source. What made this a rule rather than a one-time edit is that a blind find-and-replace would have flattened the writing: an em dash sometimes introduces a list, sometimes wraps an aside, sometimes joins two sentences that should simply be two sentences. Each one was replaced by hand with the punctuation the sentence actually wanted. The prohibition is now written into the house style, alongside the note that en dashes in numeric ranges stay, because those are correct typography and a different character entirely.
A silent deployment failure that had not happened yet
An early deployment route would have served the site through a system that ignores directories beginning with an underscore, which is exactly where the compiled stylesheet lives. The failure mode is a site that loads with every word intact and no styling at all, which is easy to misdiagnose as a CSS bug. It was caught by reasoning about the platform before trusting it, and fixed with a one-byte marker file. That route was later abandoned for unrelated reasons, but the habit is the point.
7. What it costs ¶
An honest accounting, since a note that only lists wins is an advertisement.
- The build can block on something unrelated. Editing the CV data and forgetting to regenerate the PDF stops the next deployment, whatever that deployment was for. This is the guard working as designed, and it is still occasionally inconvenient.
- A binary in version control grows forever. The generated PDF is committed so the deployment platform never needs a TeX installation. At a CV's update rate this is nothing; it is still a thing that only ever gets larger.
- The design system is bespoke, so there is no ecosystem. Nothing can be installed to add a feature; every component is hand-written. That is the cost of the site looking like nothing else, and it is a real cost the day something complicated is needed.
- The publishing bar is high on purpose, and high bars slow you down. Every note has to survive the standards the site publishes about itself. That is the intent, and it means pages sit unwritten rather than shipping thin.
- Toolchain reality intrudes. Generating the resume depends on a local LaTeX installation, and a working installation can still crash on a five-line document. The generator now proves a compiler works before trusting it, which is three lines of code that exist entirely because an assumption was wrong once.
None of these has cost more than the alternative would have. The alternative, for most of them, was finding out later and in public.
- stack
- Astro, static output, no client framework
- type
- Source Serif 4 and IBM Plex Mono, self-hosted
- resume
- LaTeX, compiled locally, committed
- hosting
- built from a private repository, no public mirror of the source
- history
- one logical change per commit, no squashing
- decisions
- recorded before implementation, then summarised here
One thing this note deliberately does not do is quote its own statistics. Counts of commits, notes and decisions are true on the day they are typed and quietly false afterwards, and a document that reports stale numbers about itself has no standing to argue for measurement. What survives above is either a historical fact that cannot change, a property the design enforces, or a figure counted at build time.
Revision History
Typeset in Source Serif 4 and IBM Plex Mono, self-hosted. Built without a framework. The only JavaScript on this site switches the theme. No tracker, no analytics. Just documents. WN-004 · rev. 2 · 2026-08-08 · nikunjindoriya.com/projects/building-this-site/