Colophon / maszynownia, otwarta

Właściwa architektura to ta zwymiarowana pod problem.

Problem jest tu precyzyjny: osobiste archiwum, które ma być szybkie, kosztować zero, dać się czytać ludziom, crawlerom i agentom, i dać się utrzymywać na autopilocie. Cała reszta tej strony z tego wynika.

Wymagania → decyzje

Lekkość

Statyczny HTML z CDN, client JS tylko tam, gdzie jest interakcja. Wąskim gardłem ma być czytanie, nigdy ładowanie.

Zero overheadu

Żadnego serwera, bazy, CMS-a: nic do patchowania, nic, co można włamać, nic, co dzwoni o 3 w nocy. Osobiste archiwum nie może wymagać operacyjnej uwagi.

Tanio

Statyczny build na planie hobby: koszt krańcowy wizyty to ~zero, koszt stały też. Pieniądze idą w treść, nie w hosting.

Autopilot

Strona utrzymuje się sama: ja mówię, co trzeba, code-os (si apre in una nuova scheda) to buduje, gate decyduje, czy się wdraża. agent-memory (si apre in una nuova scheda) z zasadami i definition of done, decyzje zapisane jako ADR: świeża sesja agentowa jest produktywna od pierwszego prompta, beze mnie w roli pamięci.

Findability / tokeny

Architektura danych też jest dla agentów: typowane dane w src/content z przewidywalnymi ścieżkami, jeden komponent na odpowiedzialność, nazwy mówiące, co robią. Wszystko da się znaleźć bez palenia tokenów na eksplorację: minimalny wystarczający kontekst to właściwość repo, nie prompta.

SEO + GEO

Statyczne jest crawlowalne z definicji, a Next wykorzystuję do tego, co umie: Metadata API dla canonicali i OpenGraph, typowane sitemap i robots, OG images generowane w build time przez ImageResponse, fonty self-hosted przez next/font (zero layout shift), JSON-LD w layoutach. Dla szukających przez AI: llms.txt i /api/dossier, z tego samego źródła co strony.

Niekomercyjność

Żadnych funneli, popupów, trackerów firm trzecich (cookieless analytics i tyle). To archiwum do czytania, nie landing do konwersji.

// ta strona też: powiedziałem, czego chcę, harness ją zbudował, gate zatwierdził.

Architektura

