---
title: "The right architecture is the one sized to the problem."
url: "https://simonebova.com/en/colophon"
lang: "en"
author: Simone Bova
alternates:
  it: "https://simonebova.com/md/it/colophon"
  en: "https://simonebova.com/md/en/colophon"
  pl: "https://simonebova.com/md/pl/colophon"
---

# The right architecture is the one sized to the problem.

The problem here is precise: a personal archive that must be fast, cost zero, be readable by humans, crawlers and agents, and let itself be maintained on autopilot. Everything else on this page follows from that.

## Requirements → decisions

- **Lightweight:** Static HTML served from a CDN, client JS only where there's interaction. The bottleneck must be the reading, never the loading.

- **Zero overhead:** No server, no database, no CMS: nothing to patch, nothing that gets breached, nothing that calls at 3am. A personal archive must not demand operational attention.

- **Cheap:** Static build on a hobby plan: the marginal cost of a visit is ~zero, and so is the fixed cost. The money goes into the content, not the hosting.

- **Autopilot:** The site maintains itself: I say what's needed, [code-os](https://github.com/yempik-ai/code-os) builds it, the gate decides whether it ships. [agent-memory](https://github.com/yempik-ai/code-os) holds the rules and the definition of done, decisions are recorded as ADRs: a fresh agentic session is productive at the first prompt, without me acting as its memory.

- **Findability / tokens:** The data architecture is for agents too: typed data in src/content with predictable paths, one component per responsibility, names that say what they do. Anything is findable without burning tokens on exploration: minimum sufficient context is a property of the repo, not of the prompt.

- **SEO + GEO:** Static is crawlable by definition, and I use Next for what it's good at: Metadata API for canonicals and OpenGraph, typed sitemap and robots, OG images generated at build time with ImageResponse, self-hosted fonts via next/font (zero layout shift), JSON-LD in the layouts. For AI-mediated search: llms.txt and /api/dossier, from the same source as the pages.

