Colophon / the engine room, open

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 (si apre in una nuova scheda) builds it, the gate decides whether it ships. agent-memory (si apre in una nuova scheda) 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

Decision record

  1. ADR-001accepted12 JUL 2026

    Zero dependencies, plus one

    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.

  2. ADR-002accepted12 JUL 2026

    Everything static, always

    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.

  3. ADR-003accepted12 JUL 2026

    Content is a type, not a page

    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.

  4. ADR-004accepted12 JUL 2026

    One accent

    #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.

  5. ADR-005accepted12 JUL 2026

    Motion as decoration, never as a gate

    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.

  6. ADR-006accepted12 JUL 2026

    Accessibility as an invariant

    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.

  7. ADR-007accepted12 JUL 2026

    Machine-readable

    /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.

  8. ADR-008accepted16 JUL 2026

    Three languages, one SSoT

    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.

  9. ADR-009accepted28 OCT 2026

    The world is the banner

    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.

  10. ADR-010accepted28 OCT 2026

    Two readers: people and agents

    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.

  11. ADR-011accepted28 OCT 2026

    Runs and piste

    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).

  12. ADR-012accepted30 OCT 2026

    SimoFree leaderboard verified by replay

    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.

  13. ADR-013accepted8 NOV 2026

    One continuous motion: the sky in the footer

    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.

  14. ADR-014accepted8 NOV 2026

    The world moves: one choreography, one switch

    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.

  15. ADR-015accepted8 NOV 2026

    The scrollbar belongs to the piste too

    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:

curl simonebova.com/api/dossier

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