Decision record

  1. ADR-001accepted12 LIP 2026

    Zero zależności, plus jedna

    Runtime: Next + React + react-aria-components (dostępność widgetów: focus management, press semantics, focus trap: rzeczy, które psujesz, jeśli piszesz je od nowa). Bez Tailwinda, CMS-a, UI kitów, bibliotek animacji. Konsekwencja: minimalna powierzchnia update'ów, każda linia w bundlu jest uzasadnialna.

  2. ADR-002accepted12 LIP 2026

    Wszystko statyczne, zawsze

    Każda route (HTML, OG image, llms.txt, /api/dossier) jest generowana w build time i serwowana z CDN. Zero compute w runtime: bez cold startów, powierzchnia ataku zredukowana do minimum, ~zerowy koszt krańcowy requesta. Ograniczenie zaakceptowane: nowa treść = nowy deploy.

  3. ADR-003accepted12 LIP 2026

    Treść to typ, nie strona

    Eseje, zasady, work żyją w src/content jako typowane obiekty (SSoT). Archiwum, strona główna, sitemap, OG, llms.txt i /api/dossier pochodzą z jednego źródła. Konsekwencja: treść pisze się raz i nie może się rozjechać między formatami.

  4. ADR-004accepted12 LIP 2026

    Jeden akcent

    #E35B2D, wszędzie; na śniegu ciemniejszy odcień (#B8481C) dla kontrastu AA na małym tekście: ta sama barwa, nie drugi kolor. Obowiązuje też w easter eggach: każda śnieżyca ma dokładnie jeden pomarańczowy płatek.

  5. ADR-005accepted12 LIP 2026

    Motion jako dekoracja, nigdy jako gate

    Ukryty stan scroll-reveala istnieje tylko przy włączonym JS (@media scripting) i dozwolonym motion. JS wyłączony albo prefers-reduced-motion: treść nietknięta. Animacje są warstwą nad treścią, nie warunkiem jej czytania.

  6. ADR-006accepted12 LIP 2026

    Dostępność jako inwariant

    Skip-link z fokusowalnym celem, widoczny focus ring, aria-current w nawigacji, kontrasty AA, linki zewnętrzne ogłaszane, aria-live nawet dla easter eggów. Traktowana jak testy: regresja to bug, nie kompromis.

  7. ADR-007accepted12 LIP 2026

    Czytelne dla maszyn

    /llms.txt dla agentów, /api/dossier dla curla, JSON-LD dla crawlerów: wszystko generowane z tego samego SSoT co strony, więc nigdy rozsynchronizowane. Kontekst o mnie serwuję sam, w formacie odbiorcy.

  8. ADR-008accepted16 LIP 2026

    Trzy języki, jeden SSoT

    IT, EN, PL jako statyczne route (/it /en /pl), hreflang per strona, wspólne slugi. Bez middleware: detekcja to statyczny redirect. Parytet między językami sprawdzany w build time: brakujące tłumaczenie psuje build, nie zaufanie.

  9. ADR-009accepted28 PAŹ 2026

    Świat to baner

    Strona staje się SimoFree: baner z LinkedIna, na żywo. Canvas rysowany raz na rozmiar (bez pętli); wszystko, co da się przeczytać lub kliknąć, to DOM nad nim, w tej samej kamerze. Śnieg, tusz, jeden akcent. Easter egg to prawdziwa, opcjonalna gra.

  10. ADR-010accepted28 PAŹ 2026

    Dwóch czytelników: ludzie i agenci

    Każda strona ma bliźniaka w Markdownie z tego samego źródła, do tego llms.txt, llms-full.txt i serwer MCP tylko do odczytu. HTML pozostaje kanoniczny; Markdown ma noindex. Przełącznik Człowiek / Agent pokazuje, co czyta agent.

  11. ADR-011accepted28 PAŹ 2026

    Zjazdy i trasy

    Case'y to zjazdy (wspólne slugi, historie bez liczb klientów); sposoby współpracy to trasy (slugi w każdym języku, jedna wyszukiwana fraza na stronę, trudność kodowana kształtem, nigdy samym kolorem).

  12. ADR-012accepted30 PAŹ 2026

    Ranking SimoFree weryfikowany przez powtórkę

    Serwer nie ufa liczbom. Wydaje seed, przeglądarka zapisuje wejścia ze stałym krokiem (120 Hz), a serwer odtwarza zjazd tą samą czystą symulacją i sam liczy wynik. Jednorazowe tickety, minimalny czas rzeczywisty, limity na IP zapisane jako HMAC, tylko dodatnie wyniki, top 100 w Upstash.

  13. ADR-013accepted8 LIS 2026

    Jeden ciągły ruch: niebo w stopce

    Zjazd kończy się nocą: w stopce jest niebo z kropek (dither 1-bit) z yeti na orbicie. Canvas rysuje się raz na rozmiar; yeti to warstwa DOM przesuwana tylko przez transform, zapisywana tylko gdy poza zmienia się o piksel. Pętla działa tylko, gdy niebo jest na ekranie i nikt jej nie zatrzymał (WCAG 2.2.2). Przy reduced motion yeti stoi, a pętla się nie uruchamia. To wyjątek od zasady zero nieskończonych animacji; ADR-014 rozszerza ten sam kontrakt na resztę strony.

  14. ADR-014accepted8 LIS 2026

    Świat się rusza: jedna choreografia, jeden przełącznik

    Nagłówek to żywy baner: Simone zjeżdża, skacze z nawisu (inny trik na każdym okrążeniu, wywrotka co czwarte), a yeti go goni i przegrywa. Choreografia to czysta, przetestowana funkcja czasu i zaczyna się dokładnie od klatki banera. Canvas stoi; ruszają się tylko warstwy DOM przez transform. Każda animacja tła przechodzi przez jeden hook (tylko na ekranie, nigdy w tle) i jeden przełącznik pauzy dla całej strony. Przewijanie to zjazd: jedna bramka na sekcję w nawigacji. Turyn, Mediolan i Warszawa na horyzoncie.

  15. ADR-015accepted8 LIS 2026

    Pasek przewijania też należy do stoku

    Na myszy i gładziku natywny pasek staje się cienką szyną: suwak w trakcie używania zamienia się w box HUD w kolorze akcentu, a każda numerowana sekcja to nazwana bramka, do której można przeciągnąć albo kliknąć. Natywne przewijanie zostaje nietknięte (klawiatura, kółko, dotyk, technologie asystujące); szyna tylko je odzwierciedla i jest aria-hidden. Natywny pasek znika dopiero, gdy szyna się zamontuje, więc bez JS albo na dotyku zostaje systemowy. Podąża za przewijaniem, to nie ruch tła: jedna zmienna CSS na klatkę.

Dla maszyn

Treść o mnie serwuję sam, w formacie tego, kto ją konsumuje. Agenci czytają /llms.txt; kto woli terminal, ma endpoint JSON generowany z tego samego SSoT co strony:

curl simonebova.com/api/dossier

// jedno źródło, trzy formaty: HTML dla ciebie, llms.txt dla agentów, JSON dla curla.