- **Non-commercial:** No funnels, no popups, no third-party trackers (cookieless analytics and that's it). It's an archive to read, not a landing page to convert.

*// this page too: I said what I wanted, the harness built it, the gate approved it.*

## Architecture

- **CONTENT / SSoT:** src/content/*.ts: essays, principles, work: typed data, 3 languages

- **REACT SERVER COMPONENTS:** thin routes, SRP sections, client JS only where you interact

- **STATIC BUILD:** every route is HTML at build time, OG, llms.txt and JSON too

- **EDGE / CDN:** Vercel: zero runtime compute, ~0 marginal cost

the same content exits via /llms.txt and /api/dossier

- **GATE:** eslint, tsc --noEmit, next build. green, or it doesn't get committed

- **INVARIANTS:** a11y AA, reduced motion, one accent, SSoT-derived, i18n parity. regression = bug

## Decision record

### ADR-001: Zero dependencies, plus one

2026-07-12 · accepted

Runtime: Next + React + react-aria-components (widget accessibility: focus management, press semantics, focus traps: things you get wrong if you rewrite them). No Tailwind, CMS, UI kits, animation libraries. Consequence: minimal update surface, every line in the bundle is justifiable.

### ADR-002: Everything static, always

2026-07-12 · accepted

Every route (HTML, OG images, llms.txt, /api/dossier) is generated at build time and served from a CDN. No runtime compute: no cold starts, attack surface reduced to a minimum, ~zero marginal cost per request. The constraint is accepted: new content = new deploy.

### ADR-003: Content is a type, not a page

2026-07-12 · accepted

Essays, principles, work live in src/content as typed objects (SSoT). Archive, homepage, sitemap, OG, llms.txt and /api/dossier all derive from the same source. Consequence: a piece of content is written once and cannot diverge across formats.

### ADR-004: One accent

2026-07-12 · accepted

#E35B2D, everywhere; on the snow section a darker shade (#B8481C) for AA contrast on small text: same hue, not a second color. It holds in the easter eggs too: every snowfall has exactly one orange flake.

### ADR-005: Motion as decoration, never as a gate

2026-07-12 · accepted

The hidden state of the scroll reveal exists only with JS enabled (@media scripting) and motion allowed. JS off or prefers-reduced-motion: content intact. Animations are a layer above the content, not a precondition for reading it.

### ADR-006: Accessibility as an invariant

2026-07-12 · accepted

Skip link with a focusable target, visible focus ring, aria-current on navigation, AA contrast, external links announced, aria-live even for the easter eggs. Treated like tests: a regression is a bug, not a trade-off.

### ADR-007: Machine-readable

2026-07-12 · accepted

/llms.txt for agents, /api/dossier for curl, JSON-LD for crawlers: all generated from the same SSoT as the pages, so never out of sync. I serve the context about me myself, in the format of whoever consumes it.

### ADR-008: Three languages, one SSoT

2026-07-16 · accepted

IT, EN, PL as static routes (/it /en /pl), per-page hreflang, shared slugs. No middleware: detection is a static redirect. Cross-language parity is asserted at build time: a missing translation breaks the build, not the trust.

### ADR-009: The world is the banner

2026-10-28 · accepted

The site becomes SimoFree: the LinkedIn banner, live. The canvas is drawn once per size (no loop); everything you can read or press is DOM on top of it, through the same camera. Snow base, ink, one accent. The easter egg is a real, optional game.

### ADR-010: Two readers: people and agents

2026-10-28 · accepted

Every page has a Markdown twin generated from the same source, plus llms.txt, llms-full.txt and a read-only MCP server. The HTML stays canonical; the Markdown is noindex. The Human / Agent switch shows what an agent reads.

### ADR-011: Runs and piste

2026-10-28 · accepted

Cases are runs (shared slugs, stories without client numbers); ways to work together are piste (per-locale slugs, one searched phrase per page, difficulty coded by shape, never by color alone).

### ADR-012: SimoFree leaderboard verified by replay

2026-10-30 · accepted

The server never trusts a number. It issues the seed, the browser records inputs at a fixed 120 Hz step, and the server replays the descent with the same pure simulation to compute the score. Single-use tickets, a real-time floor, per-IP limits stored as an HMAC, positive scores only, top 100 on Upstash.

### ADR-013: One continuous motion: the sky in the footer

2026-11-08 · accepted

The run ends at night: the footer holds a dot-matrix sky (1-bit dither) with the yeti in orbit. The canvas is painted once per size; the yeti is a DOM layer moved with transform only, written only when its pose changes by a pixel. The loop runs only while the sky is on screen and nobody has paused it (WCAG 2.2.2). Under reduced motion the yeti stays still and the loop never starts. It is the exception to the no infinite animations rule; ADR-014 extends the same contract to the rest of the site.

### ADR-014: The world moves: one choreography, one switch

2026-11-08 · accepted

The masthead is the banner, alive: Simone drops in, launches off the cliff (a new trick each lap, a wipeout every fourth) and the yeti gives chase and loses. The choreography is a pure, tested function of time and opens on the banner's exact frame. The canvas stays still; only DOM layers move, by transform. Every ambient animation goes through one hook (on screen only, never in the background) and one site-wide pause. Scrolling is a descent: one gate per section along the nav. Torino, Milano and Warszawa on the horizon.

### ADR-015: The scrollbar belongs to the piste too

2026-11-08 · accepted

On mouse and trackpad the native bar becomes a thin rail: the thumb turns into a HUD box in the accent while you use it, and every numbered section is a named gate you can drag to or click. Native scrolling stays untouched (keyboard, wheel, touch, assistive tech); the rail only mirrors it and is aria-hidden. The native bar hides only after the rail has mounted, so with JS off or on touch the system bar stays. Scroll-linked, not ambient: one CSS variable per frame.

## For the machines

I serve the content about me myself, in the format of whoever consumes it. Agents read /llms.txt; if you prefer the terminal, there's a JSON endpoint generated from the same SSoT as the pages:

- [llms.txt](https://simonebova.com/llms.txt): concise site index.
- [llms-full.txt](https://simonebova.com/llms-full.txt): every English page in full.
- [Dossier JSON](https://simonebova.com/api/dossier): structured public profile.
- [MCP](https://simonebova.com/mcp): POST JSON-RPC over stateless Streamable HTTP, initialize then tools/list and tools/call.

*// same source, three formats: HTML for you, llms.txt for agents, JSON for curl.*

[simone@yempik.ai](mailto:simone@yempik.ai) · [Book a call](https://calendar.app.google/LKDrQPKGV2EAFCMN9)
