Design systém · v1

Grafy, které vyprávějí léčbu

Editorská teze celého systému zní: „Léčba obezity nikdy nekončí.“ Každá kazuistika obsahuje návraty hmotnosti — a právě ty jsou sdělením, ne chybou. Tento systém překládá tezi do vizuálního jazyka: pokles, návrat, nový zásah, otevřený konec. Publikem je pacient v 11 večer na telefonu, ne lékař. Má odejít s pocitem „to bych mohl být já“, ne „prohrávám soutěž“.

Graf je věta, nakreslená

Nestavíme „graf váhy v čase“. Stavíme argument. Každá vrstva grafu existuje jen proto, aby nesla část věty:

Část větyVizuální prostředek
„Léčili jsme…“pruhy intervencí pod křivkou, sdílená časová osa
„…a fungovalo to…“křivka se ohne až za začátkem pruhu — kauzalita je vidět
„…pak se váha vrátila…“návrat vlastní barvou — teplá, ne alarmující; nikdy skrytý
„…tak jsme zasáhli znovu…“další pruh, další ohyb — rytmus příběhu
„…a nekončíme.“otevřený kroužek na konci křivky, běžící pruh se šipkou

Pět pilířů storytellingu

01

Tvar křivky je teze

Zubatost není šum k uhlazení — je to samotné sdělení. Regainy se nevyhlazují, neschovávají a nebarví jako selhání.

02

Kauzalita je pointa

Čtenář musí vidět, že se křivka ohne po začátku intervence. Hover propojení a animace existují jen kvůli tomuhle.

03

Minimum není konec

Každý případ po minimu regainuje. Emoční vrchol nikdy nesmí ležet v nejnižším bodě — příběh končí otevřeně, „léčba pokračuje“.

04

Identifikace, ne obdiv

Default osy je % od výchozí váhy: pacient s 95 kg se najde v „−15 %“, ne v křivce ze 142 kg. Absolutní kg jsou přepínač.

05

Skupina, ne žebříček

Srovnání = kohortní obálka (medián + rozmezí), nikdy pojmenované linky přes sebe. Nikde neexistuje řazení podle výsledku.

Zamčená rozhodnutí (L1–L10)

Tahle rozhodnutí jsou závazná. Pokud si myslíš, že je některé špatně, otevři diskusi před implementací — neodchyluj se potichu.

  1. L1Veškerý pohyb řídí jeden skalár 0→1. Každá animovaná vlastnost je jeho čistou funkcí.
  2. L2Trend je hrdina; syrové denní body jsou jen slabý rozptyl za ním.
  3. L3Default osy Y je % změny od výchozí váhy; kg jsou přepínač.
  4. L4Osa Y nikdy nezačíná nulou.
  5. L5Regain úseky jsou viditelné a barevně odlišené — ne červeně, ne skrytě.
  6. L6Žádný případ se nikdy neřadí proti jinému. Žádný „nejlepší výsledek“.
  7. L7Srovnání = kohorta (grid + obálka), nikdy překryté pojmenované linky.
  8. L8Každá intervence nese dva popisky: lidský primární, klinický sekundární.
  9. L9Mobile-first. Desktop je rozšíření.
  10. L10Statický stav musí být úplný a správný dřív, než se přidá pohyb.

Barvy

Jediný zdroj pravdy je blok @theme v globals.css. V komponentách nikdy nesmí být hex — jen sémantické třídy (stroke-data, fill-card…). Rebrand pro klienta je pak změna jednoho řádku.

--color-data

#12b2a2

křivka, akcenty, kohortní obálka

--color-chrome

#3d0653

nadpisy, UI, zvýraznění, operace

--color-regain

#d98e32

návraty hmotnosti — teplá, ne alarm

--color-ink

#241f2b

hlavní text

--color-ink-muted

#6f6a78

sekundární text, osy

--color-grid

#eae6ee

mřížka, rámečky

--color-card

#ffffff

karty, chips, pozadí grafu

--color-surface

#fdfcfb

pozadí stránky — světlé (O1)

✓ AnoRegain kreslit --color-regain: teplý apricot čte se „kapitola“, ne „poplach“.

✕ NeČervená pro regain, tmavý režim jako default, nový hex přímo v komponentě.

Typografie a čísla

  • Písmo Geist (latin + latin-ext kvůli češtině); mono jen pro kódy.
  • Všechna čísla s tabular-nums — countery při animaci nesmí poskakovat: −20,5 kg · −14,6 %
  • Formát cs-CZ přes lib/format.ts: desetinná čárka, delty vždy se znaménkem (+2,1 / −20,5), osy bez desetin.
  • Datumy: v pruzích a stepperu „11/2017 – 12/2018“, v readoutu měsíc slovem („listopad 2019“), na ose jen roky.

