The question it answers is not "how do I put things online" but "will this still be
here in five years". Portfolio sites fail in one specific way: they get built once,
for an audience of recruiters, then the work moves on and the site does not — so it
gets rebuilt every two years, and the rebuilding is the actual cost.
This version therefore fixes the constraints first and lets everything else grow
underneath them. Content lives in files, not in a database. Pages are
generated, not assembled by hand. The visual system is small enough to remember.
Those three decisions account for almost every other choice here.
data/ identity, papers, project metadata, hobbies, rooms and keys
content/notes/ note bodies
content/projects/ case-study bodies
Adding a project is one .mdx file. Adding a note is one .mdx file. No component
is edited to add content. Today that is 28 routes, 42 components and 22 lib modules
on 13 runtime dependencies — none of which is a state management library.
The seven items in the header (Home · Projects · Academic · Notes · Hobbies · Wall ·
Letter) are not in that order by accident: the order is itself an argument. It is
simultaneously the numbering of the home page's sections, the printed number on each
page, and the order in the sitemap. Moving one item means changing four places. That
rule is written into README, because it is the thing a later hand is most likely to
break without noticing.
Bilingual content does not use an i18n library. One document in content/ is two
files: <slug>.mdx in Chinese, <slug>.en.mdx in English. Two reasons: front
matter has exactly one home and cannot contradict itself, and two bodies cannot be
truncated by a separator someone forgot to close. Chinese is the language this site
is written in first; English is allowed to arrive later.
When the English file does not exist yet, the page shows the Chinese body twice over
rather than showing half an English one — untranslated is honest, badly translated
is not. The same rule governs placeholders: a link marked as a placeholder is not
published, because it cannot be told apart from a real one.
The concept is a digital cabinet of curiosities, or an archive: paper tones, hairline
rules, filing numbers, serif headings against monospaced metadata. What that produces
is mostly a list of prohibitions, written down so later changes have something to
argue against — no gradients, no glow, no glassmorphism, no particles, and square
corners, because a rounded card is the first step toward becoming a dashboard.
Every theme colour is defined in one theme block, so the whole site can be recoloured
from one place.
Beyond the public pages there are a few doors, each with its own key: a private
drive, a studio, a set of tools, and an owner's desk that carries the wall's
moderation and the message inbox.
Two rules hold that part together. The door is a server decision: every protected
route renders the challenge instead of the room, so the room's markup never enters
what the server sends to the browser, and every protected API checks again on its own.
Failure falls closed: an unconfigured key means an empty room with a note, never a
room with a default key in it. The key register lives in a directory that is not in
version control, and the permission split is documented: one key opens any room and
is remembered, every other key lasts only for the session.
This page does not print their addresses. A locked room gets no signpost — no link, no
redirect, no navigation entry, no mention in prose. Addresses that were public once are
kept alive with a permanent redirect; addresses about to be locked deliberately return
404. A redirect is a machine-readable map for crawlers, not a favour to whoever wanted
the door shut.
What is deliberately missing is as much as what is here: accounts, a database, file
uploads, real authentication. Each of them has a page and an interface, and each would
have been the wrong thing to build before the structure underneath had proven it can
carry the content. Empty pages do not fake it with grey boxes either — they print a
table of contents saying what will be filed there, because anything listed on a page
has to have a page.
The order of work was: structure, then the design system, then pages, then content,
then the parts that are actually fun. Writing two real notes before settling the
layout changed the layout more than any amount of staring at it did.
The documentation was written too: README runs to twelve sections, from theme and
language all the way to "what is still a placeholder". It exists so the next version is
easier to write than this one, not as a formality.
What is not on this page
The source repository and the deployment pipeline. This page is about the site's
judgements, not its operations.
It also does not need a screenshot — you are looking at it.