# Design-as-Code: tokeny jako standard UI w platformie agentowej

> Tokeny zamieniają decyzje wizualne w jedno, audytowalne źródło prawdy. Dlaczego deterministyczną warstwę UI da się powierzyć agentowi, a UX zostaje przy człowieku w pętli.

URL: https://eiac.dev/blog/design-as-code-tokeny-od-zera
Filar: Design-as-Code
Data: 2026-02-27
Tagi: tokeny, design-system, css, adp, design-as-code, human-in-the-loop

---

Kiedy ostatnio kłóciłeś się z kimś, czy ten guzik jest `#A8482A`, czy jednak `#A94A2B`? Ja swoje odkłóciłem — i dlatego kolory, typografię i odstępy trzymam dziś nie w pliku graficznym, tylko jako **dane**. To z pozoru drobna zmiana nośnika ma daleko idącą konsekwencję: decyzja wizualna, która jest danymi, daje się wersjonować, walidować i egzekwować jak każdy inny kod. A skoro tak, to można ją powierzyć maszynie do *stosowania*, zostawiając człowiekowi to, czego maszyna nie udźwignie: osąd.

Ten artykuł rozwija tokeny od zera, a potem stawia tezę dla platformy agentowej (ADP, którą opisujemy [od IDP do ADP](/blog/od-idp-do-adp)): **design-as-code to warstwa, w której platforma egzekwuje standardy UI maszynowo — a UX zostaje przy człowieku w pętli.** Sprawdzimy, czy ten podział jest prawidłowy, pokażemy gdzie się rozmywa, przedstawimy konkurencyjną koncepcję (generative UI) i damy macierz wyboru ścieżki wdrożenia.

<div class="callout">
<strong>Teza</strong>
<p>Tokeny czynią <em>deterministyczną</em> warstwę UI (kolor, odstęp, typografia, promień) maszynowo egzekwowalną — agent wybiera z zamkniętego zbioru, a audyt w CI odrzuca odstępstwa. Warstwa <em>osądu</em> (architektura informacji, przepływy, dobór komponentu, intencja dostępności) pozostaje przy człowieku. Granica nie biegnie więc dokładnie między „UI" a „UX", lecz między tym, co deterministyczne, a tym, co wymaga osądu.</p>
</div>

## Dlaczego tokeny

Token to nazwana wartość — `color.link = #A8482A` — której używają jednocześnie strona, komponenty i materiały marketingowe. Zmiana w jednym miejscu propaguje się wszędzie. To samo, co Infrastructure-as-Code zrobił z serwerami — zamienił ręcznie strojone, nigdy nie identyczne maszyny w odtwarzalną, audytowalną konfigurację — tokeny robią z decyzjami wizualnymi: przestają być „bo ktoś tak kiedyś kliknął w Figmie", a stają się reprodukowalnym faktem w repo.

Wartość tokenów rośnie wprost proporcjonalnie do liczby miejsc, w których ta sama decyzja musi być spójna: light/dark, wiele marek, web/iOS/Android, aplikacja i landing. Bez tokenów każde z tych miejsc dryfuje niezależnie. Z tokenami dryf jest wykrywalny i odwracalny.

## Anatomia: trzy warstwy tokenów

Dojrzały zbiór tokenów to nie płaska lista, lecz trzy warstwy pośrednictwa — i to właśnie pośrednictwo daje siłę.