Anatomie grafu — živá reference

Tohle je skutečná produkční komponenta CaseChart s referenčním případem (KAZ-001). Všechno níž je interaktivní: přehrávání, scrub, kapitoly, hover na pruhy, přepínač jednotek.

  • trend hmotnosti
  • období návratu hmotnosti
  • domácí vážení
  • měření v ambulanci
  • léčba pokračuje
  1. 2/2019 · plikace žaludku
  2. 6/2020 · návrat hmotnosti během pandemie
  3. 12/2022 · postupný návrat hmotnosti – běžná součást léčby

-40,3 kg

celková změna hmotnosti za 8,3 roku (-28,4 %) — a léčba pokračuje

  1. 1Syrová domácí vážení — rozptyl, 15 % opacita, nikdy v popředí (L2)
  2. 2Trend — LOESS přes 45denní časové okno, tyrkysově
  3. 3Úseky návratu — stejná linka, barva regain (L5)
  4. 4Ambulantní měření — kroužky s fialovým okrajem
  5. 5BMI osa vpravo — lineární přeškálování kg, jedna křivka, dvě osy
  6. 6Pruhy intervencí — řádek na kategorii, sdílená osa X
  7. 7Beat chips — delty, BMI, poznámky; kolizní layout s vodicími linkami
  8. 8Moment operace — svislá čárkovaná; křivka se ohýbá za ní
  9. 9Otevřený konec — kroužek „léčba pokračuje“; nikdy plná tečka
  10. 10Transport — play/pauza, scrub, kapitoly odvozené z intervencí

Trend a vyhlazení

Zdrojová data jsou ~2 000 denních vážení — syrově vykreslená jsou čmáranice. Trend počítá LOESS: lokální lineární regrese s tricube váhami přes časové okno (ne okno po indexech — data mají mezery). Lokálně-lineární fit drží koncové body a zlomy bez zpoždění klouzavého průměru, a zlomy jsou přesně to, kde se vypráví příběh.

Šířka pásma vyhlazení

Default systému: trajektorie s čitelnými zlomy — návrat má vlastní barvu.

Řídká data (< 20 bodů) — vyhlazení se vypne (O3)

Spojené zvýrazněné body místo falešně hladké křivky. Fallback je automatický — komponenta se rozhodne sama podle počtu měření.

  • Default šířka pásma 45 dní — trajektorie, ne vlnovka.
  • Pod 20 bodů se vyhlazení automaticky vypne a kreslí se spojené zvýrazněné body (O3). Případ KAZ-005 je toho živou ukázkou.
  • Detekce návratů: hystereze nad vyhlazeným trendem — vzestup ≥ 2,5 kg od lokálního minima otevírá úsek, pokles ≥ ½ prahu ho zavírá. Drobné vlnky úsek nerozbijí.

Anotační systém

  • Dvojí popisky (L8): primárně lidsky („injekce na hubnutí“), klinicky na hover/tap („Liraglutid 3,0 mg · 3,0 mg 1× denně“). Pacient nesmí potřebovat slovník.
  • Hover propojení: najetí na pruh zvýrazní jeho úsek křivky fialovou a ztlumí zbytek. Tohle je jádro layoutu — ohyb za pruhem.
  • Kolize chips: preferovaná pozice nad kotvou na trendu; při překryvu se chip posouvá po 22px krocích nahoru, pak pod bod. Posunuté chips dostanou vodicí linku. Překryv není nikdy přípustný — na žádném breakpointu.
  • Mobil (L9): pruhy se skládají do svislého stepperu pod grafem — chronologické akty s tečkami podle kategorie, NOTE beats vložené mezi ně. Nikdy jen zmenšený Gantt.
  • Bodové zákroky: operace je diamant + čárkovaná svislice; nemá interval, takže nikdy neukazuje „0 kg“ — píše se „jednorázový zákrok“ a efekt nese DELTA beat za ním.

Motion — jeden skalár řídí všechno

usePlayhead vrací jediný MotionValue 0→1 (L1). Neexistuje timeline orchestrace: každá animovaná vlastnost je čistá funkce skaláru, takže scrub vzad nemůže nic rozbít a reduced-motion je prostě „skalár = 1“.

Mapa aktů

osy
časová osa · linka se kreslí · pruhy rostou · chips naskakují
souhrn
00,040,961
VlastnostČistá funkce času playheadu t
odkrytí vrstev datclipRect.width = x(t)
tečka + counterx(t), y(trend(t)), text z téže interpolace
růst pruhuwidth = clamp(x(min(t, end)) − x(start))
puls operacescale = 1 + 0,5·e^(−(t−t₀)/10 dní)
chipfade končí přesně v momentu beatu
souhrnopacity v aktu 3 (p > 0,96)
  • Autoplay jednou při scrollu do view. Nikdy loop.
  • prefers-reduced-motion: okamžitě kompletní finální stav, transport se vůbec nevykreslí. Žádná „rychlejší animace“.
  • Vrchol není minimum. Časování je lineární a příběh pokračuje za minimem k otevřenému konci. Pokud animace nedokáže ukázat „ohyb za intervencí“, škrtá se — jiné ospravedlnění nemá.

