A portfolio site has an unusual property: the reader is increasingly not a person. It is a model, a crawler, or a tool fetching the page to answer a question about you.
That changes what "good content" means. Prose written for a human reader can be full of things that are true but invisible.
The heading that was 24 KB of noise
This site's title is a slot-machine reel. Each letter spins through a pool of random glyphs and settles on the right one.
The markup put every glyph in the DOM as a text node. An aria-label carried the real name for screen readers, which is the accessible name and works fine.
But a crawler reading text content got the glyph pool — 24 KB of noise for the most important heading on the page. The name was in the accessibility tree but not in the text.
The fix was to render the reel from a data attribute through CSS content, and put the real name in the DOM as real text. The animation is untouched; the glyphs just stopped being text.
The same pattern applied to the statistics. They animated up from zero, which meant the served HTML said 0 original repos 0 upstream PRs. The number a crawler saw was zero, not the real count, and the real count was somewhere else entirely — in a JSON payload the crawler would have to guess was relevant.
Claims drift, checks do not
The project cards had four metric chips each. "Status: Live" was a claim about a deployment that might have been down that morning, with nothing on the page that would notice.
They are now checked. The server fetches the live URL and reports the status it actually got; the language and last-commit date come from the GitHub API. If a deployment is down, the card says so.
This is a small change with a disproportionate effect on how the page reads. "Live" from a chip is a claim. "Live" because a HEAD request returned 200 thirty seconds ago is a fact, and it is a fact that can be wrong, visibly, instead of quietly.
One source of truth for URLs
The site had the canonical origin hardcoded in four places: metadata, robots.txt, sitemap.xml, and the terminal prompt in the corner. They had already drifted — the metadata said "Ansh Singh - Full-Stack" with a hyphen where the source had an em dash.
They now all derive from one constant. Changing domain is a one-line change rather than a scavenger hunt, and the terminal prompt shows the host that actually serves the page rather than one that does not.
The part that took the longest to accept
Adding a llms.txt felt like cargo-culting a convention, and for a while it did. What changed my mind was looking at what it actually is: a plain-text answer to "who is this and what have they built", written for something that will not render a page.
It is not a replacement for the site. It is the same content in the shape that a reader who cannot see a page needs. The projects list, the stack, the contact details — all of it already existed in the constants the UI renders from, so it cannot go stale.
What I would tell my past self
The whole exercise came down to one question: is this true right now, and can a reader check it? If yes, it works for people and for machines. If it is only true in the sense that it was true when I typed it, it works for neither.
The slot-machine title was a great effect and a bad heading. The reel is still a reel. It just no longer lies to a crawler.