1. **Prymitywy (primitive / global)** — surowa paleta faktów: `--ds-rust-600: #A8482A`, `--ds-space-2: 8px`. Bez znaczenia, sama wartość.
2. **Tokeny semantyczne (alias)** — nadają prymitywom rolę: `--color-link: var(--ds-rust-600)`, `--space-inset-sm: var(--ds-space-2)`. To tu mieszka intencja („to jest kolor linku"), nie konkretny hex.
3. **Tokeny komponentu** — opcjonalna warstwa najbliżej UI: `--button-bg: var(--color-link)`. Komponent nigdy nie sięga do prymitywu ani do surowej wartości.

```json
// W3C DTCG: prymitywy i alias ($value/$type, alias przez {ścieżka})
{
  "ds": {
    "rust": { "600": { "$value": "#A8482A", "$type": "color" } },
    "space": { "2": { "$value": "8px", "$type": "dimension" } }
  },
  "color": {
    "link": { "$value": "{ds.rust.600}", "$type": "color" }
  },
  "space": {
    "inset-sm": { "$value": "{ds.space.2}", "$type": "dimension" }
  }
}
```

```css
/* Ta sama hierarchia w CSS — trzy warstwy pośrednictwa */
:root {
  --ds-rust-600: #A8482A;        /* prymityw  */
  --color-link: var(--ds-rust-600);   /* semantyka */
}
.button { color: var(--color-link); } /* komponent */
```

Pośrednictwo jest tym, co ratuje skórę: gdy marka zmienia odcień, podmieniasz **jeden** prymityw; gdy dochodzi dark mode czy druga marka, przepinasz **warstwę alias** — komponenty nie wiedzą o niczym. Płaska lista hexów takiej operacji nie przeżywa.

## Standard, nie dialekt: W3C DTCG

Do niedawna każde narzędzie miało własny format tokenów. To się zmieniło: [Design Tokens Format Module](https://www.designtokens.org/tr/) grupy [W3C Design Tokens Community Group](https://www.w3.org/community/design-tokens/) osiągnął [pierwszą stabilną wersję (2025.10)](https://www.w3.org/community/design-tokens/2025/10/28/design-tokens-specification-reaches-first-stable-version/) — wendor-neutralny JSON z polami `$value`/`$type`, aliasami, theming/multi-brand i nowoczesnymi przestrzeniami koloru (Display P3, Oklch, CSS Color 4). Trzymanie się standardu, zamiast formatu jednego dostawcy, to dokładnie ta sama zasada, którą stosujemy wobec [licencji i suwerenności](/blog/open-source-a-suwerennosc): unikasz zamknięcia.

Ekosystem narzędziowy zna już ten format. W praktyce sięga się po [Style Dictionary](/katalog/style-dictionary) (transpilacja jednego źródła do CSS/iOS/Android/Flutter), [Tokens Studio](/katalog/tokens-studio) (pomost Figma ↔ repo), a do dokumentacji i izolowanego rozwoju komponentów [Storybook](/katalog/storybook); całość projektowa może żyć w otwartym [Penpot](/katalog/penpot). Wspólny mianownik: **tokeny są źródłem, a kod i materiały są generowane** — nie odwrotnie.

## Tokeny jako guardrails dla agenta

Tu wchodzi platforma agentowa. Gdy interfejs pisze (lub współpisze) model, pojawia się problem, którego nie ma przy człowieku z dobrą pamięcią zespołową. Asystent kodujący nie *odpytuje* design systemu — on **generuje prawdopodobnie wyglądające wartości**. W jednej sesji potrafi podjąć 200–300 mikrodecyzji wizualnych (padding, odcień, promień), każda z osobna sensowna, a w sumie niespójna; a następna sesja nie pamięta poprzedniej i zgaduje od nowa ([opis problemu i metoda — Hardik Pandya](https://hvpandya.com/llm-design-systems)).

Trzy słabości modeli i ich tokenowe przeciwlekarstwa:

- **Fabrykuje wartości** → daj **zamkniętą warstwę tokenów**: agent wybiera z `var(--color-link)`, a nie wymyśla `#1D4ED8`. Nie ma „złego niebieskiego", bo jest tylko jeden.
- **Nie ma pamięci między sesjami** → daj **pliki spec w repo** (foundations + komponenty), które model czyta na starcie każdej sesji. Decyzję podjął człowiek raz; model ją *odczytuje*.
- **Nie czyta intencji ze źródła** → **audyt w CI**: skrypt skanuje CSS, a każda surowa wartość to błąd ze wskazaniem właściwego tokenu i `exit 1`. Czego nie da się scalić, tego nie ma.

```bash
# Bramka tokenowa w CI: zero surowych wartości w UI
$ npm run token-audit
src/components/Nav.css
  ✗ L42: zakodowany #1868DB → użyj var(--color-link)
  ✗ L78: surowy 12px w padding → użyj var(--space-inset-sm)
Errors: 2   # exit 1 → PR nie przechodzi
```

To jest dokładnie ten sam ruch, co [deterministyczny szkielet ADP](/blog/deterministyczny-szkielet-adp): nie ufamy modelowi „że będzie ładnie", tylko zamykamy go w polityce, która jest [policy-as-code](/blog/policy-as-code-dla-zespolow) i bramką w pipeline. Smak człowieka wchodzi raz — do tokenów i specyfikacji — a model stosuje go mechanicznie. Tokeny są więc dla UI tym, czym OPA dla wdrożeń: zamkniętym zbiorem dozwolonych decyzji.

<figure>
<svg viewBox="0 0 760 210" role="img" aria-label="Potok warstw tokenów: prymitywy do tokenów semantycznych do komponentów, na końcu bramka audytu w CI; człowiek ustawia tokeny raz, agent stosuje je mechanicznie.">
  <g fill="none" stroke="currentColor" stroke-width="1.5">
    <rect x="12" y="92" width="150" height="58" rx="6"/>
    <rect x="206" y="92" width="180" height="58" rx="6"/>
    <rect x="430" y="92" width="150" height="58" rx="6"/>
  </g>
  <rect x="624" y="92" width="124" height="58" rx="6" fill="none" stroke="var(--color-rust)" stroke-width="1.5"/>
  <g font-family="'Space Grotesk', system-ui, sans-serif" fill="currentColor" font-size="14" text-anchor="middle">
    <text x="87" y="116">Prymitywy</text>
    <text x="296" y="116">Tokeny semantyczne</text>
    <text x="505" y="116">Komponenty</text>
    <text x="686" y="116" fill="var(--color-rust)">Audyt w CI</text>
  </g>
  <g font-family="'Space Mono', monospace" fill="var(--color-muted)" font-size="11" text-anchor="middle">
    <text x="87" y="136">#A8482A · 8px</text>
    <text x="296" y="136">--color-link</text>
    <text x="505" y="136">var(--…)</text>
    <text x="686" y="136" fill="var(--color-rust)">exit 1 = stop</text>
  </g>
  <g fill="none" stroke="currentColor" stroke-width="1.5">
    <path d="M168 121 H200"/><path d="M392 121 H424"/><path d="M586 121 H618"/>
  </g>
  <g fill="currentColor">
    <path d="M200 121 l-7 -4 v8 z"/><path d="M424 121 l-7 -4 v8 z"/><path d="M618 121 l-7 -4 v8 z"/>
  </g>
  <path d="M87 64 V90" fill="none" stroke="var(--color-rust)" stroke-width="1.5" stroke-dasharray="4 3"/>
  <path d="M87 90 l-4 -7 h8 z" fill="var(--color-rust)"/>
  <text x="95" y="58" font-family="'Space Grotesk', system-ui, sans-serif" fill="var(--color-rust)" font-size="12">człowiek: smak raz →</text>
  <text x="430" y="184" font-family="'Space Grotesk', system-ui, sans-serif" fill="var(--color-muted)" font-size="12" text-anchor="middle">agent: stosuje mechanicznie, audyt pilnuje</text>
</svg>
<figcaption>Tokeny jako guardrails: człowiek ustawia warstwę raz, agent wybiera wyłącznie z zamkniętego zbioru, a audyt w CI odrzuca surowe wartości.</figcaption>
</figure>

## Gdzie kończy się automat: weryfikacja tezy

Czy założenie „UI maszynowo, UX przy człowieku" jest prawidłowe? Źródła w większości je potwierdzają — ale z istotną korektą, którą trzeba uczciwie postawić.

**Co potwierdza tezę.** Praktyka pokazuje, że gdy tylko zamkniesz warstwę tokenów i dodasz audyt, jakość wizualna dziesiątej sesji agenta dorównuje pierwszej — czyli deterministyczna część UI faktycznie się automatyzuje. Po drugiej stronie, UX z udziałem AI jest dziś opisywany jako wzorzec **human-in-the-loop**: AI proponuje, człowiek zatwierdza lub koryguje, bo to człowiek odpowiada za zaufanie, prowadzenie użytkownika i nadzór ([wzorzec HITL w UX](https://www.aufaitux.com/blog/human-in-the-loop-ux/)). AI ma być współpracownikiem, nie zamiennikiem projektanta.

**Gdzie teza wymaga korekty.** Linia podziału nie biegnie czysto między „UI" a „UX". Część UI to wciąż osąd: *który* komponent użyć (modal czy inline message), jak ułożyć architekturę informacji, jak brzmi mikrokopia, jaka jest *intencja* dostępności (nie samo `aria-`, lecz sensowny przepływ dla czytnika ekranu). Tego model nie wyczyta ze źródła — ta wiedza „mieszka w głowach projektantów" i musi zostać spisana albo dostarczona przez człowieka. Dlatego trafniejsza granica brzmi: **deterministyczne (tokeny, audyt, stany komponentu) → maszyna; wymagające osądu (IA, przepływy, dobór, kopia, intencja a11y) → człowiek w pętli.** Sam zgodny token nie gwarantuje dobrego doświadczenia — gwarantuje tylko spójność.

To rozróżnienie ma też wymiar regulacyjny: nadzór człowieka nad istotnymi decyzjami i ślad audytowy to nie tylko dobra praktyka UX, ale i kierunek, w którym idzie [AI Act](/blog/ai-act-a-agentowy-sdlc).

## Koncepcja alternatywna: generative UI

Powyższe zakłada **statyczny** interfejs: tokeny i komponenty są ustalone, a agent wypełnia je w czasie budowy. Istnieje jednak inna szkoła — **generative UI (GenUI)**: interfejs nie jest z góry zaprojektowany, lecz **składany przez AI w czasie działania**, dopasowany do kontekstu i intencji użytkownika ([przegląd GenUI](https://www.builder.io/blog/designing-generative-ui-in-an-agent-native-world)). Zamiast kodować każdy wariant ekranu, projektant ustawia *guardrails* — system prompt, model intencji i **kuratorowany katalog komponentów** — w których AT generuje UI na bieżąco.

Co istotne dla naszej tezy: nawet GenUI nie znosi standardów — przesuwa je. Nadal potrzebuje zamkniętego katalogu komponentów i tokenów jako budulca; zmienia się tylko *moment* składania (runtime zamiast build-time). Spotykane są trzy tryby, o rosnącym ryzyku:

- **Statyczny (parametryczny)** — AI wypełnia z góry zaprojektowane sloty danymi. Przewidywalny.
- **Deklaratywny (z rejestru)** — AI komponuje UI z zamkniętego rejestru komponentów. Zwykle najlepszy kompromis elastyczność/niezawodność.
- **W pełni generatywny** — AI emituje surowy HTML/CSS. Maksymalna elastyczność, maksymalne ryzyko (niespójność, halucynacje komponentów, bezpieczeństwo).

GenUI płaci za elastyczność znanymi kosztami: spójność (każde wygenerowanie może wyglądać inaczej), wydajność (generowanie trwa), bezpieczeństwo (dynamiczny kod) i halucynacje. Dlatego nie jest „następcą" design systemu, lecz innym punktem na tej samej osi — z tym samym fundamentem tokenów pod spodem.

## Wybierz ścieżkę wdrożenia

Nie ma jednej słusznej drogi — jest spektrum, a wybór zależy od tolerancji ryzyka, skali i tego, jak bardzo interfejs musi się adaptować do użytkownika. Trzy realne ścieżki:

| Ścieżka | Kiedy ma sens | Rola agenta | Człowiek w pętli | Główne ryzyko |
|---|---|---|---|---|
| **A. Statyczny design system + tokeny** | Większość produktów; potrzeba spójności i audytowalności | Pisze kod w granicach tokenów; audyt go pilnuje | Ustala tokeny/spec, projektuje IA i przepływy, recenzuje | Sztywność; „złota klatka" przy nietypowych potrzebach |
| **B. Deklaratywny GenUI (z rejestru)** | Interfejsy mocno kontekstowe (asystenci, dashboardy dopasowane do roli) | Składa UI z zamkniętego rejestru w runtime | Projektuje rejestr + guardrails, definiuje intencje, nadzoruje | Niespójność między wygenerowaniami; wydajność |
| **C. W pełni generatywny** | Eksperymenty, prototypy, wysoce spersonalizowane nisze | Emituje surowy markup w runtime | Definiuje twarde bariery bezpieczeństwa, waliduje wyjście | Halucynacje, bezpieczeństwo, brak powtarzalności |

Reguła kciuka: **zacznij od A** (tokeny + audyt to fundament, który i tak przyda się w B i C), sięgnij po **B**, gdy realnie potrzebujesz adaptacji do kontekstu, a **C** trzymaj za barierą człowieka w pętli i poza ścieżką krytyczną. We wszystkich trzech tokeny pozostają wspólnym mianownikiem — różni się tylko, *kiedy* i *jak swobodnie* agent z nich korzysta. Mapuje się to wprost na [cztery poziomy agentowego wytwarzania](/blog/cztery-poziomy-agentowego-wytwarzania): im wyżej autonomia, tym mocniejsze muszą być guardrails i tym wyraźniejszy punkt, w którym decyzję zatwierdza człowiek.

## Pierwszy plik

Niezależnie od ścieżki, start jest ten sam — jeden plik, który staje się źródłem prawdy:

```json
{
  "color": { "link": { "$value": "#A8482A", "$type": "color" } }
}
```

Stąd generujesz CSS variables, motywy i dokumentację — wszystko z repo, wszystko audytowalne, wszystko gotowe, by agent z tego korzystał, a nie zgadywał.

## Podsumowanie

Design-as-code zamienia decyzje wizualne w dane, a tokeny — w trójwarstwowy, standaryzowany ([W3C DTCG](https://www.designtokens.org/)) zbiór, który platforma agentowa potrafi egzekwować maszynowo: zamknięta warstwa tokenów, pliki spec i audyt w CI sprawiają, że agent stosuje smak człowieka, zamiast go wymyślać. Teza „UI dla maszyny, UX dla człowieka" jest w rdzeniu prawidłowa, ale precyzyjniej brzmi: **deterministyczne dla maszyny, wymagające osądu dla człowieka w pętli.** Alternatywa — generative UI — nie znosi tego fundamentu, tylko przesuwa moment składania na runtime. Wybór ścieżki (statyczny DS, deklaratywny GenUI, pełna generacja) należy do Ciebie i Twojej tolerancji ryzyka — ale każda z nich stoi na tym samym fundamencie tokenów. Zacznij od jednego pliku tokenów i audytu w CI, a potem sam zdecyduj, jak daleko wpuścisz agenta. Polecam się tym pobawić. :)