Kohorta a browse

Filtry (pohlaví, věk, vstupní BMI, druh léčby) vedou na grid karet + souhrnnou obálku: medián a mezikvartilové rozmezí v % od výchozí váhy, na ose „čas od začátku léčby“. Obálka se kreslí jen tam, kde má data ≥ 3 případy — nikdy nedegraduje na jednotlivé linky.

Jak probíhá léčba u lidí jako vy (8 příběhů)

  • střední průběh (medián)
  • rozmezí poloviny případů
  • Karta nikdy nenese číslo výsledku — grid s deltami je žebříček (L6). Tvar křivky mluví sám: pokles, návraty, otevřený kroužek.
  • Neexistuje řazení podle výsledku; pořadí je ediční (dle PID).
  • Na klienta jdou jen štíhlé souhrny (~150 bodů trendu na případ), nikdy plná měření.

Datový kontrakt

Zdroj pravdy je zod schéma v data/schema.ts. Reálná měření budou přicházet z platformy Čas pro zdraví; případ je JSON:

{
  "id": "stefurak", "pid": "KAZ-001",
  "title": "Osm let léčby: …",
  "narrative": "… **léčba nikdy nekončí** …",   // markdown
  "patient": { "sex": "M", "ageAtStart": 40, "heightCm": 169,
               "diagnoses": ["DIA", "KARDIO", "OSA"] },
  "measurements": [ { "date": "2016-03-01", "weightKg": 142.0,
                      "source": "CLINIC" }, … ],   // CLINIC | HOME
  "interventions": [ { "category": "PHARMA", "code": "LIRA-1",
      "labelPlain": "injekce na hubnutí",          // ← primární (L8)
      "labelClinical": "Liraglutid 3,0 mg",        // ← sekundární
      "start": "2017-11-01", "end": "2018-12-31" }, … ],  // end: null = běží
  "beats": [ { "type": "DELTA", "from": "…", "to": "…", "text": "−20,5 kg …" },
             { "type": "BMI", "at": "…", "text": "BMI 49,7 – …" },
             { "type": "NOTE", "at": "…", "text": "návrat během pandemie" } ]
}
  • Odvozené hodnoty se nikdy neukládají. BMI, pásma, delty, kapitoly, regainy — všechno počítá lib/derive.ts a vyhlazení. Uložená pásma jsou přesně to, co rozbilo klientův Excel.
  • parseCase() vyhazuje čitelné české chyby — špatný JSON se dozví co a kde má špatně.
  • Beats jsou autorská vrstva (editor rozhoduje, co je úder příběhu); delty per intervence jsou odvozená vrstva (hover). Nemíchat.

Nová kazuistika v 5 krocích: ① JSON podle schématu (měření seřazená, intervence s oběma popisky) → ② 3–8 beats → ③ registrace v data/cases/index.ts → ④ npm test (validace + vlastnosti) → ⑤ vizuální kontrola na 360 px. Stránka i karta vzniknou samy.

Co nikdy nestavíme

Žebříček, „nejlepší výsledek“, řazení podle zhubnutí

Pojmenované křivky více pacientů v jednom grafu

Konfety, trofeje, oslavné efekty

Tmavý režim jako default — data o vlastním zdraví nemají číst zlověstně

Smyčkující animace

Osa Y od nuly — zničí veškeré rozlišení

Obalování chart knihovny — vlastní SVG je celý design

Ukládání odvozených hodnot do dat

Checklist před merge

  • Čitelné na 360 px; žádný překryv anotací na žádném breakpointu
  • Viditelný keyboard focus na každém ovládacím prvku; scrub ovladatelný šipkami
  • prefers-reduced-motion = kompletní finální stav okamžitě
  • Žádný hex mimo @theme; žádné localStorage/sessionStorage
  • Všechna čísla tabular-nums, formáty přes lib/format.ts
  • Regain viditelný a klidný; konec příběhu otevřený, ne minimum
  • npm test zelený (schéma, derive, vyhlazení, vlastnosti seed dat)
  • Graf vykreslitelný ve fixních rozměrech bez interaktivního chrome (budoucí PNG export, O5)

Otevřené body do dalších verzí: sekundární metriky (glykémie, tlak — layout slot rezervován, O4) · PNG export pro PowerPoint (O5) · napojení na reálná data z platformy Čas pro zdraví.