brainz-ink — KI spricht violett, Inhalt trägt seine Farbe
Der „paved path" für jede Brainz-Oberfläche. Ein Token-System, das Plugins sicher, theme-fähig und host-frei macht — plus die verbindlichen Regeln, die UI auf Besser-als-Apple-Niveau halten. Für Menschen und Coding-Agents.
Neu: Twerenbold · Ein Reisetag → · Teilnehmer, Tagesgruppen und Anwesenheit interaktiv ausprobieren.
Kanon: brainz-ink.md · Maschinenlesbar: manifest.json · Architektur: component-rebaseline.md
✦ Mockup: Dynamic-Home „Aurora"-Redesign → ▶ render_ui Playfield (live Engine) → Premium-Home-Vorschlag + Live-Spielfeld mit echten Komponenten
Für Plugin-Entwickler
Drei Regeln, dann bist du im paved path:
Ein Plugin liest --bzc-* (compose) bzw. seinen eigenen
(--rmd-* …), nie --bz-* direkt. So themt es automatisch und läuft
standalone (Hex-Fallbacks).
Violett (--bzc-ai) nur für KI-Momente.
Alles Gefüllte/Primäre trägt --bzc-accent (Content-Type → User).
≥44px Touch-Targets, sichtbares :focus-visible,
Motion nur transform/opacity mit reduced-motion-Guard. Siehe Checkliste.
Async-Zustände → Async-Pack.
Display → render_ui-Descriptor. Eingabe → compose-kind. Icons → bzIcon().
Für Coding-Agents
Start hier → ARCHITECTURE.md: wie Compose-Engine (Eingabe) und render_ui (Anzeige)
zusammenspielen — und die Schritt-für-Schritt-Anleitung, ein neues Element anzulegen, das überall verfügbar ist.
manifest.json ist die maschinenlesbare Quelle:
Tokens, Icons, beide Komponenten-Kataloge mit Props/Zuständen/Constraints. Lade sie, bevor du UI generierst.
① Gefülltes Primär-Element trägt nie KI-Violett. ②
Animiere nur transform/opacity — nie box-shadow/width/top.
③ Jedes interaktive Element ≥44px + :focus-visible.
④ Fetch-Felder zeigen loading/empty/error (nie still scheitern) → Async-Pack.
⑤ Icons ausschließlich über bzIcon(name) aus dem 70er-Satz.
⑥ Display-Inhalt = render_ui-Descriptor (Katalog B), Eingabe = compose-kind (Katalog A) — nie vermischen.
Layout-System worauf der Layouter zugreift + Auto-Moleküle
Der Home-Layouter (Chefredakteur, free-layout) komponiert in zwei Granularitäten:
grob er selbst (Reihenfolge, Gruppierung, kurze Prosa + ganze Daten-{ref} aus dem Inventar) —
fein datengetrieben die Karten-/Detail-Komposition, die aus structured_data automatisch
Moleküle baut. Der Layouter wählt also keine Atome/Moleküle direkt; er platziert Prosa-Blöcke + fertige Komponenten.
Layouter-Palette 10 Prosa-Blöcke + Daten-refs · home-digest-shape.sanitizeLayout
| Block | Rolle | Props |
|---|---|---|
Briefing | Editorialer Aufmacher: Dachzeile + Schlagzeile + 1-2 Sätze | eyebrow?, title, text?, tone (ai|neutral) |
SectionHeader | Gruppen-Überschrift zum Strukturieren | title |
BodyText | Kurzer, selbst geschriebener Fließtext (Begrüßung, Kontext) | text |
Callout | Hervorhebung / KI-Moment | text, tone (ai|info|warn) |
PullQuote | EIN herausgehobener Editorial-Satz (max. 1x) | text, cite? |
MetricRow | 2-4 echte Kennzahlen auf einen Blick (Struktur, neutral) | items[{value,label}], tone? |
Spotlight | DIE eine featured Sache (KI-Halo, max. 1x) | eyebrow?, title, note?, tone |
Divider | Visueller Trenner | — |
Countdown | Live tickender Countdown auf EIN nahes Ereignis aus der echten Agenda (max. 1x, target NUR aus vorhandenen Terminen) | target (ISO), title?, tone? |
ProgressRing | EIN Ziel-Fortschritt als Ring (max. 1x, value/max NUR aus echten Signalen, nie erfinden) | label?, value, max?, display?, tone? |
{ref} | Ein ganzes Inventar-Element (Karte/Sektion) an dieser Stelle zeigen | ref |
Molekül-Auto-Erkennung 40 Moleküle · aus structured_data.fields (genericCardProps/composeDetail)
| Molekül | erkannt aus Feld-Keys | Slot | Label |
|---|---|---|---|
Rating | rating, bewertung | lead | Rating |
Gallery | images, photos, bilder, gallery | media | Galerie |
VideoPlayer | videourl, video_url, video, youtube, youtubeurl | media | Video |
IngredientList | ingredients, zutaten | body | IngredientList |
StepList | steps, instructions, schritte, anleitung, syllabus, curriculum, lessons, modules | body | StepList |
Timeline | timeline, milestones, meilensteine, history, verlauf, stationen, roadmap | body | Timeline |
FaqList | faq, faqs, questions, fragen, qa | body | FaqList |
ProsCons | pros, vorteile | body | ProsCons |
Sparkline | trend, series, messwerte, readings, verlaufswerte | body | Sparkline |
ChangeList | changes, changelog, added, fixed, removed, deprecated, breaking_changes | body | ChangeList |
ScoreRow | imdb_score, metacritic_score, rt_score, tmdb_score, rawg_rating, scores | lead | ScoreRow |
MoneySummary | total, subtotal, gross_total, net_total, totals | body | MoneySummary |
NutritionFacts | nutrition, naehrwerte, nutrients, calories, kalorien | body | NutritionFacts |
ValiditySpan | expiry_date, renewal_date, warranty_until, valid_until, trial_end, expires_at | body | ValiditySpan |
ProgressRing | progress, fortschritt, completion, completion_pct, reading_progress | lead | ProgressRing |
Quote | quote, testimonial, zitat | body | Quote |
Highlights | highlights | body | Highlights |
ProgressRing | listened_episodes, current_episode | lead | ProgressRing |
Callout | safety_notes, warnhinweise, sicherheitshinweise | body | Callout |
StatusTrack | fulfillment_status, order_status | lead | StatusTrack |
MiniMonth | event_date, appointment_date, start_date, startdate | body | MiniMonth |
LineItems | line_items, positionen, parts_list | body | LineItems |
PeopleRow | team, stakeholders, attendees, speakers, teilnehmer, members | body | PeopleRow |
CopyField | tracking_number, serial_number, isbn, iban | body | CopyField |
Tip | tips, tipps, hinweise, hints | body | Tip |
HoursTable | openingHoursSpecification, opening_hours, oeffnungszeiten | body | HoursTable |
MetaChips | prep_time, cook_time, total_time, servings, runtime, reading_time, reading_time_min | lead | MetaChips |
WhereToWatch | streaming, watch_providers, where_to_watch | body | WhereToWatch |
AllergenBlock | allergies, allergens, allergene | body | AllergenBlock |
PeopleRow | characters, figuren | body | PeopleRow |
ChipRow | platforms, plattformen | lead | ChipRow |
ProgressRing | nps_score | lead | ProgressRing |
List | key_points, keypoints, takeaways, kernpunkte | body | List |
Byline | author, autor | lead | Byline |
Kpi | price, preis | lead | Kpi |
Coupon | coupon_code, gutschein_code, promo_code, voucher_code | body | Coupon |
AudioPlayer | audio_url, enclosure_url, podcast_url | media | AudioPlayer |
LocationCard | address, adresse | body | LocationCard |
ContactChannels | email, phone, mobile, telefon, website | body | ContactChannels |
PlaceList | places, orte, stops, locations | body | PlaceList |
Field Registry ein Feld = Eingabe + Anzeige + Validierung
Die Field Registry (field-registry.ts in @brainz/doc-model) ist der typisierte Vertrag
für structured_data-Felder — eine serialisierbare Deklaration speist die Compose-Eingabe
(compose-fields-bridge mappt auf Katalog-A-Kinds), das Eigenschaften-Sheet
(structured-data-editor), die Molekül-Anzeige (Katalog B) und die Server-Validierung
(contentRepo, warn-only). Plugins steuern Felder als reine Daten bei (Capability.fields,
trait-scoped via appliesTo) — keine Closures, sandbox-fähig. Maschinenlesbar: manifest.fields.
Registrierte Felder 48 FieldDefs · Quelle ui-contract/field-registry
| Key | Wert | Eingabe (A) | Molekül (B) | Geltung | Beschreibung |
|---|---|---|---|---|---|
rating | number (≥0, ≤5) | stepper „Bewertung" | rating | universell | Bewertung 0–5 — Eingabe als Stepper, Anzeige als Rating-Molekül (Sterne). |
tags | stringList (max 60) | tokens | — | universell | Freie Schlagwörter — Eingabe als Token-Chips; Anzeige über die Karten-TagRow. |
effort_bucket | string (flash|quick|focus|deep|project) | segmented „Aufwand" | — | Typen: task | Grobe Aufwandsschätzung der Aufgabe in 5 Stufen (~2 min bis Projekt) — speist 2-Minuten-Rubrik, Lücken-Matcher und Aufwands-Anzeige. |
images | stringList (max 4000) | — (Code-Feld/display-only) | gallery | universell | Bild-URLs — Anzeige als Gallery-Molekül (Eingabe läuft über das photo-Code-Feld). |
video | string (max 2000) | video | video | universell | Video-URL (YouTube watch/youtu.be/shorts) — Eingabe mit Live-Thumbnail, Anzeige als VideoPlayer-Molekül. |
ingredients | json | — (Code-Feld/display-only) | ingredient-list | universell | Zutaten (Objekte {amount?, name}) — Anzeige als IngredientList-Molekül. |
places | json | — (Code-Feld/display-only) | place-list | universell | Strukturierte Orte (Objekte {name, type?, why?, lat?, lng?, image_url?, website?}) — Anzeige als PlaceList-Molekül. |
steps | stringList (max 400) | — (Code-Feld/display-only) | step-list | universell | Zubereitungs-/Arbeitsschritte — Anzeige als StepList-Molekül. |
tips | stringList (max 400) | — (Code-Feld/display-only) | tip | universell | Tipps/Hinweise — Anzeige als Tip-Molekül (akzent-getönte Blöcke). |
timeline | json | — (Code-Feld/display-only) | timeline | universell | Meilensteine (Objekte {date|when|year|label, title|text} oder Strings „2026 — Ereignis“) — Anzeige als Timeline-Molekül. |
faq | json | — (Code-Feld/display-only) | faq | universell | Frage-Antwort-Paare (Objekte {q|question, a|answer}) — Anzeige als FaqList-Accordion. |
pros | stringList (max 400) | — (Code-Feld/display-only) | pros-cons | universell | Pro-Argumente (String-Liste; Geschwisterfeld cons/nachteile wird mitgelesen) — Anzeige als ProsCons-Molekül. |
trend | json | — (Code-Feld/display-only) | sparkline | universell | Zahlenreihe in zeitlicher Reihenfolge (≥3 Werte) — Anzeige als Sparkline-Molekül. |
changes | stringList (max 400) | — (Code-Feld/display-only) | changelog | universell | Changelog-Einträge (String-Liste; Geschwister added/fixed/removed/… werden gruppiert) — Anzeige als ChangeList-Molekül. |
imdb_score | number (≥0, ≤10) | — (Code-Feld/display-only) | scores | universell | Provider-Score (IMDb 0–10; Geschwister rt/metacritic/tmdb werden mitgelesen) — Anzeige als ScoreRow-Molekül. |
total | json | — (Code-Feld/display-only) | totals | universell | Endsumme (Zahl oder formatierter String; Geschwister subtotal/tax/vat werden mitgelesen) — Anzeige als MoneySummary-Molekül. |
nutrition | json | — (Code-Feld/display-only) | nutrition | universell | Nährwerte (Objekt {calories, protein, …} oder calories-Skalar mit Geschwistern) — Anzeige als NutritionFacts-Molekül. |
expiry_date | string (max 40) | — (Code-Feld/display-only) | validity | universell | Ablauf-/Enddatum (ISO; Geschwister purchase_date/start_date als Beginn) — Anzeige als ValiditySpan-Molekül. |
progress | number (≥0, ≤100) | — (Code-Feld/display-only) | progress | universell | Fortschritt als Anteil (0–1) oder Prozent (0–100) — Anzeige als ProgressRing-Molekül. |
quote | string (max 2000) | — (Code-Feld/display-only) | quote-block | universell | Zitat/Testimonial-Text (Geschwister person/position als Quelle) — Anzeige als Quote-Molekül. |
person | string (max 120) | person „Von wem?" | — | Typen: quote, testimonial | Wer hat's gesagt? Sprecher:in des Zitats (cite-Geschwister von quote; KE-Match über Personen-Namen/Aliasse). |
said_at | string (max 40) | datetime „Wann?" | — | Typen: quote | Wann wurde es gesagt (ISO-Datum) — für nachgetragene Zitate; frisch erfasste tragen ihr created_at. |
context | string (max 300) | text „Kontext" | — | Typen: quote | Situation/Anlass des Zitats (z. B. beim Abendessen, 4 Jahre alt) — Detail-Zeile, keine eigene Karte. |
highlights | stringList (max 600) | — (Code-Feld/display-only) | highlights | universell | Markierte Passagen/Zitate (String-Liste) — Anzeige als Highlights-Molekül (Textmarker-Look). |
listened_episodes | number (≥0) | — (Code-Feld/display-only) | episodes | universell | Gehörte/gesehene Episoden (Zahl; Geschwister total_episodes/episode_count als Skala) — Anzeige als Episoden-ProgressRing. |
safety_notes | stringList (max 400) | — (Code-Feld/display-only) | safety | universell | Sicherheits-/Warnhinweise (String-Liste) — Anzeige als warn-Callout. |
fulfillment_status | string (max 60) | — (Code-Feld/display-only) | order-status | universell | Bestell-Status (bestellt/bezahlt/versandt/geliefert) — Anzeige als StatusTrack-Pipeline. |
event_date | string (max 40) | — (Code-Feld/display-only) | calendar | universell | Termin-Datum (ISO; Geschwister end_date als Zeitraum) — Anzeige als MiniMonth-Kalender. |
line_items | json | — (Code-Feld/display-only) | line-items | universell | Rechnungs-/Stücklisten-Positionen (Objekte {name|description, qty?, price?}) — Anzeige als LineItems-Molekül. |
team | stringList (max 80) | — (Code-Feld/display-only) | team | universell | Personen-Namen (String-Liste; auch attendees/stakeholders/speakers) — Anzeige als PeopleRow-Avatare. |
tracking_number | string (max 120) | — (Code-Feld/display-only) | tracking | universell | Kenncode (Tracking/Serien-Nr./ISBN/IBAN) — Anzeige als kopierbares CopyField. |
opening_hours | json | — (Code-Feld/display-only) | opening-hours | universell | Öffnungszeiten (schema.org-Objekte {dayOfWeek, opens, closes}; auch openingHoursSpecification) — Anzeige als HoursTable mit „Jetzt geöffnet“-Chip. |
prep_time | string (max 40) | text „Vorbereitung" | meta | universell | Vorbereitungszeit (z. B. „20 min“; Geschwister cook_time/servings/runtime/reading_time werden mitgelesen) — Anzeige als MetaChips-Faktenreihe. |
cook_time | string (max 40) | text „Kochzeit" | meta | universell | Koch-/Backzeit (z. B. „15 min“) — Anzeige als MetaChips-Faktenreihe. |
servings | number (≥1, ≤99) | stepper „Portionen" | meta | universell | Portionen — Eingabe als Stepper, Anzeige als MetaChips-Faktenreihe. |
streaming | json | — (Code-Feld/display-only) | where-to-watch | universell | Streaming-Verfügbarkeit (TMDB/JustWatch-Objekt, länder-gekeyt mit flatrate/rent/buy) — Anzeige als WhereToWatch-Providerchips. |
allergies | stringList (max 60) | tokens „Allergene" | allergens | universell | Allergene/Allergien (String-Liste) — Eingabe als Token-Chips, Anzeige als AllergenBlock-Warnbanner. |
characters | stringList (max 80) | tokens „Charaktere" | characters | universell | Figuren/Charaktere (String-Liste) — Eingabe als Token-Chips, Anzeige als PeopleRow-Avatare mit Label „Charaktere“. |
platforms | stringList (max 60) | tokens „Plattformen" | platforms | universell | Plattformen (String-Liste, z. B. PC/PS5/Switch) — Eingabe als Token-Chips, Anzeige als ChipRow-Pillen. |
nps_score | number (≥0, ≤10) | stepper „NPS" | nps | universell | NPS-Wert 0–10 — Eingabe als Stepper, Anzeige als ProgressRing (Promoter grün, Passiv neutral, Detraktor warnend). |
key_points | json | — (Code-Feld/display-only) | key-points | universell | Kernpunkte/Takeaways (String-Liste, meist KI-Enrichment) — Anzeige als kompakte List. |
author | string (max 120) | text „Autor:in" | byline | universell | Autor:in — mit Publikations-Geschwistern (site_name/datePublished) als Byline-Zeile. |
price | string (max 40) | text „Preis" | price | universell | Preis (Zahl oder String; Geschwister currency wird mitgelesen) — Anzeige als Kpi mit Einheit. |
coupon_code | string (max 60) | text „Gutschein-Code" | coupon | universell | Gutschein-/Promo-Code (Geschwister valid_until/conditions werden mitgelesen) — Anzeige als Coupon-Ticket. |
audio_url | string (max 2000) | text „Audio-URL" | audio | universell | Direkte Audio-URL (.mp3/.m4a/…) — Anzeige als AudioPlayer. |
address | string (max 300) | text „Adresse" | address | universell | Postadresse (String oder schema.org-Objekt; Geschwister geo wird mitgelesen) — Anzeige als LocationCard mit Karten-Link. |
email | string (max 200) | text „E-Mail" | contact-channels | universell | E-Mail (Geschwister phone/mobile/website werden mitgelesen) — Anzeige als tappbare ContactChannels-Chips. |
secret | string (max 4000) | text „Geheimnis" | — | Typen: credential | Geheimnis (API-Key, Passwort, Token) — nur Eingabe/Bearbeitung; wird nie als Molekül angezeigt, nie embedded, nie indexiert. |
Farbe & Zwei-Akzent der Kern
Zwei Akzent-Familien, strikt getrennt. Das Violett der KI ist eine eigene Sprache und fällt nie mit der vom User gewählten Akzentfarbe zusammen — so bleibt KI als KI erkennbar.
--bzc-accent. Fallback-Kette: override → --tc → --bz-accent → Hex.--bzc-ai) auf gefüllten Buttons/Chrome. Es gehört nur an den Magic-Moment, die Funke, die Quelle, OCR. (Die „Purple-Slop"-Falle.)Tokens Schicht 1 · --bz-*
Die App liefert --bz-* (theme-aware). Plugins leiten daraus ihren Namespace ab.
Werte light / dark:
| Token | Light | Dark |
|---|
Typografie
System-Stack -apple-system, "SF Pro Text", system-ui, antialiased.
Tabellen-Zahlen font-variant-numeric: tabular-nums. Beobachtete Stufen (noch nicht tokenisiert):
Geometrie & Raum
Radius skaliert über --bz-radius-scale. Spacing: rem für vertikalen Rhythmus,
px für komponenteninterne Gaps.
Motion performant by construction
Animiere ausschließlich transform und opacity (Compositor) —
nie box-shadow/filter/width/height/top/left (Paint/Layout). Glow „atmet" über ein Pseudo-Element mit
statischem box-shadow, dessen opacity animiert wird. Alles Dekorative hinter
@media (prefers-reduced-motion: no-preference).
Spring-Token cubic-bezier(.2,.9,.3,1) · Dauern 120–340ms (Mikro), 460–620ms (Entrance).
Tippe den Button (press = scale(.96)):
A11y-Standards die Latte
Verbindlich für jede neue/geänderte Komponente:
- Touch-Target ≥ 44×44px — kleinere Visuals brauchen eine ≥44px Hit-Area (Utility
.bz-tap). - Sichtbares
:focus-visibleauf jedem interaktiven Element; Inputs nie ringlos. - Interaktiv = echtes
<button>/tabindex, kein nacktercursor:pointer-Span. - Motion-Guard via
prefers-reduced-motion; nur essentielles Press-Feedback ungated. - Two-Accent eingehalten (Violett nur KI).
:focus-visible fehlt komplett (Inputs entfernen den Ring sogar). Behebung = Task #4 (Re-Baseline §5).Iconography
24er-Grid, 1.7 Stroke, runde Kappen, currentColor. Keine Emojis.
Immer über bzIcon(name) — fehlt ein Glyph, im Service ergänzen (nicht inline). Gefüllte Varianten
(violett) sind Akzent-Momente.
Async-State-Pack Primitive · live
Ein verwalteter Container für die Lebenszyklen jedes Fetch-Feldes:
loading(Skeleton) · empty · error(+Retry) · results. Quelle:
compose-async.ts ·
Mockup: compose-async.html.
slot.loading("rows")
opts.ai:true → KI-Laden (violett)
slot.empty()
slot.error(msg, retry)
// jeder Fetch läuft durch run() — verschlucktes Versagen ist unmöglich const slot = createAsyncSlot({ skeleton: "rows", empty: { icon: "search" } }); field.appendChild(slot.el); await slot.run(() => discover(url), (hits, s) => hits.length ? s.results(render(hits)) : s.empty()); // Reject → s.error(msg, retry) automatisch; Retry re-fährt den Task.
slot.run() leiten — empty/error sind dann garantiert abgedeckt.urlDiscover macht genau das) oder .catch weglassen (place/entity/person).AudioRecorder kind "audio" · live
Sprachnotizen, drei Zustände. Die Wellenform lebt (transform:scaleY),
Transkribieren ist der einzige KI-Moment (violett), die Aufnahme trägt --bz-rec.
Quelle: compose-audio.ts (echter MediaRecorder + AnalyserNode).
state: idle
state: recording — lebende Wellenform · Stop (Rot)
state: recorded — Scrubber · Erneut · Transkribieren (KI)
const rec = createAudioRecorder({ onTranscribe: (blob, sec) => transcribe(blob), // violetter KI-Moment }); field.appendChild(rec.el); // idle → recording (Live-Wellenform) → recorded (Scrubber + Transkribieren)
getUserMedia/MediaRecorder/AnalyserNode) braucht Geräte-Test — im Headless-Preview nicht ausführbar. Die Demo hier animiert per CSS-Keyframe; das Modul treibt die Bars live aus der Mikrofon-Amplitude.Callout kind "callout" · tonal
Tonale Verallgemeinerung von aiNote: info/success/warn/danger laufen über
--tone; ai behält das KI-Violett (die einzige violette Ausnahme).
Quelle: compose-callout.ts.
field.appendChild(createCallout({ tone: "ai", // info | success | warn | danger | ai title: "KI-Vorschlag", text: "Theo bekommt die Erinnerung …", }));
Die zwei Kataloge
Brainz hat zwei getrennte Komponenten-Sprachen — nicht vermischen. Detail: component-rebaseline.md.
--bzc-*Eingabe → schreibt ComposeState. Eine Fläche.
Quelle compose-sheet.ts.
--bz-*Anzeige eines KI-/Daten-Ergebnisses. Drei Flächen:
live · Lexical-Roundtrip · PDF. Quelle ui-contract + cards.
lexicalNodeType + Serialisierung als Quelle für Validierung und BRAINZ_NODE_TYPES. Komponenten-Seiten für beide Kataloge folgen (Task #7).Katalog A · Compose-Felder --bzc-* · Eingabe
Jedes kind schreibt nach ComposeState[key]. Visuelle Referenz:
compose-catalog.html. Props mit ? sind optional.
magictextnumberdatetimedaterangecomboboxrepeatablesecretamounttokensurlDiscovervideopresetssegmentedselecttoggletoggleGroupstepperradiusdatetimeplacemapphotoentityruipersonaiNotehintpersonListintentCardspillRowhandoffsharerecurshareLinkshareTargetsmodeBandaudiocalloutsectionKatalog B · render_ui-Descriptoren --bz-* · Display
Deklarative Anzeige eines KI-/Daten-Ergebnisses über drei Flächen:
live DOM · lex Lexical-Roundtrip · pdf Export.
$ref-Props zeigen in den Server-Result-Store. Richtung: render_ui ≡ Lexical.
Core @brainz/doc-model · 75 Typen
MarkdownlivelexpdfFließtext mit Markdown (sanitized, kein HTML-Passthrough) — der Default für jeden Prosa-/Artikel-Body und mehrzeilige Erklärtexte. Kurze selbst geschriebene Einordnung → BodyText, Anreißer-Absatz nach dem Titel → Lead.
content
KpilivelexGENAU EINE hervorgehobene Kennzahl mit Label, optional Trend (+/-) und Einheit — wenn diese eine Zahl die Aussage ist. 2–4 gleichrangige Kennzahlen nebeneinander → MetricRow; Wert mit Ziel/Fortschritt → ProgressRing.
label·value·unit?·trend?
TablelivelexpdfTabelle. rows als $ref aus dem Result-Store (Arrays ODER Objekte je Zeile); bei Objekt-Zeilen die Daten-Keys in fields angeben (Reihenfolge = columns). maxRows begrenzt die Anzeige. Live sortierbar per Spaltenkopf (sortable:false schaltet ab, z. B. mit Summenzeile).
columns·rows·fields?·maxRows?·sortable?
ListlivelexpdfEinfache Liste aus reinen Strings (Aufzählung, Top-N); items darf $ref sein, ordered=true nummeriert. NUR für Aufzählungen ohne Zustand — abhakbare To-dos → Checklist, Schlüssel-Wert-Fakten → KeyValue, Vergleichswerte → BarList.
items·ordered?
BadgeliveKleine Status-/Kategorie-Pille (EIN Wort/Kürzel, inline, max 40 Zeichen) mit tone neutral/success/warning/danger/info — z.B. „Aktiv“, „Überfällig“. Für einen Hinweis mit Titel+Text → Callout; für Label-Wert-Fakten → MetaChips.
text·tone?
CalloutlivelexpdfHervorgehobener Hinweis-Block mit Ton (info/success/warn/danger/ai), Titel und optionalem Text — für Warnungen, Tipps, KI-Hinweise. Kein $ref nötig.
tone?·title·text?·icon?
QuotelivelexpdfZitat / Blockzitat im Textfluss mit optionaler Quelle (cite) — für wörtliche Wiedergabe fremder Aussagen. EIN herausgehobener Editorial-Satz als Blickfang (max 1x) → PullQuote (cards-Pack); mehrere markierte Passagen → Highlights.
text·cite?
CodelivelexpdfCode-Block (monospace, vorformatiert) mit optionaler Sprache — für Quellcode, Config, CLI-Ausgaben, Logs; erhält Whitespace exakt. Kopierbare Einzel-Codes (Seriennummer, IBAN) → CopyField; Formeln → Math; normaler Text NIE hierhin.
code·language?
MathlivelexpdfMathematische Formel als LaTeX, browser-nativ über MathML gerendert (keine Schrift-Abhängigkeit). display: block = eigene zentrierte Zeile, inline = im Textfluss. NUR für echte Formeln/Notation — einfache Zahlen mit Einheit bleiben Fließtext oder Kpi, Quellcode → Code.
latex·display?
ChecklistlivelexpdfAufgaben-/Checkliste mit Abhak-Zustand: items = [{text, checked?, value?}]. items darf $ref sein. editable+entityUuid = abhakbar (persistiert via setChecklistPersist). Alternativ trägt der Block on.itemCheck (eine Capability-Action) — dann dispatcht ein Haken diese Action mit dem Item-Payload (value/checked/index) statt des generischen Persist (render-ui-item-actions.md). variant wählt die Darstellung: checkbox (Default, abhakbar), bullet (schlichte Aufzählung), numbered (nummeriert) — Umschalten macht aus der Checkliste eine normale/nummerierte Liste, ohne den Typ zu wechseln. NUR wenn Erledigt-Status Sinn ergibt (To-dos, Packlisten, Schritte) — reine Aufzählung ohne Zustand → List.
items·variant?·editable?·entityUuid?
DeviceControllivelexSteuerbare Smart-Home-Entität als EINE Zeile: name + optional room, state (on|off|playing|paused|open|closed|unavailable) und je nach kind eine Affordanz — toggle (Licht/Schalter), level (Dimmer/Rollo, value 0–100), setpoint (Klima, value in unit) oder media (Player). EINE Komponente statt je einer pro Geräteart; kind beschreibt die Bedienform, nicht den Gerätetyp. editable=true macht sie bedienbar (schaltet über den Host-Hook setDeviceControl, der das Kommando einreiht); ohne editable ist sie reine Anzeige — so bleibt sie in Stream/PDF/SSR ungefährlich. state='unavailable' rendert gedämpft und nie bedienbar. Zeigt NIE Zugangsdaten (Secrets leben im Geräte-Detail).
entityRef·name·room?·kind·state·value?·unit?·min?·max?·subtitle?·editable?
DividerlivelexpdfVisueller Trenner (horizontale Linie) zwischen thematischen Abschnitten. Keine Props. Sparsam einsetzen und nie zwei hintereinander — braucht der neue Abschnitt einen Titel, ist SectionHeader statt Divider richtig.
— keine Props
KeyValuelivelexpdfSchlüssel-Wert-Paare als vertikale Fakten-Liste (Eckdaten EINES Gegenstands): items = [{key, value}]. Optionales fieldKey pro Zeile = Reverse-Binding-Provenance (structured_data-Feld-Key → Detail-Sheet macht die Zeile antippbar/editierbar). items darf $ref sein. 2–6 Kurz-Fakten kompakt in einer Reihe → MetaChips; mehrere Datensätze mit gleichen Spalten → Table.
items
CommentThreadlivelexpdfDiskussions-Thread (read-only Anzeige): Liste von Kommentaren mit optionalem Autor, Zeit, Typ (comment/idea/annotation/todo/ai_insight/ai_question), Pin und Reply-Einrückung. comments darf $ref sein. Display-Zwilling der interaktiven Kommentar-Section — NUR für vorhandene Kommentar-/Notiz-Daten mit Autoren, nicht für Zitate (Quote/Highlights) oder erfundene Dialoge.
title?·comments·empty?
ImagelivelexpdfEIN Bild per URL mit optionalem Alt-Text und Bildunterschrift; 2+ aufeinanderfolgende Images verschmelzen automatisch zu einer Gallery. Zwei Zustände zum Wischen vergleichen → BeforeAfter; Link-Vorschau mit og:image → HeroCard.
url·alt?·caption?
SearchResultslivelexWeb-Suchergebnisse im Snippet-Stil (Favicon, Titel-Link, gekürzte URL, Snippet) — für web_search-Ergebnisse IMMER diese Komponente verwenden, NIE Table. results als $ref auf das Tool-Result (z.B. r2.results), nie abschreiben.
results·maxResults?
HeroCardlivelexpdfGrosse Vorschau-Karte für EIN hervorgehobenes Link-Ergebnis (og:image wird automatisch nachgeladen). Nutze sie, wenn ein web_search-Treffer klar am relevantesten ist — weitere Treffer dann optional mit SearchResults darunter oder ganz weglassen.
url·title·description?·published?
CardlivelexReiner Layout-Container mit optionalem Titel — gruppiert Kinder visuell als abgesetzte Fläche, trägt selbst keine Daten. Eine Inhalts-/Entity-Karte mit eigenen Feldern → GenericCard (cards-Pack); ein betonter Hinweis mit Ton → Callout.
title?
GridliveRaster-Layout: verteilt die Kinder gleichmäßig auf columns (1–4) Spalten — für gleichartige Kacheln (Kpi-Reihen, Karten-Raster). Redaktionell befüllte, im Editor bearbeitbare Spalten mit eigenem Inhalt → Columns + Column.
columns?
TogglelivelexpdfAuf-/zuklappbarer Abschnitt (Container). summary = Kopfzeile, open = initial geöffnet. Gruppiert beliebige Kinder im EDITIERBAREN Body — im Lexical-Editor eine native, faltbare Sektion (ElementNode, kein Leaf), in Live-/PDF-Flächen expandiert. Für lange/optionale Inhalte (Details, FAQ, Notion-Toggles).
summary·open?
ColumnslivelexpdfMehrspalten-Layout (Container). count = Spaltenzahl (1–4, Default = Anzahl der Column-Kinder). Die Kinder sind Column-Container, die NEBENEINANDER gerendert werden (Live/Editor/PDF, auf schmalen Flächen gestapelt). Für nebeneinander gestellte Inhalte / Notion column_list.
count?
ColumnlivelexpdfEine Spalte INNERHALB von Columns (Container). Gruppiert beliebige Kinder vertikal im editierbaren Body. Nur innerhalb von Columns sinnvoll (entspricht Notion column).
— keine Props
EmailTemplatelivelexVom Assistenten generierte E-Mail-Vorlage zum Kopieren. Karte mit Betreff + Textkörper (optional Empfänger/Anrede/Grußformel) und eigenem Kopier-Button (kopiert die formatierte E-Mail als Text). body ist reiner Text mit Zeilenumbrüchen, KEIN Markdown/HTML. Nutze das, wenn der Nutzer eine E-Mail zum Übernehmen/Versenden wünscht — nicht Fließtext im Chat.
subject·body·to?·greeting?·signature?
ButtonliveAktions-Button für App-Aktionen: on.press bindet eine Action aus der Allowlist — NUR emittieren, wenn eine solche Action existiert (sonst rendert er wirkungslos). Weblinks sind KEINE Buttons (dafür References/HeroCard); kopierbare Werte → CopyField.
label·variant?
ReplyChipsliveKurze Antworten zum Antippen im Gespräch (Florian 07.10.): bis zu 6 Chips unter einer optionalen Frage. Ein Tipp sendet `value` als Nachricht der Person (sendMessage) – danach sind die Chips gesperrt, der gewählte bleibt markiert; Tasten 1–6, am Phone seitlich scrollbar. kind: reply (Antwort), confirm (Zustimmung, gefüllt), cancel (Ablehnen, ruhig), starter (Einstiegsfrage beim Öffnen, ohne prompt). multi: mehrere wählen, dann „Senden“. WICHTIG: confirm ist NUR die Antwort der Person – jede Aktion mit Folgen läuft weiter über die Freigabe-Karte; ein Chip führt nie selbst eine Aktion aus. Nur emittieren, wenn eine kurze Antwort genügt (Ja/Nein, eine Wahl aus wenigen) – nicht für lange Formulare (→ Form).
prompt?·options·multi?
EmbedlivelexpdfCSP-isoliertes Drittanbieter-Widget in einem sandbox-iframe (kein Zugriff aufs Eltern-DOM/Cookies). Entweder `url` (iframe-src, MUSS auf der Host-Allowlist liegen) ODER `html` (roher oEmbed-Blob, z.B. X/TikTok → srcdoc-iframe, gegated über `host`). Der Renderer blockiert nicht-erlaubte Hosts sichtbar. Dritt-Inhalt lädt erst nach Zustimmung, wenn autoload nicht true ist. Für Anzeige-Widgets/Player, NICHT für App-eigene Daten.
url?·html?·title?·host?·aspect?·autoload?
VideoPlayerlivelexpdfVideo-Player: Poster + Play-Overlay, klick-to-play lädt einen CSP-isolierten Provider-iframe (youtube-nocookie etc.) über dieselbe Embed-Mechanik/Allowlist wie `Embed`. Aspect-aware — `16:9` für klassische Videos, `9:16` für Shorts/Reels, `1:1`. Optional `title`/`channel`/`duration` als Overlay-Chrome. Für YouTube genügt eine watch-/youtu.be-/shorts-/embed-URL; ist kein `poster` gesetzt, wird er aus der Video-ID abgeleitet. Ist `press` an eine Action gebunden, öffnet ein Tap diese (z.B. Vollbild) statt inline zu spielen. Für Video-Anzeige, NICHT für App-eigene Daten.
url·poster?·aspect?·title?·channel?·duration?
CompositelivelexZusammengesetzte Fläche (Container) — die höchste Kompositions-Schicht: gruppiert die eigenen Felder/Moleküle eines Eintrags mit VERWANDTEN Inhalten (QueryBlock) zu EINER Sektions-Sheet-Ansicht. title = optionale Überschrift; die Kinder sind die Regionen (Header/Body/verwandte Sektion), vertikal mit feinen Trennern gestapelt. Deklarativ getrieben aus dem Composite-Katalog (z. B. productSheet); für Cross-Content-Type-Sheets in Detail/Home.
title?·variant?
RelatedBlocklivelexVerwandte Inhalte DES aktuellen Eintrags (referenziell) — Vektor-Ähnlichkeit + Tag-Overlap + Collection-Ko-Mitgliedschaft (`/api/assets/by-uuid/:uuid/related`). Anders als QueryBlock (regel-basiert) ein echter „was gehört zu DIESEM Eintrag"-Bezug. sourceUuid = uuid des Eintrags; optional per content_type gefiltert (z. B. nur verwandte Reviews). Der Host löst per setRelatedResolver auf; ohne Resolver/Treffer ein sichtbarer Zustand. Für „Ähnliches/Verwandtes"-Sektionen in Detail/Composite.
title?·sourceUuid?·contentType?·contentTypes?·limit?
QueryBlocklivelexDynamischer Abfrage-Block: filtert die eigenen Inhalte (`content`) nach Regeln (field/op/value, wie Smart Collections) und rendert die Treffer als Liste. Der Host löst die Abfrage auf (setQueryResolver → /api/collections/preview); ohne Resolver/Treffer ein sichtbarer Zustand. Für „lebende" Listen (offene Aufgaben, neueste Notizen, getaggte Einträge) in Dokument-Body, Home oder Detail. Liest nur eigene Inhalte; NICHT für Drittdaten (dafür Embed).
title?·rules·limit?·layout?·typeFilter?
TimelinelivelexpdfVertikale Meilenstein-Timeline für Verläufe, Historien, Roadmaps und Changelogs: items = [{label?, title, text?, tone?, now?}]. label = freier Zeitpunkt (z.B. „Mai 2026“), tone färbt den Punkt (success=erreicht, warn/danger=Risiko, ai=KI-Moment), now=true markiert den aktuellen Schritt mit Puls. NICHT für die Tagesagenda mit Uhrzeiten (dafür DayTimeline).
title?·items
ProgressRinglivelexpdfKreisförmiger Fortschrittsring (conic-gradient, animiert): value/max als Donut mit großem Zentrum-Wert. label = worum es geht, unit optional, display überschreibt den Zentrum-Text (Default gerundete Prozent), tone färbt (success/warn/danger/ai). Für Ziele, Auslastung, Gewohnheiten, Budgets — EINE Zahl mit Richtung, kein Chart-Ersatz.
label?·value·max?·unit?·display?·tone?
SparklinelivelexpdfMini-Trendlinie (Sparkline) aus einer Zahlenreihe — zeichnet sich beim Erscheinen ein, letzter Punkt pulsiert. points = Rohwerte in zeitlicher Reihenfolge (darf $ref sein), label + unit beschriften, delta = Veränderungs-Chip (z.B. „+12%“, Vorzeichen färbt), tone färbt die Linie. Für Verläufe NEBEN einer Kennzahl (Kpi) — kein Ersatz für eine echte Chart-Fläche.
label?·points·unit?·delta?·tone?
BarListlivelexpdfHorizontale Vergleichs-Balken (Ranking/Verteilung): items = [{label, value, display?, tone?}] — Balkenbreite relativ zum Maximum (max überschreibt), display ersetzt die angezeigte Zahl (z.B. „2,4 h“), unit hängt an alle Werte. Balken wachsen gestaffelt hinein. Für Top-N, Budgets, Stimmen, Zeitanteile — überall wo Table zu schwer wäre.
title?·items·max?·unit?
GraphlivelexpdfInteraktiver Wissens-Graph (eingebettet): nodes = [{id, label, tone?, icon?, glyph?, weight?}], edges = [{source, target, strength?, relation?, confirmed?}]. icon = Content-Type-/Icon-Name (echte SVG via Host-Icon-Resolver, sonst Glyph/Disc). Zeigt einen Ausschnitt des Verknüpfungsnetzes als 2D-Layout (Stärke = Breite/Deckkraft, Top-K pro Knoten gegen Haarball), getönte Knoten nach Inhaltsklasse (tone). Zwei Tinten: Kanten mit relation attachment/link/collection/manual (ein Mensch hat verknüpft) zeichnen in der Akzentfarbe, Kanten mit relation entity/suggested/similar/predicted/semantic/temporal (die KI hat gefunden) im KI-Violett — gestrichelt, solange confirmed nicht true ist (predicted gepunktet); Kanten ohne relation bleiben neutral grau. Tippen auf einen Knoten emittiert openEntity; on.press bindet optional „im Vollbild öffnen“. Tippen auf eine Kante feuert das DOM-Event bz-graph-edge ({source, target, relation, confirmed}, bubbelt) — Hosts öffnen damit den Beleg (Warum-Sheet). Langes Drücken auf einen Knoten feuert bz-graph-hold ({id}); ghost=true-Knoten (Lücken) feuern beim Tippen bz-graph-ghost ({id}) statt openEntity. Knoten mit x/y (−1…1) werden ohne Layout an diese Position gesetzt (vorberechnete Karte), size skaliert den Radius, sub ist die Zweitzeile, weight die Präsenz (Deckkraft), highlight hebt Pfad-Stationen/-Kanten hervor. Fällt ohne Canvas / bei reduzierter Bewegung auf eine statische, zugängliche Knotenliste zurück. intro=true spielt beim Mount einen Zoom-out-Reveal vom Fokus-Knoten (Vollbild-Einstieg). Beim Hinfliegen zu einem Knoten feuert das Root-Element das DOM-Event bz-graph-focus ({id}, bubbelt) — Hosts können damit das Netz um den Knoten expandieren (nachladen + re-rendern). Für Detail-/Chat-Flächen — kein Ersatz für den Vollbild-Reveal-Layer der App.
title?·nodes·edges·focus?·height?·lens?·intro?
BeforeAfterlivelexpdfVorher/Nachher-Bildvergleich mit Wisch-Griff: zwei Bilder übereinander, ein nativer Slider zieht die Trennlinie (touch-first, Tastatur via Pfeiltasten). before/after = Bild-URLs, beforeLabel/afterLabel = Eck-Chips (Default „Vorher“/„Nachher“), start = Startposition in %. Für Renovierungen, Retuschen, Fortschrittsfotos, Design-Iterationen.
before·after·beforeLabel?·afterLabel?·alt?·caption?·start?
FlipcardlivelexpdfUmdreh-Karte (3D-Flip beim Tippen): front = Vorderseite (Frage/Begriff, groß), back = Rückseite (Antwort/Erklärung). frontLabel/backLabel = kleine Dachzeilen (Default „Frage“/„Antwort“), tone ai = violette KI-Aura. Reduced-Motion blendet statt zu drehen. Für Lernkarten, Vokabeln, Quiz, Spoiler.
front·back·frontLabel?·backLabel?·tone?
FaqListlivelexpdfAuf-/zuklappbare Frage-Antwort-Liste (natives Accordion, es ist immer nur EINE Frage offen): faqs = [{q, a}]. title = optionale Überschrift. Für FAQ-Inhalte, Anleitungs-Fragen, Wissenssammlungen — bei langen Antworten besser als eine flache Liste.
title?·faqs
ProsConslivelexpdfPro/Contra-Gegenüberstellung in zwei Spalten (auf schmalen Flächen gestapelt): entries = [{text, kind: pro|con}]. prosLabel/consLabel überschreiben die Spalten-Titel (Default „Dafür“/„Dagegen“). Für Produkt-Reviews, Entscheidungen, Vergleiche — immer BEIDE Seiten befüllen, wenn Daten da sind.
title?·entries·prosLabel?·consLabel?
ChangeListlivelexpdfChangelog-/Release-Notes-Block: changes = [{kind, items}] mit kind added|changed|fixed|removed|deprecated|breaking|security|note — jede Gruppe bekommt Badge + Farbton, Einträge erscheinen gestaffelt. version + date als Kopfzeile. Für Software-Releases, Produkt-Updates, Vertrags-Änderungen.
version?·date?·changes
ScoreRowlivelexpdfKritiker-/Provider-Scores nebeneinander (IMDb, Rotten Tomatoes, Metacritic, RAWG …): scores = [{label, value, pct?}] — value ist der Anzeigewert (z.B. „8,4“), pct 0–100 füllt die Mini-Leiste und färbt (rot→grün). Für Filme, Serien, Spiele, Podcasts — NICHT für die persönliche Bewertung (dafür Rating).
scores
MoneySummarylivelexpdfRechnungs-/Beleg-Summenblock: totals = [{label, value, strong?}] — Zwischensummen rechtsbündig in Tabellenziffern, strong=true ist DIE Endsumme (fett, Akzentlinie darüber). Für Rechnungen, Belege, Bestellungen, Abos — Reihenfolge wie auf dem Beleg (Zwischensumme → Steuer → Gesamt).
title?·totals
NutritionFactslivelexpdfNährwert-Kacheln: nutrients = [{label, value, emph?}] — emph=true hebt die Leitzahl hervor (meist Kalorien). serving = Bezugsgröße (z.B. „pro Portion“). Für Rezepte, Produkte, Health-Einträge.
serving?·nutrients
ValiditySpanlivelexpdfGültigkeits-/Laufzeit-Leiste zwischen ZWEI Daten (Garantie, Abo, Vertrag, Visum): from/to = ISO-Daten, der Heute-Marker wandert über die Leiste, der Rest-Chip färbt sich automatisch (läuft bald ab → warn, abgelaufen → danger). label = worum es geht, fromLabel/toLabel überschreiben „Beginn“/„Ende“. Live-Ticken auf EINEN Zeitpunkt → Countdown; Prozess-Schritte → StatusTrack.
label?·from·to·fromLabel?·toLabel?
AudioPlayerlivelexpdfSchlanker Audio-Player für direkte Audio-URLs (.mp3/.m4a/.ogg/.wav): großer Play-Button (44px), Scrub-Leiste, Zeitanzeige in Tabellenziffern. title/artist als Beschriftung, duration als Vorab-Anzeige (z.B. „42:10“). Lädt die Datei erst beim ersten Play. Für Sprachmemos, Podcast-Episoden, Musik-Snippets — NICHT für YouTube (dafür VideoPlayer).
url·title?·artist?·duration?
StatusTracklivelexpdfHorizontale Prozess-Leiste (Wizard-Stil): steps = [{label, state: done|current|pending}] — erledigte Schritte mit Haken, der aktuelle pulsiert, kommende bleiben gedimmt, Verbindungslinien füllen sich. Für Bestell-Status, Bug-Lifecycle, Bewerbungs-Pipelines, Onboarding — 2 bis 8 Schritte, NICHT für datierte Verläufe (dafür Timeline).
title?·steps
MediaStatuslexWatchlist-Status (Medien, interaktiv, app-only): tippbares Segment Wunsch/Läuft/Fertig, schreibt den media_status. NUR im Detail eines existierenden Medien-Eintrags (Film/Serie/Buch/Spiel) mit echter entityId = content.id; status = aktueller Zustand; progressDetail/rating = read-only Anzeige (volle Bearbeitung dropped/repeat/Fortschritt/Rating über die Bar-Aktion „Status“). Der Renderer wird von der mediathek-Capability beigesteuert. Kritiker-Scores anzeigen → ScoreRow; Prozess-Fortschritt allgemein → StatusTrack.
entityId·status·progressDetail?·rating?
HighlightslivelexpdfMarkierte Passagen im Textmarker-Look (Kindle-Highlights): quotes = die hervorgehobenen Sätze, jeder mit Marker-Hintergrund und feiner Anführung. title überschreibt „Highlights“. Für Buch-/Film-/Spiel-Notizen, Zitate aus Artikeln, das Beste aus einem Podcast.
title?·quotes
MiniMonthlivelexTermin-Block: Datums-Kachel (Wochentag-Band + große Tageszahl + Monat) neben Uhrzeit/Label, dazu die relative Einordnung („in 11 Tagen“, „heute“) und bei endDate der Zeitraum; vergangene Termine dimmen. date = ISO-Datum (gern mit Uhrzeit), label = Kontextzeile (z. B. Ort oder Zeitfenster). display=„month“ zeigt stattdessen den kompakten Monatskalender mit markiertem Datum, Zeitraum-Band und Heute-Ring. Für Events, Termine, Reisen, Fristen — EIN Blick statt Datums-Text.
date·endDate?·label?·display?
HeatmaplivelexAktivitäts-Heatmap (GitHub-Stil): values = ein Wert pro Tag in zeitlicher Reihenfolge (0 = leer, höher = intensiver), startDate = Datum des ersten Werts (Wochen-Raster startet Montag), max überschreibt die Skala. Für Gewohnheiten, Trainings-Streaks, Schreib-Routinen, Commits — Muster auf einen Blick, kein Chart-Ersatz.
label?·values·startDate?·max?
LineItemslivelexpdfRechnungs-/Stücklisten-Positionen: lineItems = [{name, qty?, price?}] — Menge als Präfix-Chip, Preis rechtsbündig in Tabellenziffern. Für Rechnungspositionen, Bestellinhalte, Ersatzteil-/Stücklisten — darunter passt MoneySummary für die Summen.
title?·lineItems
PeopleRowlivelexpdfPersonen-Reihe mit Initialen-Avataren: people = Namen — jeder bekommt einen deterministisch getönten Kreis (Name→Farbton), überlappend gestapelt, ab acht ein +N-Chip. label = Rolle der Gruppe (z.B. „Team“). Für Projekt-Teams, Teilnehmer, Stakeholder, Speaker.
label?·people
CopyFieldlivelexpdfKopierbarer Kenncode (Tracking-Nummer, Seriennummer, ISBN, IBAN, Gutschein): value monospaced mit Ein-Tap-Kopieren und Erfolgs-Feedback direkt am Button. label = was der Code ist. Für alles, was man in eine andere App einfügen will — statt fehleranfälligem Markieren.
label?·value·mono?
RangeBarlivelexpdfEinordnung EINES Werts in eine Spanne: value zwischen min und max als Marker auf einer Leiste, minLabel/maxLabel beschriften die Enden, unit hängt an den Wert. Für Preis-vs-Marktspanne, Blutdruck im Referenzbereich, Gehalt in der Bandbreite — WO ein Wert liegt, nicht wie er sich entwickelt (dafür Sparkline).
label?·min·max·value·unit?·minLabel?·maxLabel?
CountdownlivelexLive tickender Countdown bis zu einem Zeitpunkt: target = ISO-8601 (z.B. 2026-12-24T18:00:00), title = worauf gezählt wird, doneText erscheint nach Ablauf (Default „Jetzt!“). Tage/Stunden/Minuten/Sekunden als Ziffern-Kacheln mit sanftem Tick, tone ai = violett. Für Deadlines, Events, Launches — NICHT für vergangene Zeitpunkte.
target·title?·doneText?·tone?
HoursTablelivelexpdfÖffnungszeiten-Tabelle (schema.org openingHoursSpecification): hours = [{day, opens?, closes?, closed?}] — day als Wochentag („Montag“ oder „Mo“), opens/closes als HH:MM, closed=true für Ruhetage. Die heutige Zeile ist hervorgehoben und ein Live-Chip zeigt „Jetzt geöffnet“/„Geschlossen“ anhand der aktuellen Uhrzeit. Für Orte, Restaurants, Praxen, Läden.
title?·hours·note?
MetaChipslivelexpdfKompakte Fakten-Chips unter dem Titel (Rezept/Film/Buch-Eckdaten): items = [{label, value}] — z. B. Vorbereitung „20 min“, Portionen „4“, Laufzeit „128 min“, Lesezeit „5 min“. Label klein, Wert betont, alles in EINER umbruchfähigen Reihe. Für 2–6 Kern-Fakten, die keine KeyValue-Tabelle verdienen.
items
WhereToWatchlivelexpdfStreaming-Verfügbarkeit (TMDB/JustWatch Watch-Providers): providers = [{name, kind?, logo?}] mit kind flatrate (Abo) | rent (Leihen) | buy (Kaufen) — gruppiert nach Art, Provider als Logo-Chips. link = „Alle Anbieter“-Ziel (JustWatch), country = Ländercode der Angaben. Für Filme und Serien — wo läuft das gerade?
providers·link?·country?
BylinelivelexAutoren-Zeile unter einer Überschrift: name mit Initialen-Avatar (deterministischer Farbton wie PeopleRow), meta = Datum, Lesezeit, Publikation als eine gedimmte Zeile. Für Artikel, Interviews, Kolumnen — NICHT für Personen im Inhalt (dafür PeopleRow).
name·meta?
DocMetalivelexEingeklappte Kopf-/Fußzeilen der gescannten Quelle (Druckdatum, URL-Zeile, Seitenzahlen): rows = die Original-Zeilen, label = Zusammenfassung im Summary (Default „Kopf-/Fußzeilen der Quelle“). Bewahrt Provenienz ohne den Lesefluss zu stören; im PDF bewusst weggelassen. NUR für solchen Quellen-Schrott aus OCR/Scans — Quellen-Links → References, Autor+Datum eines Artikels → Byline.
label?·rows
ReferenceslivelexQuellen-/Literatur-Block am Dokumentende: links = [{label?, url}] — jede Quelle eine Zeile, label = Anzeigename (sonst die gekürzte URL). Für Quellenangaben aus Scans, Fußnoten-URLs, weiterführende Links — als klar abgesetzter Block statt nackter URLs im Fließtext.
title?·links
BankDetailslivelexBankverbindung aus Rechnung/Brief: iban (gruppiert dargestellt, Ein-Tap-Kopieren ohne Leerzeichen), optional bic, holder (Empfänger), reference (Verwendungszweck, eigener Kopier-Knopf), amount (Betrag als Text, z.B. „969,61 €“). Nur mit serverseitig prüfziffern-validierter IBAN emittieren (ext.bank_details) — nie aus unsicherer Erkennung raten.
iban·bic?·holder?·reference?·amount?
KickerlivelexDachzeile ÜBER einer Überschrift (Magazin/Zeitung): kurzes Ressort- oder Themen-Label („Technologie“, „Interview“, „Exklusiv“) — klein, versal, gesperrt, in Akzentfarbe. Immer direkt vor dem Titel, nie als eigenständige Überschrift.
text
LeadlivelexVorspann/Standfirst direkt nach Titel und Byline: der Anreißer-Absatz des Artikels, größer und ruhiger gesetzt als Fließtext. NUR für den ersten zusammenfassenden Absatz — der Artikeltext selbst bleibt Markdown.
text
LetterHeadlivelexBriefkopf (DIN-Brief/Rechnung), max 1x ganz am Dokumentanfang: sender = einzeilige Absenderzeile (klein, über dem Anschriftfeld), recipient = mehrzeiliger Empfängerblock, meta = rechte Spalte [{label, value}] (Datum, Kunden-Nr., Rechnungs-Nr., Ort). Ersetzt die losen Adress-Absätze am Briefanfang — eine Adresse IM Inhalt (Ort, Veranstaltung) → LocationCard, sonstige Eckdaten → KeyValue.
sender?·recipient·meta?
SignatureLinelivelexUnterschriften-Zeile am Brief-/Vertragsende: Linie, darunter name und optional role (Funktion) sowie place/date („Berlin, 15.04.2026“). Für Grußformel-Abschlüsse, Verträge, Bescheinigungen.
name·role?·place?·date?
CouponlivelexGutschein/Rabatt-Code als Ticket: code zentriert monospaced mit Ein-Tap-Kopieren, label = was der Code bringt („20 % auf alles“), validUntil = Gültigkeit, condition = Kleingedrucktes. Gestrichelter Ticket-Rahmen. Für Coupons aus Flyern, Newslettern, Bonusprogrammen.
code·label?·validUntil?·condition?
LocationCardlivelexPostadresse als handelbarer Block: address (mehrzeilig erlaubt), label = wozu sie gehört (z.B. „Veranstaltungsort“), optional lat/lon. Rendert die Adresse mit Karten-Link (geo:/Maps aus Koordinaten oder Adresse) und Kopier-Knopf. Für erkannte Standorte aus Scans, Orte in Terminen, Absender-Adressen.
label?·address·lat?·lon?
ContactChannelslivelexTappbare Kontakt-Kanäle als Chip-Reihe: channels = [{kind: email|phone|web, value, label?}] — E-Mail öffnet mailto:, Telefon tel:, Web den Link. Icon je Kanal, Wert gekürzt, ≥44px Ziele. Für Kontakte, Organisationen, Support-Blöcke — EIN Tap statt Abtippen.
channels
HeadinglivelexpdfFreie Überschrift (level h1–h3, Default h2) für Dokument-/Berichts-Gliederung im Fließtext. NUR im Dokument-Kontext — Gruppen-Titel in komponierten Ansichten/Streams ist SectionHeader (mit Kicker-Optik), ein Karten-Titel gehört in die Karte selbst.
text·level?
TextlivelexpdfReiner Klartext-Absatz — Markdown wird NICHT interpretiert (sicher für wörtliche Zitate/rohe Strings mit Sonderzeichen). Formatierter Fließtext mit Listen/Links/Fett → Markdown; gekürzter Detail-Lesetext mit mehr/weniger → BodyText.
text
SpacerlivelexpdfVertikaler Abstand (height in px, 2–200) für bewusste Luft zwischen Dokument-Blöcken. NUR wenn Abstand die Aussage ist — thematischer Schnitt mit Linie → Divider, neuer benannter Abschnitt → SectionHeader/Heading.
height
PageBreaklivelexpdfErzwungener Seitenumbruch im PDF/Druck (keine Props). Am Bildschirm nur ein dezenter Marker — für sichtbare Trennung im UI Divider oder Spacer verwenden.
— keine Props
KpiRowlivelexpdfKennzahlen-Zeile für Dokumente/Berichte: 1–5 KPIs nebeneinander, items = [{label, value, unit?, tone?}], items darf $ref sein. tone (neutral|accent|success|warning|danger) nur sparsam: accent für die eine Kennzahl, auf die es ankommt, success/warning/danger für einen Zustand, den Lesende bemerken sollen. GENAU EINE hervorgehobene Kennzahl → Kpi; Kennzahlen mit Trend-Chips in komponierten Ansichten → MetricRow.
items
SourceslivelexpdfQuellenverzeichnis ans Ende von Berichten/Recherchen: nummerierte Liste mit Titel-Link + gekürzter URL, items = [{title, url, published?}] (gern $ref auf web_search-Treffer). Einzelne weiterführende Links im Fluss → LinkRow.
title?·items
Cards pack-brainz-cards · 102 Typen
TaskCardliveAufgaben-Karte im Stream: EIN abhakbares To-do mit Erledigt-Status — nicht ReminderCard (nur Weck-Zeitpunkt, kein Status), nicht EventCard (Termin mit Zeit/Ort), mehrere Aufgaben als Liste → TaskList. due = Fälligkeit als Anzeigetext, done = erledigt, heat = Glut-Stufe 0–3.
title·time?·heat?·tags?·pinned?·entityUuid?·due?·done?
ReminderCardliveErinnerungs-Karte: etwas soll zu einem Zeitpunkt wieder hochkommen — kein Erledigt-Status (dafür TaskCard), kein Termin mit Ort/Dauer (dafür EventCard). remindAt = Erinnerungszeitpunkt als Anzeigetext, heat = Glut-Stufe 0–3.
title·time?·heat?·tags?·pinned?·entityUuid?·remindAt?
GenericCardliveGenerische Karte aus dem Feld-Schema (Default-Render, Phase 3) für content_types mit render.card='generic'. contentType treibt Label/Icon/Farbe; pills = Akzent-Chips (aus pill/amount/date-Feldern); image+imageTreatment = Bild; imageTreatment='gallery' + images[] = Foto-Mosaik (z.B. resultType 'galerie'); subtitle/body = Text. Neuer Typ braucht so keinen eigenen Karten-Code.
title·time?·heat?·tags?·pinned?·entityUuid?·contentType?·subtitle?·body?·image?·images?·steps?·ingredients?·rating?·ratingMax?·ratingCount?·tips?·imageTreatment?·pills?
TicketCardliveTicket-Karte NUR für scanbare Reise-/Eintrittsdokumente (Boarding-Pass / Bahn-Platzkarte / Event-Ticket) — der Termin selbst ist eine EventCard. subtitle = Route oder Züge, pills = Akzent-Chips (Sitz/PNR/Klasse/Wagen), ticketKind = 'boarding_pass'|'rail'|'event', barcodeKind = 'PDF417'|'Aztec'|'QR' (steuert den Barcode-Streifen-Stil); der scanbare Barcode lebt im Detail-Sheet. secret = optionaler Kenncode (PNR/Buchungscode): erscheint MASKIERT mit Auge (lokales Anzeigen) + Kopieren — der Wert landet NIE in einer Action.
title·time?·heat?·tags?·pinned?·entityUuid?·subtitle?·ticketKind?·barcodeKind?·secret?·pills?
DeviceCardliveBrainz-Geräte-Karte: Smart-Home-Gerät (Matter/HomeKit). subtitle = Hersteller/Typ, room = Raum, ecosystem = 'matter'|'homekit', deviceType = Geräteart, codeStored = Setup-Code hinterlegt. SECRET-SAFE: zeigt NIE den Code/QR im Klartext — secret rendert MASKIERT mit Auge (lokales Anzeigen) + Kopieren, der volle Code lebt weiter im Detail (Tap-to-reveal).
title·time?·heat?·tags?·pinned?·entityUuid?·subtitle?·room?·ecosystem?·deviceType?·codeStored?·secret?
BookmarkCardliveBookmark-Karte für einen gespeicherten WEB-LINK (Artikel/Seite) — Film/Buch/Serie mit Poster → MediaCard, eigenes Foto als Hauptinhalt → PhotoCard. domain = Anzeige-Domain, readMinutes = geschätzte Lesezeit, image = OG-Preview (https oder data:image).
title·time?·heat?·tags?·pinned?·entityUuid?·domain?·readMinutes?·image?
PhotoCardliveFoto-/Plakat-Capture: das BILD ist der Hauptinhalt (eigenes Foto/Scan; https oder data:image) — nicht BookmarkCard (Link mit OG-Preview), nicht MediaCard (Werk mit Poster); mehrere Bilder → Gallery. aspect: wide (16:10) oder square, caption = OCR-/Bildunterschrift.
image·title?·caption?·aspect?·time?·heat?·tags?·pinned?
MediaCardliveMedien-Karte für ein WERK (Film/Buch/Serie/Spiel/Hörbuch/Podcast/Musik) mit Poster — nicht BookmarkCard (Web-Link) und nicht PhotoCard (eigenes Foto). variant: poster = vertikales 2:3-Poster + Titel darunter (Shelf) · hero = großes Poster + Body (Featured) · row = Zeile (Default); subtitle = Autor/Jahr, status = z.B. Watchlist, rating = 0–10, provider = Streaming-Anbieter (z.B. Netflix).
title·time?·heat?·tags?·pinned?·entityUuid?·variant?·mediaType·image?·subtitle?·status?·rating?·provider?
ContactCardliveKontakt-Karte für EINE Person als eigener Stream-Eintrag — Teilnehmer-Avatare an einem Termin → AttendeeRow, erwähnte Personen als Chips → EntityChips. title = Name, role = Rolle/Firma, relation = Beziehung (z.B. Familie), image = Avatar (sonst Initialen).
title·time?·heat?·tags?·pinned?·entityUuid?·role?·relation?·image?
ExpenseCardliveAusgaben-/Beleg-Karte für EINE Transaktion mit Betrag als Blickfang — viele Ausgaben als Kontoauszug-Liste → LensLedger. amount = Anzeigebetrag (z.B. '42,90 €'), merchant = Händler, category = Kategorie, image = optionales Beleg-Thumbnail (Foto/Scan; https, data:image oder /api/files/:id/preview).
title·time?·heat?·tags?·pinned?·entityUuid?·amount·merchant?·category?·image?
NoteCardliveNotiz-Karte für einen freien Text-Drop ohne stärkere Typ-Semantik — hat der Inhalt Fälligkeit/Status → TaskCard, eine URL → BookmarkCard, einen Betrag → ExpenseCard. body = Notiztext (gekürzt), heat = Glut-Stufe 0–3, image = optionales Vorschau-Thumbnail, wenn die Notiz aus einem Foto/Scan entstand (https, data:image oder /api/files/:id/preview).
title·time?·heat?·tags?·pinned?·entityUuid?·body?·image?
EventCardliveTermin-Karte: Ereignis mit Beginn und optionalem Ort — nicht TaskCard (abhakbares To-do), nicht ReminderCard (bloßer Weck-Zeitpunkt); Tagesagenda mehrerer Termine → DayTimeline. start = Beginn als Anzeigetext, location = Ort, scope = Sichtbarkeit (z.B. 'Familie').
title·time?·heat?·tags?·pinned?·entityUuid?·start?·location?·scope?
InsightCardliveProaktive Karte für EINE KI-Erkenntnis (Funke) im Stream — mehrere Insights zum selben Dokument → InsightStackCard, redaktionelle Home-Stimme → Briefing. KI-Framing violett: gem + kind-Eyebrow + „Weil"-Signale (reasons) + Glut-Glow; text/title = Headline, sub = Kontextzeile, actionLabel + actionType = beste Aktion (Farbe = Ergebnis-Typ; ohne Typ violett=KI-Aktion), feedback/snoozable steuern die Leiste.
text?·title?·kind?·sub?·reasons?·actionLabel?·actionIcon?·actionType?·gemIcon?·feedback?·feedbackValue?·entities?·snoozable?·time?·heat?
StackCardlivelexKanonischer Glut-Stapel: bündelt N verwandte Einträge zu EINER Karte, die mit sinkender Glut (heat) kondensiert — h3 voll (Stapel-Tiefe + Glow + CTA) über h1 ruhig bis h0 Asche-Zeile (KONZEPT §8.0, glut-stufen.md). preset = insight (Erkenntnis-Stapel: entries/docType/sourceUuid, KI-violett) | moment (Thought-Cluster: members/dominantType/timeLabel/clusterId, Typ-Akzent) | ohne = generisch (Plugin emittiert StackCard direkt und bekommt Optik + Glut-Stufen frei). accent = Akzentfarbe ("ai" = KI-Violett, sonst content_type-Farbe), eyebrow = Stapel-Label, count = Anzahl, anchorTitle/-Label/-Icon = repräsentativer Anker, chips = Arten-Reihe, cta = Aktionstext, clusterId = Bündel-ID fürs Deck. Ersetzt InsightStackCard/MomentStackCard (permanente Aliase).
title·time?·heat?·tags?·pinned?·entityUuid?·preset?·eyebrow?·accent?·gemIcon?·count?·anchorLabel?·anchorTitle?·anchorIcon?·chips?·cta?·clusterId?·docType?·sourceUuid?·entries?·dominantType?·timeLabel?·members?
InsightStackCardliveErkenntnis-Stapel (Funke): bündelt mehrere Insights ZUM SELBEN Dokument (gleiches source_uuid) zu EINER ruhigen Feed-Karte statt N Einzelkarten — gegen die Insight-Flut. Violettes KI-Framing + Stapel-Tiefe. title = Dokument-Anker, docType = dessen content_type (Icon), count = Anzahl Funken, entries = die gebündelten Erkenntnisse (Headline/kind/gem + Aktion + insightId) fürs Abarbeiten-Deck. Tap öffnet das Deck. (Alias von StackCard{preset:'insight'})
title·docType?·count?·entries·heat?·sourceUuid?
MomentStackCardliveMoment-Stapel: bündelt zeitlich dicht aufeinanderfolgende Drops (Thought Cluster, 90-s-Fenster) zu EINER Karte statt N Einzelkarten — gegen Stream-Spam bei Screenshot-Serien/Meetings. Content-Type-Akzent (kein KI-Violett). title = Kurzlabel (z.B. „5 Fotos“), timeLabel = Zeit, dominantType = häufigster content_type (Icon/Farbe), count, clusterId (für Manage-Aktionen), members = Mitglieder fürs Durchseh-Deck. Tap öffnet das Deck. (Alias von StackCard{preset:'moment'})
title·timeLabel?·dominantType?·count?·clusterId·members·heat?
SuggestionRowliveVorschlags-Zeile unter/auf einer Karte: MEHRERE antippbare Aktions-Chips aus den Rules-Engines (Collection Rules, Predictive Next, Brainflows); Kinder sind Suggestion-Komponenten. Für den ephemeren „du öffnest sonst jetzt X"-Einzelvorschlag stattdessen PredictiveRow; source steuert das Icon (rule | predictive | flow | agent).
source?
SuggestionliveEinzelner Vorschlags-Chip, NUR als Kind einer SuggestionRow (z.B. 'Zu Italien-Trip hinzufügen', 'Erinnerung setzen'). Event 'press' trägt die hinterlegte Action; label = Chip-Text, hint = optionaler Zusatz. Sind accept/reject gebunden, erscheinen Ja/Nein-Mini-Affordances (EntityChips-Idiom) neben dem Chip. id = stabile Vorschlags-Id (hintId-Slug): NUR mit id kann der Host accept/reject an den Scorecard-Kanal binden (sugact → POST /api/suggestions/:id/feedback); source = optionale Provenienz (hint_source, z.B. 'rule', 'predictive-next').
label·hint?·id?·source?
StepRowliveProvenienz-Zeile zwischen Stream-Karten (KONZEPT §8.0 'Steps statt Spine'): was das SYSTEM wann tat, bevor die Card erscheint — reine Herkunfts-Anzeige, kein Nutzer-Vorschlag (dafür SuggestionRow). icon: drop|search|spark|bulb|mail|globe|sync|bell|cal|user|check; spinning = laufender Vorgang.
icon?·text·detail?·time?·spinning?
PredictiveRowliveInline-Predictive-Row (bz-isug): GENAU EIN ephemerer „nächster"-Vorschlag unter einer Karte, KI-violett — mehrere Aktions-Chips aus Rules-Engines → SuggestionRow. text = Lead (Default „Du öffnest sonst jetzt"), label = Ziel-Titel, hint = „Weil"-Begründung; Tap „Öffnen" → on.open; ohne on.open + mit refType/refId ein openEntity{type,id,title}.
label·text?·hint?·actionLabel?·refType?·refId?
EntityRefsliveErwähnte/verglichene Einträge als anklickbare Referenz-Chips in Content-Type-Farbe — reine Anzeige ohne Bestätigen/Verwerfen; KI-Vorschlags-Zustand → EntityChips{suggestable}. Jeder Chip öffnet sein Detail via openEntity{type,id,title}. (Alias von EntityChips)
entities
FieldListlivepdfLabel/Wert-Zeilen mit optionalem Icon (Detail-Sheet) für strukturierte Metadaten (Ort, Datum, Status …) — Fließtext → BodyText, große Kennzahlen → MetricRow. value optional — ohne value wird label als Fließtext-Zeile gerendert (z.B. Subtasks); key = structured_data-Feld-Key der Zeile (Tap editiert das Feld).
rows
RichPreviewlivepdfOG-Link-Vorschau (Detail-Sheet): kompakter Block mit Bild (layoutstabil via aspect-ratio 1.91:1), Domain, Titel, Beschreibung — als großer Blickfang mit Action-Button stattdessen MediaHero. image nur https oder data:image.
image?·domain?·title?·description?
BodyTextliveKlartext-Absatz (Detail-Sheet): gekürzter Lesetext mit „mehr“-Toggle ab clampLines Zeilen — reiner Fließtext ohne Auszeichnung; formatierter Text (Listen/Links/Fett) → Markdown, KI-Destillat → AiSummary. moreLabel/lessLabel überschreiben die Beschriftung.
text·clampLines?·moreLabel?·lessLabel?
AiSummarylivepdfKI-Zusammenfassung (Detail-Sheet): destillierter Kerninhalt der Entity mit eigener KI-Identität (violett) — NUR für KI-generierte Zusammenfassungen; originaler Lesetext → BodyText. summary = der Zusammenfassungstext; keyPoints = optionale Kernpunkte, die IM Block als kompakte Liste rendern (eine KI-Einheit statt zwei Sektionen).
summary·keyPoints?
AttendeeRowlivepdfTeilnehmer-Zeile (Detail-Sheet): kompakte Avatar-Reihe der Personen an einem Termin/Inhalt (https/data:image oder Initialen, ab maxVisible ein +N-Zähler) — anklickbare Personen-Chips → EntityChips, eigenständige Personen-Karte → ContactCard. label = optionale Überschrift der Zeile.
attendees·label?·maxVisible?
LinkRowlivepdfAntippbare Link-Zeile (Detail-Sheet, 44px-Target) für externe URLs/allgemeine Sprungziele — Brainz-Einträge mit Typ-Icon → RelatedItem, Suchtreffer → DiscoveryResult. Event 'press' trägt die hinterlegte Action (z.B. navigate mit params.url); external zeigt das Extern-Indiz.
label·hint?·external?
TagRowlivepdfTag-Chips des Eintrags als eigene Zeile (Detail-Sheet) — reine Anzeige der vergebenen Tags; generische Text-Pillen → Chips{role:'plain'}, klickbare Filter → Chips{role:'facets'}, Entity-Referenzen → EntityChips. (Alias von Chips)
tags
MediaHerolivepdfGroßes Vorschaubild (Detail-Modul, RichPreview-Ausbau): OG/YouTube-Hero 1.91:1 mit Domain-Badge und optionalem Action-Button (z.B. „Im Web öffnen“) — für DEN Blickfang oben im Detail; kompakte Vorschau im Textfluss → RichPreview. Event 'press' trägt die hinterlegte Action; image nur https oder data:image.
image·title?·domain?·actionLabel?
QuickActionsliveQuick-Actions-Sektion (Detail-Modul): reiner Container mit Caps-Überschrift + 2-Spalten-Grid für Manifest-Aktionen der Entity. Kinder sind ausschließlich QuickActionItem; die Items referenzieren nur Manifest-Action-IDs.
title?
QuickActionItemliveEinzelne Quick-Action-Kachel, NUR als Kind von QuickActions: Icon im getönten Quadrat, Label, 2-zeilige Beschreibung, optionale actionLabel-Pille — führt eine Manifest-Action aus, kein freier Link (dafür LinkRow). id = Manifest-Action-ID, severity steuert die Tönung (info|warning|subtle).
id·icon?·label·description?·actionLabel?·severity?
VorgangRowliveEine Vorgangs-Zeile aus `app_public.actions` (Heute → „Wartet auf dich“, Detail → „Vorgänge zu diesem Eintrag“; home-klarheit-2026-09.md §3, Entscheidung 3 vom 09.09.: der Wartet-Block ist eine render_ui-Komposition, kein Sonder-DOM): Icon nach Art, Titel, Meta-Chips (Art · Quelle · Frist · Status · Lücken), optional EIN primärer und EIN sekundärer Knopf. Knöpfe und 'press' referenzieren NUR Manifest-Action-IDs (vorgang-*) und tragen die Vorgangs-Id als params.vorgangId — die Wirkung liegt beim Host (runCapabilityAction), die Zeile ist reine Daten.
id·kind?·title·meta?·warn?·done?·primary?·secondary?
RuleHintliveHinweis-Banner der Rules-Engine (Detail-Modul, volle Breite): dynamischer SYSTEM-Hinweis zur Entity, z.B. „Entwurf lange inaktiv“ — statische inhaltliche Tipps → Tip. severity = info|warning|subtle; warning zeigt den deutlicheren Rahmen.
severity·label·description?
RelatedListliveSektion für verwandte/verknüpfte Inhalte (Detail-Modul, kanonisch): source = related (Default; per Vektor-Similarity GEFUNDENE Nachbarn, Caps-Überschrift mit optionalem Count in Klammern) | linked (EXPLIZITE Verknüpfungen aus dem Entity-Graph, Kopfzeile mit count-Badge + label). Kinder sind RelatedItem. Ersetzt LinkedContent (permanenter Alias).
source?·title?·label?·count?
RelatedItemliveZeile eines verwandten/verknüpften BRAINZ-Inhalts (Kind von RelatedList oder LinkedContent): Typ-Icon, einzeiliger Titel, optionale Score-Pille (pct 0–100) + Chevron — externe URLs → LinkRow, Suchtreffer → DiscoveryResult. Event 'press' trägt die Drill-In-Action (openEntity {type, id}); Referenz via numerischer id (Related) ODER uuid (Backlinks).
id?·uuid?·kind·title·contentType?·pct?·preview?
DiscoveryResultlivelexAntippbare Treffer-Zeile für SUCH-/Discovery-Ergebnisse (Explore-Discovery): gefundene Ressource mit optionalem Icon, Titel und Untertitel — Ähnlichkeits-Nachbarn im Detail → RelatedItem, externe Links → LinkRow. icon aus dem Icon-Service; Event 'press' trägt die hinterlegte Action (z.B. openEntity).
icon?·title·subtitle?
LinkedContentliveSektion „Verknüpfte Inhalte“ (Detail-Modul): EXPLIZITE Verknüpfungen aus dem Entity-Graph (content_links/Backlinks) — bloß ähnliche, nicht verknüpfte Inhalte → RelatedList{source:'related'}. Kopfzeile mit count-Badge, Kinder (RelatedItem) als Liste darunter. (Alias von RelatedList)
count·label?
SectionHeaderliveSektions-Überschrift (Caps-Label + optionales Akzent-Icon) zum Gliedern einer Detail-Sektion, z.B. „Saison“, „Allergene“ — NUR die Überschrift, kein Container: der Inhalt folgt als Geschwister (z.B. BodyText). icon aus dem Icon-Service (sun|globe|alert|swap|leaf|…).
icon?·label
SeasonCalendarliveSaisonkalender (Ingredient-Knowledge): SVG-Ring mit 12 Monatspunkten (aktive Monate akzentuiert, aktueller Monat pulsiert, Mitte = Monats-Anzahl) + Monats-Strip Jan–Dez + optionale Notiz. months = aktive Monate 1–12.
months·note?
StatBarliveQuick-Stat-Leiste (Ingredient-Knowledge): 1–4 getönte, live-fähige Kacheln mit Icon, großem Wert und Label — schlichte Kennzahlen-Reihe ohne Tönung/Live → MetricRow. tone = on|warn|safe tönt die Kachel; liveMonths + liveLabel heben die Kachel LIVE hervor, wenn der aktuelle Monat aktiv ist („Jetzt Saison“).
stats
ChipslivelexKanonische Chip-/Pillen-Reihe: role wählt das Idiom — plain (Default; statische Text-Pillen aus chips, ab max ein „+N“-Chip) · tags (Eintrag-Tags aus tags, mit Tag-Icon) · facets (KLICKBARE Filter-Pillen aus items, horizontal scrollbar; Event select trägt {id}, role 'divider' im Item rendert einen Trenner, active/ai heben hervor). BINDUNG: on.select nimmt EINE Action für die ganze Reihe; die getroffene Chip-id reicht der Renderer nach — bei setHostFilter als args.id, bei sendMessage ersetzt sie den Platzhalter {id} im Text (ohne Platzhalter senden alle Chips dasselbe). Form immer on.select = { action, args } — ohne diesen Wrapper verwirft die Validierung die Bindung stillschweigend. Ersetzt ChipRow/TagRow/FacetBar (permanente Aliase); Entity-Referenzen → EntityChips.
role?·chips?·max?·tags?·items?
ChipRowliveChip-Reihe (Ingredient-Knowledge): eine STATISCHE Text-Pille pro Eintrag, ab `max` ein „+N“-Chip — für Anbauregionen, Nährwert-Highlights, kulinarische Verwendung; klickbare Filter → Chips{role:'facets'}, Eintrag-Tags → Chips{role:'tags'}. (Alias von Chips)
chips·max?
EntityChipsliveKnowledge-Entity-Chips (kanonisch, ersetzt EntityRefs): an einem Inhalt erwähnte Personen/Orte/Firmen/Events, inkl. bestätigbarer KI-Vorschläge. entities = [{id, kind, title, initials?, confirmed?, suggested?, hint?, status?}]; confirmed zeigt ein Häkchen, suggested rendert den KI-Vorschlag (gestrichelt-violett) mit Bestätigen/Verwerfen; suggestable = true schaltet den Vorschlags-Modus für ALLE (unbestätigten) Chips, ohne jedes entity einzeln zu markieren. status = kleines Zustands-Badge am Chip-Ende ({label, tone ok|warn|neutral}, z.B. „wartet“ amber) — für Workflow-Zustände; hint bleibt der 9px-KI-Grund. Events: select (Chip öffnen), confirm/reject (Vorschlag).
suggestable?·entities
CollabCardlivelexZusammenarbeits-Karte pro Person (Delegations-/Sharing-Übersicht): Kopf mit Initial-Avatar, Richtung („Bei“ = von dir übergeben · „Von“ = an dich) + Name und leisem Offen-Zähler; darunter stille Status-Zeilen — Typ-Icon in Typfarbe, Titel, rechts ein Mikro-Status (wait amber · seen Ring · progress blau · done grünes Häkchen) statt lauter Badges. Tap auf eine Zeile öffnet den Inhalt (Event select; Host-Delegation via data-act/data-ent-id wie EntityChips). Aktionen (annehmen, erinnern) wohnen im Puls/Detail — die Karte ist Übersicht.
person·openCount?·items
FacetBarlivelexFilter-Chip-Reihe (Explore-Facetten): horizontal scrollbare, KLICKBARE Pillen zum Filtern einer Fläche — statische Anzeige-Pillen → Chips{role:'plain'}, Eintrag-Tags → Chips{role:'tags'}. items = [{id, label, icon?, active?, ai?, role?}]; role 'divider' rendert einen Trenner, 'chip'/'action' eine Pille; active hebt die Pille hervor, ai färbt sie KI-violett. Event 'select' trägt die getroffene Auswahl ({id}). BINDUNG: on.select nimmt EINE Action für die ganze Reihe; die getroffene Chip-id reicht der Renderer nach — bei setHostFilter als args.id, bei sendMessage ersetzt sie den Platzhalter {id} im Text (ohne Platzhalter senden alle Chips dasselbe). Form immer on.select = { action, args } — ohne diesen Wrapper verwirft die Validierung die Bindung stillschweigend. (Alias von Chips)
items
AllergenBlockliveAllergen-Banner (Ingredient-Knowledge): leere Liste → grünes „Keine bekannten Allergene“; sonst Warn-Banner (Akzent) mit Allergen-Pillen.
allergens
SubstituteListliveAlternativen & Ersatz (Ingredient-Knowledge): Chip je Substitut mit optionalem vegan-Marker (Blatt) und Kontext (title), ab `max` ein „+N“-Chip.
items·max?
RatinglivelexpdfSternebewertung (Molekül): fraktionale Sterne ohne Layout-Shift, inline — NUR für Bewertungs-Werte; sonstige Kennzahlen → MetricRow/StatBar. rating = Wert, ratingMax = Skala (Default 5/10), ratingCount = Stimmen.
rating·ratingMax?·ratingCount?
GallerylivelexpdfFoto-Mosaik (Molekül): MEHRERE Bilder als Raster (2 · 3er · 2×2 + „+N“) — EIN Bild als Stream-Karte → PhotoCard, als Detail-Hero → MediaHero. images = URLs (https/data:/blob:/api).
images
IngredientListlivelexpdfZutatenliste (Molekül): tabellarisch, Menge rechtsbündig + Name — NUR für Zutaten/Mengen-Paare; generische Label/Wert-Zeilen → FieldList, Arbeitsschritte → StepList. ingredients = [{amount?, name}].
ingredients
PlaceListlivelexStrukturierte Orte (Molekül, Planungs-Welle): antippbare Orts-Zeilen mit optionalem Foto, Typ·Warum-Hinweis und Maps-Link (Koordinaten bevorzugt, sonst Name + near). Für Reiseplan-Stopps, Tour-Stationen, Event-Locations — EINE Adresse mit Kopier-Aktionen → LocationCard, die reine LAGE → GeoMap. places = [{name, type?, why?, lat?, lng?, image_url?, website?}].
places·near?
StepListlivelexpdfSchritt-für-Schritt (Molekül): geordnete, nummerierte Liste für Anleitungen/Rezepte/Abläufe („So funktioniert es“) — NICHT abhakbar (abhakbare To-dos → TaskList), Zutaten → IngredientList, Wochenplan mit Zeitangaben → Timeline. steps = Texte ODER [{title, text?}] (Titel fett, Erklärung darunter).
steps
TiplivelexpdfTipps/Hinweise (Molekül): akzent-getönte Callout-Blöcke für STATISCHE inhaltliche Hinweise — dynamische System-Hinweise der Rules-Engine → RuleHint. tips = Texte.
tips
AdaptiveSectionlivelexAdaptive-Home-Sektion: getitelter VERTIKALER Gliederungs-Rahmen (z. B. 'JETZT', 'Heute Abend') — horizontale Schienen → Shelf/Strip. title = Überschrift, tone = warm|cool|calm|relaxed|neutral (Akzent-Hinweis); Kinder = Sektion-Inhalt (z. B. eine MediaCard als Fokus).
title?·tone?
BriefinglivelexpdfEditorial-Briefing der Home (Stimme des KI-Redakteurs): optionaler eyebrow (Eyebrow-Zeile), title = fette Schlagzeile, text = lesbarer Fließtext. tone = ai (violettes KI-Framing, Default) | neutral. Ersetzt die graue SectionHeader+BodyText-Behelfslösung.
eyebrow?·title·text?·tone?
PullQuotelivelexpdfEditoriales Pull-Quote: EINE herausgehobene Aussage in enger Display-Type mit Akzent-Leiste — der pointierte Kern eines Briefings, ein KI-Highlight oder DAS markanteste Zitat eines Dokuments (OCR-Designer). text = die Aussage, cite = optionale Quelle/Urheber. Sparsam einsetzen (max. 1 pro Home/Abschnitt).
text·cite?
MetricRowlivelexpdfKennzahlen-Reihe auf einen Blick: 2-4 schlichte Blöcke mit großer Zahl (value) + kleinem Label — für die Tagesbilanz aus echten Signalen (z. B. 8 Termine, 4 Calls, 2 h frei); getönte/Live-Kacheln im Detail → StatBar. tone ai = violette Werte; Werte NUR aus vorhandenen Daten, nie erfinden.
items·tone?
SpotlightlivelexpdfShowpiece die eine Sache: featured Karte mit langsam rotierendem KI-Halo (conic-gradient). eyebrow (opt. Dachzeile) + title (Schlagzeile) + note (opt. ein Satz). tone ai = violetter Halo (Default). Sparsam, max. 1 pro Home.
eyebrow?·title·note?·tone?
TaskListlivelexpdfAbhakbare, KURZE kuratierte Aufgabenliste (max 8): items = [{title, uuid?, done?, due?}] — EINE Aufgabe als Karte → TaskCard, die lange gruppierte Voll-Liste → LensTaskList, nicht abhakbare Anleitungsschritte → StepList. Abhaken setzt den Status direkt (uuid); im Free-Layout uber den vorkomponierten ref tasks:focus platzieren.
title?·items
NewsBriefinglivelexpdfStrukturierter KI-Tagesnews-Überblick (Morgen-Home): headline (Saira-Schlagzeile) + sections [{label, icon?, summary, tags?}] (Weltgeschehen/Tech/Wirtschaft/Gesellschaft/Gute Nachrichten). Reine Anzeige (Daten, keine KI-Stimme, neutral). Uber den vorkomponierten ref news:briefing platzieren.
headline·sections·cta?
ShelflivelexAdaptive-Home-Medien-Schiene: horizontale, snap-scrollbare Reihe VOLLER Karten (Filmabend/Medien; Kinder z. B. MediaCard) — kompakte Explore-Kärtchen (StripItem) → Strip, vertikale Sektion → AdaptiveSection. title = Überschrift, hint = optionaler Zähler.
title?·hint?
StriplivelexHorizontal scrollbare Karten-Schiene (Explore-Rail): Container NUR für kompakte, antippbare StripItem-Karten — große Medien-Karten in einer Schiene → Shelf. title = Caps-Überschrift, emptyLabel = Hinweistext, wenn keine Kinder vorhanden; Kinder tragen ihre eigenen Aktionen.
title?·emptyLabel?
StripItemlivelexKompakte, antippbare Karte, NUR als Kind einer Strip-Schiene: optionales Cover-Bild, Quellen-Eyebrow und Titel — vollwertige Stream-Karten gehören nicht hierher. image nur https/http/api-relativ; Event 'press' trägt die hinterlegte Action.
image?·source?·title
DayTimelinelivelexAdaptive-Home-Tagesagenda / Typ-Linse Termine (TypeView): getypte Zeit-Zeilen (Termine/Erinnerungen). title = Überschrift, today = HEUTE-Timeline (aktiviert Vergangen/Jetzt/Nächster-Hervorhebung + Fortschritts-Spine anhand der Uhrzeit), items = [{time, title, kind:'event'|'reminder', location?, allDay?, day?, dayLabel?, uuid?, contentType?, state?}]. `state:'past'|'next'` setzt Vergangen/Naechster AUSDRUECKLICH — noetig ueber mehrere Tage hinweg, wo die Timeline aus der blossen Uhrzeit nichts ableiten kann (Termin-Linse); diese Angabe gewinnt vor der today-Herleitung. Bei >1 day wird je Tag eine Trennzeile (dayLabel) gesetzt. Mit uuid öffnet die Zeile das Detail (press → open).
title?·today?·items
LensMasonrylivelexTyp-Linse Bilder/Notizen (TypeView): Pinterest-artiges, spaltenbasiertes Masonry-Raster gleichartiger Inhalte. items = [{uuid?, title?, imageUrl?, snippet?, aspect?, contentType?}]; ohne imageUrl wird eine Text-Kachel (title + snippet) gerendert (Notiz-Galerie). Mit uuid öffnet die Kachel das Detail (press → open). Der Host setzt beim Morph view-transition-name pro Kachel (data-uuid).
title?·columns?·items
LensTaskListlivelexTyp-Linse Aufgaben (TypeView): lange, nach `group` (z. B. Heute/Diese Woche/Später) gruppierte Tasklist. items = [{uuid?, title, done?, due?, dueSoon?, priority?:'hi'|'mid'|'lo', group?, contentType?}]. Checkbox schaltet den Status (setContentStatus), die Zeile öffnet das Detail (press → open), Griff = Ziehen zum Umsortieren (reorder).
title?·items·collapsible?·addable?
LensReaderlivelexTyp-Linse Lesezeichen (TypeView): Link-Wall gleichartiger Inhalte. items = [{uuid?, title, url?, domain?, imageUrl?, snippet?, contentType?}]; je Eintrag OG-Bild (falls vorhanden), Domain + Titel + optionaler Auszug, große Tap-Ziele. Die Karte öffnet das Detail (press → open).
title?·items
LensGridlivelexTyp-Linse Personen/Medien (TypeView): gleichmäßiges Raster aus quadratischen Kacheln (Avatar/Cover). items = [{uuid?, title, subtitle?, imageUrl?, contentType?}]; je Kachel Bild (oder Initiale) + Titel + optionaler Untertitel. Die Kachel öffnet das Detail (press → open).
title?·columns?·items
PlaceCardlivelexOrts-Karte (Cover): Bild-Hero mit Kategorie- + Entfernungs-Overlay, darunter Name, Rating (Sterne + Anzahl) und Adresse. uuid öffnet das Detail (press → open), saved = Bookmark-Status. Genutzt in der Orte-Linse und für Ortssuche-Ergebnisse.
uuid?·title·category?·rating?·ratingCount?·address?·distance?·image?·saved?·braveId?·lat?·lng?·contentType?
LensPlaceslivelexTyp-Linse Orte (TypeView): vertikaler Feed aus Orts-Karten. Kinder = PlaceCard. title = optionale Überschrift.
title?
LensDeviceslivelexTyp-Linse Geräte (TypeView): nach Raum oder Geräte-Typ gruppiertes Kachel-Raster aller Smart-Home-Geräte (Geräte-Bibliothek). groupBy = 'room' | 'deviceType' (Default 'room'), je Gruppe Kopfzeile (Name + Anzahl). items = [{uuid?, title, subtitle?, deviceType?, ecosystem?, room?, codeStored?, linkCount?, contentType?}]; je Kachel teal-akzentuiertes Tile mit Typ-Icon, Name, 'Hersteller · Typ'-Untertitel, Ökosystem-Badge (Matter/HomeKit), '🔒'-Indikator bei codeStored und Link-Anzahl-Chip. SECRET-SAFE: zeigt NIE den Setup-Code/QR. Die Kachel öffnet das Detail (press → open).
groupBy?·items
LensVaultlivelexTyp-Linse Zugangsdaten (TypeView): Kachel-Raster aller Credentials (Passwort-Manager-Blick). items = [{uuid?, title, service?, username?, category?, contentType?}]; je Kachel Service-Monogramm, Name, Benutzername/Service-Untertitel und Schloss-Indikator. SECRET-SAFE: zeigt NIE Passwörter, Keys, Tokens oder Secrets — nur Titel/Service/Benutzername. Die Kachel öffnet das Detail (press → open).
items
LensLedgerlivelexTyp-Linse Finanzen (TypeView): Kontoauszug-Feed für Ausgaben/Belege/Rechnungen/Abos — nach Monat gruppiert, je Gruppe Kopfzeile (Monat + Summe, wenn alle Beträge numerisch in EINER Währung vorliegen). items = [{uuid?, title, amount?, currency?, date?, category?, merchant?, contentType?}]; je Zeile Händler/Titel, Kategorie-Sub und Betrag rechtsbündig in Tabellenziffern. Die Zeile öffnet das Detail (press → open).
items
LensPipelinelivelexTyp-Linse Pipeline (TypeView): nach kanonischem Status gruppierte Ticket-/Bug-Liste (Offen → In Arbeit → Behoben → Geschlossen), je Gruppe getönte Kopfzeile mit Anzahl. items = [{uuid?, title, status?, severity?, area?, contentType?}]; je Zeile Status-Punkt, Titel, Severity-Chip (hi/mid/lo-Töne) und Bereich. Die Zeile öffnet das Detail (press → open).
items
LensCalendarlivelexTyp-Linse Kalender (TypeView): Monatsraster-Übersicht datierter Inhalte (Termine/Reisen) — je Monat mit Einträgen ein Mo-basiertes Grid, Tage mit Einträgen als Akzent-Punkte, heute mit Ring; darunter die Einträge des Monats als öffnbare Zeilen (Datum + Uhrzeit + Titel). items = [{uuid?, title, date, time?, contentType?}]. Die Zeile öffnet das Detail (press → open).
items
RunCardliveStream-Verdichter-Gruppenkarte (Run-Coalescing): EIN Lauf gleichartiger, aufeinanderfolgender Stream-Karten als Karte mit Kopf (Icon, Titel „5 Fotos“, Zeitfenster, Zähler) und Inline-Sub-Lens — lensType/lensProps sind ein normaler Lens-Descriptor (LensMasonry/LensTaskList/LensReader/LensPipeline), der wiederverwendet inline rendert. Der Aufklapp-Knopf feuert brainz:run-toggle {runKey} (Host entfaltet zu den Einzelkarten). Reine Anzeige-Projektion, stream-only.
runKey·title·subtitle?·count·icon?·tone?·lensType·lensProps·actionKey?·actionLabel?·actionAi?·memberUuids?·collect?·heat?·autoHeat?·userBoost?·calmed?·boostPin?·clusterId?·deck?·dominantType?·timeLabel?·members?·typeMix?
WeatherSkylivelexAnimierte Aktuell-Wetter-Hero: Bedingungs-Gradient + Canvas-Partikel (Sonne/Sterne/Wolken/Regen/Schnee/Gewitter) hinter Temperatur, Icon und Beschreibung. tempC/feelsC IMMER in °C, unit schaltet die Anzeige (C|F). code = WMO-Code, isDay = Tag/Nacht-Palette.
tempC·feelsC?·code·isDay?·label?·place?·unit?
ForecastStriplivelexHorizontale, scrollbare STUNDEN-Wettervorschau: je Stunde Label, WMO-Icon und Temperatur — Mehrtages-Vorschau → DayRange, alles in einem Descriptor → WeatherCard. tempC IMMER °C, unit schaltet die Anzeige (C|F).
title?·unit?·hours
DayRangelivelexMehrtages-Wettervorschau: je Tag Label, WMO-Icon, Min/Max und ein absolut skalierter Temperatur-Verlaufsbalken (kalt=blau, heiß=orange über alle Tage) — Stunden-Vorschau für heute → ForecastStrip. minC/maxC IMMER °C, unit schaltet die Anzeige (C|F).
title?·unit?·days
WeatherCardlivelexKomplette Wetterkarte in EINEM Descriptor: WeatherSky-Hero + Wind/Luftfeuchte-Metriken + optional ForecastStrip (hours) + DayRange (days). Alle Temperaturen IMMER °C, unit schaltet die Anzeige (C|F). Für Plugins, die eine fertige Wetterkarte ausgeben wollen.
place?·unit?·current·hours?·days?
WeatherChiplivelexKompakte Wetter-Glance (Strip/Badge): WMO-Icon + Temperatur + Beschreibung + optional Ort, bedingungs-getönt. Statisch (keine Animation — für ruhige Flächen wie den Home-Strip). tempC IMMER °C, unit schaltet die Anzeige (C|F).
tempC·code·isDay?·place?·unit?
TransitChiplivelexKompakte ÖPNV-Glance (Strip/Badge): Verkehrsmittel-Icon + Linien-Badge + nächste Abfahrt als Countdown (dringlichkeits-getönt: jetzt/bald/später) + optionale Verspätung. Statisch — für ruhige Glance-Flächen wie den Home-Strip (Pendant zu WeatherChip).
line·lineColor?·mode?·minutes·delay?
DepartureRowlivelexEine ÖPNV-Abfahrtszeile: Verkehrsmittel-Icon + Linien-Badge + Fahrtrichtung (optional Gleis) + Countdown (jetzt/bald/später) + optionale Verspätung; cancelled = durchgestrichen. Reines Display — die Fahrtrichtungs-Hervorhebung (fett/dünn) setzt der Host imperativ via .ahead/.behind.
line·direction·lineColor?·mode?·platform?·minutes·delay?·cancelled?
TransitStopHeaderlivelexKopfzeile einer Haltestelle im Abfahrtsbrett: Name + optionale Entfernung + optionale Gehzeit (mit Geh-Icon). Reines Display; ein interaktiver Kompass-Button wird vom Host angehängt.
name·distance?·walk?
TransitBoardHeaderlivelexKopf des ÖPNV-Abfahrtsbretts: Verkehrsmittel-Pin + Label (Default Unterwegs) + optionaler Untertitel (z. B. Entfernung von Zuhause). Bei gebundenem on.refresh erscheint eine dezente Aktualisieren-Affordance rechts; der Mobile-Host hängt seinen Live-Button weiterhin imperativ an.
label?·subtitle?
DocCardlivelexKanonische Prosa-/Dokument-Karte für Lese-Inhalte: variant wählt die Form (article = Hero-Bild, briefing = KI-Framing mit rows/chips, recipe = Rezept-Hero, sonst Titel+Excerpt). body/summary = Text, image+mediaType = Medien, source/duration/readMinutes = Kontext-Pills.
title·time?·heat?·tags?·pinned?·entityUuid?·variant?·body?·summary?·excerpt?·source?·image?·mediaType?·duration?·readMinutes?·kind?·sub?·gemIcon?·text?·rows?·chips?
ArticleCardlivelexBildgetriebene Artikel-/News-Reader-Karte: Full-Bleed-Hero wenn image vorliegt, sonst Text-Excerpt (summary|excerpt|body); source = Quelle, duration/readMinutes = Pills, mediaType video = Play-Overlay. (Alias von DocCard)
title·time?·heat?·tags?·pinned?·entityUuid?·summary?·excerpt?·body?·source?·image?·mediaType?·duration?·readMinutes?
StoryCardlivelexReader-Karte für eine Story: title + body-Excerpt (240 Z.), image = Thumbnail neben dem Text, source = Quelle. (Alias von DocCard)
title·time?·heat?·tags?·pinned?·entityUuid?·body?·image?·source?
DocumentCardlivelexReader-Karte für ein Dokument (Scan/Beleg/PDF-Text): title + body-Excerpt, image = Scan-Thumbnail neben dem Text, source = Quelle. (Alias von DocCard)
title·time?·heat?·tags?·pinned?·entityUuid?·body?·image?·source?
BlogpostCardlivelexReader-Karte für einen Blogpost: title + body-Excerpt, image = Thumbnail neben dem Text, source = Quelle. (Alias von DocCard)
title·time?·heat?·tags?·pinned?·entityUuid?·body?·image?·source?
ChangelogCardlivelexReader-Karte für einen Changelog-/Release-Eintrag: title + body-Excerpt, image = Thumbnail, source = Quelle/Projekt. (Alias von DocCard)
title·time?·heat?·tags?·pinned?·entityUuid?·body?·image?·source?
EmailCardlivelexReader-Karte für eine E-Mail: title = Betreff, body-Excerpt = Nachrichtenanfang, source = Absender, image = Anhang-Thumbnail. (Alias von DocCard)
title·time?·heat?·tags?·pinned?·entityUuid?·body?·image?·source?
RecipeCardlivelexRezept-Karte mit Hero-Bild (16:10) unter dem Titel + kurzem body-Excerpt (160 Z.) — volle Zutaten/Schritte leben im Detail bzw. in GenericCard-Molekülen. (Alias von DocCard)
title·time?·heat?·tags?·pinned?·entityUuid?·body?·image?·source?
BriefingCardlivelexFunke-Briefing-Karte (KI-violett): kind-Eyebrow + Gem + Headline (text|title); mit rows (Digest-Zeilen) + chips wird sie zum aufklappbaren Tagesanker mit summary-Erzählung — redaktionelle Home-Stimme ohne Struktur → Briefing. (Alias von DocCard)
title?·text?·body?·summary?·kind?·sub?·gemIcon?·reasons?·feedback?·feedbackValue?·rows?·chips?·time?·heat?·pinned?
PulseCardlivelexPuls-Entscheidungskarte (KI-violett): Gem + kind-Eyebrow + when-Kontextzeile, title = Headline, narrative = Erzähl-Body; Entscheidungsleiste dispatcht accept (acceptLabel, Default Annehmen) · snooze · reject. Für Inbox-Entscheidungen, kein Swipe.
title·narrative?·kind?·when?·gemIcon?·acceptLabel?·heat?
PulseReflivelexKompakte antippbare Öffnen-Zeile zu einer Entität (z.B. „dir übergeben" / „bald fällig"): Icon-Chip in der Content-Type-Farbe (contentType), title + sub; press öffnet die Entität — volle Entscheidung → PulseCard. Puls v2 (Einheits-Zeile): optional whyNow-Subline (whyAi → KI-violett), source-Chip (bell/spark/pin/share/clock/event/task) und das Verben-Trio ✓/→ später/✕ — Verben dispatchen brainz:pulse-verb auf document (Host persistiert).
title·sub?·icon?·contentType?·whyNow?·whyAi?·source?·overdue?·doneable?·laterLabel?·laterIso?·dismissable?·entityUuid?·insightId?·pulseId?·actionId?·prevDueIso?·localId?
InboxListlivelexEingang / Handlungsbedarf (app-controls inboxList): Gruppen mit Einträgen – je Eintrag Art (warning, weather, change, message, document, task, info) als Symbol, Dringlichkeit (high/medium/low) als schmaler Balken, Titel, Kontext (Reise · Ort), Zeitpunkt (ISO), ungelesen, Absender {kind: agent|rule|pipeline|source|person|system, id, label, avatar?: Schlüssel wie Initialen oder agent:<typ>, nie eine URL} und eine Hauptaktion (primary.label). Gelesen/Erledigt/Später und „Alle gelesen/erledigt“ meldet der Block als Pack-Actions inboxAction {kind, itemId, until?, date?} bzw. inboxBulk {kind, groupId, ids} – der Host ruft die Posteingangs-API. Für Cockpit, Crew- und Reise-App.
label?·groups·empty?
FeatureGridlexpdfRaster aus Funktions-Kacheln mit ehrlichem Reifegrad: items = [{title, text?, icon?, status?, statusNote?}]; status available|pilot|preparing|on_request|principle erscheint als Etikett Verfügbar/Pilot/In Vorbereitung/Auf Anfrage/Grundsatz, statusNote präzisiert (z. B. „Deutschland zuerst“). WANN: „Was Sie bekommen“, Neuheiten der Plattform, Vertrauens-/Datenschutz-Punkte (dann ohne status) und mit variant "gaps" die Liste „Noch nicht dabei“. columns = Spalten-Hinweis für breite Flächen (2–4); schmal immer eine Spalte. NICHT für abhakbare Aufgaben (TaskList), Kennzahlen (KpiRow) oder Abläufe (StepList).
title?·variant?·columns?·items
StatusLegendlexpdfLegende der Reifegrad-Etiketten (Verfügbar · Pilot · In Vorbereitung · Auf Anfrage · Grundsatz) mit kurzer Erklärung je Etikett. statuses = welche Etiketten in welcher Reihenfolge (Standard: die vier Stufen ohne Grundsatz), notes überschreibt einzelne Erklärungen. WANN: direkt über einer FeatureGrid mit status-Etiketten, damit Leser die Stufen verstehen. NICHT als allgemeine Farblegende für Diagramme (dafür die Legende des Chart).
statuses?·notes?
TrustBadgelexpdfKleine Vertrauens-Pille für eine nachprüfbare Tatsache zum Datenstandort oder Betrieb: label (z. B. „Daten in der EU“), detail? (z. B. „Rechenzentrum Frankfurt“), tone eu|neutral. Bewusst OHNE EU-Emblem/Sternenkranz und ohne Hinweis auf eine Unterstützung durch die EU — nur die Tatsache. WANN: neben Überschriften, in Karten-Köpfen, unter einem Angebot. Für eine Status-Pille ohne Detail → Badge; für mehrere Vertrauens-Punkte mit Text → FeatureGrid ohne status.
label·detail?·tone?
CtaBandlexpdfAbschluss-Band mit Handlungsaufforderung: title, text?, actionLabel (Knopf), contact? (Klartext, z. B. E-Mail-Adresse — wird nicht verlinkt), note? (z. B. „Kein Formular: zwei, drei Sätze genügen“). Der Knopf erscheint NUR, wenn on.press an eine erlaubte Action gebunden ist (openUrl mit https, navigate, sendMessage) — keine Formulare. WANN: einmal am Ende einer Angebots-/Produktseite oder eines Pilot-Vorschlags. Für einen Hinweis ohne Handlung → Callout; für einen einzelnen App-Knopf → Button.
title·text?·actionLabel·contact?·note?
TimelineSketchlexpdfSkizzen-Zeitleiste (Gantt im Kleinen): units = Anzahl Spalten (z. B. 7 Reisetage), unitLabel (Standard „Tag“), rows = [{label, spans:[{from, to, state: done|running|planned}], marker?, markerLabel?}] — from/to sind Spaltengrenzen (0–7 = Tag 1–7), marker setzt einen Punkt (z. B. wo der Bus nach Plan steht), now die Heute-Linie. sample=true zeigt das Etikett „Beispielansicht“. WANN: erklärende Beispiele (Busreisen, Einsatzplan) und kleine Übersichten bis 8 Zeilen. NICHT für echte Cockpit-Daten mit Abfahrten (dafür DepartureRadar im Cockpit-Pack) und nicht für Meilensteine (Timeline).
title?·units·unitLabel?·now?·rows·caption?·sample?
Charts pack-charts · 17 Typen
MermaidDiagramStrukturiertes Diagramm mit automatischem Mermaid-Layout. title, description (vollständige Textalternative), source (max6000Zeichen/100Zeilen). Nur folgende Syntax, explizite Definitionen vor Kanten: Flowchart: flowchart TD oder LR; A[Label] oder B{Frage?}; A --> B oder B -->|Ja| C. Sequenz: sequenceDiagram; participant A as Name; A->>B: Text oder B-->>A: Text. Zustand: stateDiagram-v2; state "Label" as A; [*] --> A; A --> B: Text; B --> [*]. Max40Objekte/60Verbindungen,Labels max80, kurze reine Texte ohne HTML/Entities. Keine Styles/Klassen/Links/Bilder/Icons/Kommentare/Frontmatter/Init/Callbacks/Subgraphs. Für mobile wenige Schritte und flowchart TD, kurze Labels. Theme und Einpassen/Lesen kontrolliert UI. Keine Datenabfragen/Filter/Aktionen; Analytics für echte Daten bevorzugen.
title·description·source
VectorSceneFreie illustrative Vektorgrafik, wenn kein Standarddiagramm passt. Kein SVG-/HTML-Code: title, description (vollständige Textalternative), width/height 64–2048 und marks (max256): rect, circle, line, path, text. Koordinaten ±4096. path.commands max128 aus {op:M|L,x,y}, {op:C,x1,y1,x2,y2,x,y}, {op:Q,x1,y1,x,y}, {op:Z}; beginnt mit M; insgesamt max4096 Befehle. Formen: x,y; rect width,height,radius?; circle radius; line x2,y2; text text,size?,anchor:start|middle|end. fill/stroke: foreground|muted|accent|onAccent|surface|border|series1..series5|none; strokeWidth 0–12. tooltip optional (reiner Text), animation:none|fade|draw (draw nur line/path; einmalig, reduziert bei reduzierter Bewegung). Keine Links, Skripte, CSS, fremden Ressourcen, Datenabfragen oder automatischen Filterbindungen. Standarddiagramme für Daten bevorzugen; keine Daten erfinden. Beschriftungen mit ausreichendem Kontrast und Platz zeichnen. Mobile zuerst: wenige Elemente (z.B. 3–5), kurze Labels, keine kleinteiligen Nebenbeschriftungen. Als Ausgangspunkt width 400 und wesentliche Textgrößen mindestens 22; die gesamte Szene wird proportional skaliert, nicht umgebrochen. Details in description/tooltip erläutern.
title·description·width·height·marks
AnalysisDashboardliveGemeinsamer Rahmen für AnalysisView/TimeGrid-Kinder. group entspricht filters.group der verbundenen Kinder. Gemeinsame Filter nur bei identischer Quellenbindung und identischem Abfragevertrag; andere Filter bleiben lokal. Quellen als $ref erhalten, keine Daten/Kennzahlen zusammenrechnen. AnalysisFilters optional als Kind für die zentrale Filterleiste; sonst automatisch im Kopf. filters.compose:'separate' verhindert automatische Nachbarschafts-Komposition für absichtliche Vergleiche.
title?·group
AnalysisFiltersliveZentrale Filterleiste innerhalb eines AnalysisDashboard. Leere Props; übernimmt nur bestätigte gemeinsame Fähigkeiten der Kinder. Außerhalb eines Dashboard bleiben lokale Filter aktiv.
— keine Props
DataGridInteraktives Datengrid: data ist unveränderte analytics-Antwort als $ref, keine Werte abschreiben. columns optional ausgewählte Feld-IDs (höchstens 12), groupBy optional eine Dimension, pageSize 10–100. merge=[Feld-IDs, 1–4] fasst gleiche Werte in aufeinanderfolgenden Zeilen zu einer Zelle zusammen (z.B. eine Abreise mit mehreren Reiseleitungen), hierarchisch in Listenreihenfolge (Reise nur innerhalb derselben Abreise); leere Werte nie, Export bleibt vollständig. Suche, numerische Sortierung, Spaltenauswahl, gruppierte Zeilen pro Seite und Seitenwechsel. Datumsspalten (type time, ISO) erscheinen als dd.MM.yyyy (Zeitpunkte mit Z/Offset in Europe/Zurich umgerechnet, ohne Offset als Wandzeit), leere Zellen (null) als „—“; der Export behält ISO. summaries=[{field,operation:sum|avg|min|max|count}] über geladene/gefilterte Zeilen; unterdrückte Werte verhindern exakte Summen. Excel exportiert sichtbare Spalten, alle lokal gefilterten/sortierten geladenen Zeilen. Keine serverseitige Pagination. Für gemeinsame Filter in AnalysisView views:[{type:'datagrid',grid:{...}}].
title?·data·query?·columns?·groupBy?·pageSize?·summaries?·merge?
ComboChartBalken und Linien zusammen: data unveränderte analytics-Antwort als $ref; dimension Feld-ID für X-Achse, series=[{field,kind:'bar'|'line'}] höchstens 6 numerische Reihen mit derselben Einheit, erste 200 Zeilen in Quellreihenfolge. Lücken bleiben Lücken. Unterschiedliche Einheiten in separaten Charts zeigen. Geeignet z.B. Ist/Plan und Verlauf, auch negative Werte. Für gemeinsame Filter AnalysisView views:[{type:'combo',combo:{dimension,series}}].
title?·data·query?·dimension·series
ScatterPlotStreu-/Blasendiagramm: data unveränderte analytics-Antwort als $ref; x und y numerische Feld-IDs, size optional nichtnegative Größe (Blasenfläche proportional), category optional Farbgruppen, label optional Punktbeschriftung. Numerische X/Y-Achsen, erste 200 Quellzeilen, unvollständige Punkte nicht dargestellt. Für Beziehungen und Verteilungen. Für gemeinsame Filter AnalysisView views:[{type:'scatter',scatter:{x,y,size?,category?,label?}}].
title?·data·query?·x·y·size?·category?·label?
WaterfallChartWasserfall für geordnete additive Änderungen beliebiger Kennzahlen: data unveränderte analytics-Antwort als $ref; dimension Schrittnamen, value numerische Änderung, total optional Gesamtbalken (Standard true). Start bei 0, positive/negative Schritte, höchstens 200 Quellzeilen; Reihenfolge durch Quellabfrage sortieren. Keine Prozentsätze/Ratios addieren. Fehlende/unterdrückte oder begrenzte Daten verhindern kumulative Darstellung. Für gemeinsame Filter AnalysisView views:[{type:'waterfall',waterfall:{dimension,value,total?}}].
title?·data·query?·dimension·value·total?
RatingBarsHorizontale Bewertungs-Balken, z.B. Durchschnitts-Ratings je Frage (Skala 0–max). data als $ref auf Objekt-Rows (z.B. r1.data aus feedback_avg_ratings), labelKey z.B. 'question_name', valueKey z.B. 'avg', countKey optional 'count' (Antwortzahl). Statt data geht auch query (eine analytics.query-Anfrage) mit result als $ref auf deren Antwort – dann zeichnet die Auswertung (Filter, Export, Herkunft).
data?·query?·result?·labelKey·valueKey·countKey?·max?·title?
MatrixHeatmapMatrix-Heatmap für zwei Kategorien (z.B. Thema × Monat). data als $ref auf Objekt-Rows; xKey/yKey kategorische Felder, valueKey numerisch (Farbintensität). Statt data geht auch query (eine analytics.query-Anfrage) mit result als $ref auf deren Antwort – dann zeichnet die Auswertung (Filter, Export, Herkunft).
data?·query?·result?·xKey·yKey·valueKey·title?
ChartpdfDiagramm aus Objekt-Rows (data als $ref, z.B. {"$ref": "r1.nps_trend"}). xKey = Feldname für Label/X-Achse (z.B. 'month'), yKey = Feldname für den Zahlenwert (z.B. 'score'). kind: line (Zeitreihen/Verläufe), area (Verlauf mit Fläche, Mengen), bar (Vergleiche), donut (Anteile, max 8, Rest als 'Weitere'), sparkline (Mini-Verlauf ohne Achsen). Mehrere Reihen: series=[{key, label}] (ersetzt yKey, max 6) – bar gruppiert, mit stacked:true gestapelt (auch area). orientation:'horizontal' für Balken mit langen Beschriftungen (Rangliste). target={value, label?} zieht eine Ziel- oder Referenzlinie. Passt sich selbst an Platz an (Sparkline bis Detail mit Werten und Tabelle). Statt data geht auch query (eine analytics.query-Anfrage) mit result als $ref auf deren Antwort – dann zeichnet die Auswertung (Filter, Export, Herkunft).
kind·title?·data?·query?·result?·xKey·yKey·unit?·maxPoints?·series?·stacked?·orientation?·target?
AnalysisViewInteraktive Auswertung aus analytics.query bzw. query_aggregates (TourData-Mirror) (KONZEPT-ANALYSEN): query = die Anfrage (dataset, measures, dimensions, timeRange={from,to}), data = ihre Antwort unverändert als $ref (z.B. {"$ref": "r1"}). Zeilenliste (Reporting-Quelle): query={mode:'list',dataset:'reporting:<source>',spec:<Reporting-Spec unverändert, snake_case, time_range Pflicht ≤366 Tage>}, data = deren Antwort als $ref; Filter ändern nur spec.filters und spec.time_range, Kacheln/subtitle rechnen über die geladenen Zeilen; fehlende Spalten fallen weg, ein Filter darauf wird als „nicht verfügbar“ angezeigt. subtitle = eine Zeile unter dem Titel mit Live-Zahlen, die mit jedem Filter neu gerechnet werden: {sum:pax}, {count}, {count:guide}, {distinct:departure}, {missing:guide/departure}, {from}, {to}, {asOf} (höchstens 8, Text bis 200 Zeichen), z.B. "{from}–{to} · {distinct:departure} Abreisen · {sum:pax} Gäste". Kennzahlen immer als {sum:<measure-id>} schreiben, nicht {departures}; {value:<dimension>} zeigt den Wert einer Dimension, wenn die gezeigten Zeilen genau einen haben, sonst fällt der Platzhalter weg. Diagramme (bar/line/area/pie/rating) brauchen dimension und measure; fehlt eins, nimmt die Ansicht das erste der query. views: kpi (Kennzahl-Kachel: aggregation sum (Standard, je measure; Prozent als Mittelwert) | count (Zeilen bzw. mit dimension: Zeilen mit Wert) | distinct (verschiedene Werte von dimension, z.B. Abreisen) | missing (Zeilen ohne Wert in dimension; mit of: verschiedene of-Werte, bei denen keine Zeile einen Wert hat – {aggregation:"missing",dimension:"guide",of:"departure"} = Abreisen ohne Reiseleitung); tone neutral|accent|success|warning|danger; fünf Kacheln je Zeile), bar/line/area (dimension × measure, Klick auf einen Balken filtert alles), pie (sparsam, Anteile), table (sortierbar), timegrid (generisches Zeitraster; Konfiguration siehe TimeGrid, einschließlich frei wählbarer Kennzahlen und Tooltips). filters.group = explizite gemeinsame Filtergruppe für mehrere Blöcke desselben Datensatzes im selben Dashboard; Host-Scope trennt Dashboards. filters.display:summary zeigt nur aktive Filter auf abhängigen Blöcken, controls (Standard) zeigt die Bedienelemente. Aktive Filter sind einzeln entfernbar. Unbekannte/leere Zellen bei fehlender Zeitabdeckung, truncated oder suppression sind kein Nullwert. filters.dimensions = bis 8 Filterdimensionen, filters.controls=[{dimension,label,type:chips|select|daterange,multiple}] wählt Bedienelemente; type:select mit multiple:true ist einzeilig mit integrierter Suche und Checkboxen; Übernehmen wendet die Auswahl gesammelt an. type:daterange (höchstens eins, dimension = die Datumsspalte) zeigt Von/Bis-Datumsfelder: ein gültiger Zeitraum (höchstens 366 Tage) setzt query.timeRange und lädt neu; query.timeRange gibt den Startzeitraum vor (nicht zusammen mit timegrid). Viele Optionen automatisch als Auswahl, search = Suche (true: über alle Textspalten; oder eine Liste von Spalten-IDs, z.B. ["trip","code","person"], dann nur dort; Bezeichnungen werden mitdurchsucht). Weitere views: datagrid (grid={columns?,groupBy?,pageSize?,summaries?,merge?}; merge=["departure","trip"] fasst gleiche Werte untereinander zu einer Zelle zusammen, hierarchisch), combo (combo={dimension,series:[{field,kind:bar|line}]}), scatter (scatter={x,y,size?,category?,label?}), waterfall (waterfall={dimension,value,total?}); gemeinsame Filter wirken auf alle views desselben Datensatzes. Bis 12 views, darunter frei wählbare kpi-Kacheln. Mit snapshot (Stand zum Stichtag) wird nichts nachgeladen. Nur Aggregate; '<3' ist eine unterdrückte Kleingruppe.
title?·subtitle?·views·timegrid?·filters?·values?·snapshot?·query·data?
TimeGridGenerisches Zeitraster für beliebige Objekte und numerische Werte mit ISO-Datumsbezug (day = Spalte YYYY-MM-DD bzw. ISO-Zeitstempel). Das LLM wählt timegrid={row,rowLabel?,day,value,category?,ref?,period:'week'|'month'|'quarter'|'year',granularity?:'day'|'week'|'month',valueLabels?:boolean (Standard true, Zahlen ohne Einheit; Tooltip vollständig),cellStyle?:'auto'|'solid'|'fractional' (auto: Belegung und deklarierte Tage-Einheiten geteilt; fractional generisch),mode:'value'|'occupancy',aggregation?:'sum'|'avg'|'min'|'max'|'count'}. Für beliebige Messwerte mode:value (auch 0 und negative Werte); für Ganz-/Halbtagbelegung explizit occupancy. Standardgranularität: Jahr=Monat, sonst Tag. Titel ohne fest eingebettete Datumsangaben wählen, wenn Navigation angeboten wird; der Zeitraum wird separat angezeigt. Datumsspanne der query muss die gesamte sichtbare Woche (Mo–So), den Monat, das Kalenderquartal bzw. Jahr umfassen; Quellen-Zeitraumgrenzen beachten, keine Vollständigkeit bei truncated behaupten. Tooltip direkt je Zelle: tooltip:[{field,label?}] bis 8 vorhandene Ergebnisspalten, mehrere Einträge werden zusammengeführt; keine erfundenen Felder oder zusätzlichen Berechtigungen. Zusammenfassungen: summaries:[{kind:'total'|'objects'|'full'|'half'|'cells'|'measure',label,field?,aggregation?}] bis 12 Kacheln; [] blendet sie aus; measure benötigt field, full/half nur für occupancy sinnvoll. options:{periods?:['week','month','quarter','year'],navigation?,copy?,exports?,legend?,showEmpty?,totals?} steuert Bedienelemente. Filter wie AnalysisView, ebenso query und data als unveränderter $ref. Standardmodus bleibt occupancy für alte Ansichten. query_aggregates unterstützt derzeit maximal 3 Gruppierungsdimensionen, max 5000 Zeilen; Tooltipfelder müssen geliefert werden (z.B. Reise ist keine automatisch verfügbare vierte Dimension). vehicle_days Beispiel: dimensions [day,vehicle,category], measure operating_days, timegrid={row:'vehicle',day:'day',category:'category',value:'operating_days',mode:'occupancy',period:'month'}, limit 5000.
title?·subtitle?·views·timegrid?·filters?·values?·snapshot?·query·data?
CalendarHeatmapKalender-Heatmap: Datum → Wert als Monatsraster (Mo–So, höchstens 12 Monate). data = die analytics.query- bzw. query_aggregates-Antwort unverändert als $ref (z.B. {"$ref": "r1"}); date = Tages-Dimension (YYYY-MM-DD), value = Kennzahl. Tage ohne Angabe bleiben sichtbar leer (Lücke, nicht 0); '<n' (Kleingruppe) erscheint schraffiert. Für Tagesverläufe wie Buchungen je Tag, Einsatztage, Rückmeldungen. Titel ohne Personennamen.
title?·data·query?·date·value
PivotTableKreuztabelle aus einer analytics-Antwort: rows = Dimension nach unten, columns = Dimension nach rechts (≤ 24 Spalten), value = Kennzahl; mit Zeilen-, Spalten- und Gesamtsummen. data = die Antwort als $ref. Maskierte Kleingruppen ('<n') werden NIE mitsummiert – eine Summe ohne sie steht als '≥ …' mit Hinweis. Prozentwerte werden nicht aufsummiert. Für 'X nach A und B'-Fragen (z.B. Buchungen je Reiseziel und Monat). Titel ohne Personennamen.
title?·data·query?·rows·columns·value
RankListRangliste Top-N aus einer analytics-Antwort: dimension = was gereiht wird, value = Kennzahl, limit = Anzahl (Standard 10, max 50), compare optional = zweite Kennzahl als Vergleich (z.B. Vorjahr) → Trendpfeil mit Differenz. Balken relativ zum Ersten. data = die Antwort als $ref. Kleingruppen ('<n') kommen ohne Balken ans Ende, nie geschätzt. Für 'Top 10 …', 'Wer/was am meisten …'. Bei der Dimension person (P1) keine Namen in Titel oder Text nennen.
title?·data·query?·dimension·value·compare?·limit?
SparkTableTabelle mit einer Sparkline je Zeile aus einer analytics-Antwort: rows = Dimension je Zeile (z.B. Reiseziel), x = Zeit-Dimension (Tag/Monat), value = Kennzahl; je Zeile Verlauf, letzter Wert, Veränderung und Summe (ohne Kleingruppen, dann '≥'). limit = Zeilen (Standard 20, max 50). data = die Antwort als $ref. Lücken (fehlend, '<n') unterbrechen die Linie. Für 'Entwicklung je …' auf einen Blick. Titel ohne Personennamen.
title?·data·query?·rows·x·value·limit?
Forms pack-forms · 12 Typen
FormFormular-Container für interaktive Eingabe-Flows: NUR nutzen, wenn der Nutzer Werte eingeben/bestätigen soll (nicht für reine Anzeige). formId identifiziert die Submission; Kinder sind Input/Select/DatePicker/Checkbox/Submit (auch gemischt mit Markdown/Grid); genau EIN Submit pro Form. Optionales contentType = deklarativer Submit-Vertrag: der Host legt die Werte als neuen Eintrag dieses Typs an (createEntry über den Drop-Pfad) — ohne contentType muss der Host submitForm selbst behandeln.
formId·title?·contentType?
InputTextfeld. inputType number/email für entsprechende Eingaben.
name·label?·inputType?·placeholder?·maxLength?·minLength?·pattern?·min?·max?·value?·required?·multiline?·errorText?·disabled?
SelectAuswahl für GENAU-1-aus-N vordefinierten Optionen — Ja/Nein → Checkbox, Freitext → Input, Datum → DatePicker. options als Strings oder {value, label, icon?}-Paare. variant 'native' (Default) = Dropdown, 'segmented' = Pill-Reihe (Compose-Segmented-Look als Vertrags-Baustein, Wert läuft über ein Hidden-Input — Submit-kompatibel).
name·label?·options·variant?·required?·placeholder?·value?·errorText?·disabled?
DatePickerDatumsfeld mit nativem Picker (ISO-Datum als Wert) — bei Datums-Eingaben IMMER dieses Feld statt Input verwenden; min/max grenzen den wählbaren Bereich ein (ISO).
name·label?·min?·max?·value?·required?·errorText?·disabled?
CheckboxEinzelne Checkbox für EINE Ja/Nein-Entscheidung (Wert true/false) — Auswahl aus mehreren Optionen → Select. checked = Vorbelegung. variant 'switch' = Pill-Schalter (gleiche Semantik, anderer Look).
name·label·checked?·variant?·required?·errorText?·disabled?
CheckboxGroupChip-Reihe für N-aus-N-Auswahl (Mehrfachauswahl) — GENAU-1-aus-N → Select, Ja/Nein → Checkbox. options als Strings oder {value, label, icon?}-Paare; value = Array der gewählten Werte. Bei submitForm landet der Wert als Array (data-as-multi), bei bind als Array im Store.
name·label?·options·value?·disabled?
RepeatableGroupWiederholbare Feldgruppe (Array-of-Objects): N Zeilen derselben Felder — Reise-Etappen, Packlisten-Einträge, Positionen. fields = deklarierte Spalten ({key, label, kind text|number|date|select, options?, placeholder?}); value = Array von Objekten. addLabel/removeLabel steuern die Zeilen-Buttons. Submit sammelt als Array (data-as-repeat), bei bind als Array im Store.
name·label?·fields·value?·minItems?·maxItems?·addLabel?·removeLabel?·disabled?
ComboboxSuche-mit-Vorschlägen + freie Eingabe (native <datalist>): tippen filtert die Optionen, kein passender Vorschlag ist trotzdem ein gültiger Wert (freeText, Default). Vordefinierte Pflicht-Auswahl → Select. options als Strings oder {value, label}-Paare (angezeigt/gespeichert wird der label-Text).
name·label?·options·placeholder?·freeText?·value?·required?·errorText?·disabled?
DateRangeZeitraum (von–bis) als EIN Feld: zwei native Date-Picker mit Kreuz-Validierung (von ≤ bis — Verletzung markiert inline). Für Reisezeiträume, Filterspannen, Gültigkeiten. EIN Datum → DatePicker. value = {from, to} (ISO), bei bind injiziert der Host; Submit sammelt {from, to} als Objekt (data-as-range).
name·label?·min?·max?·value?·required?·errorText?·disabled?
TimePickerUhrzeit-Feld mit nativem Picker (HH:MM als Wert) — bei Uhrzeit-Eingaben dieses Feld, bei Datum DatePicker, bei beidem zwei Felder nebeneinander. min/max grenzen den wählbaren Bereich ein (HH:MM).
name·label?·min?·max?·value?·required?·errorText?·disabled?
StepperZahlen-Schrittsteller (Minus/Wert/Plus) für gestufte Mengen — Bereich min/max, Schrittweite step (Default 1), optionale Einheit (Personen, Tage, m). Freie Zahleneingabe → Input mit inputType number; Ja/Nein → Checkbox. Der Wert läuft über ein Hidden-Input (Submit-kompatibel), bei bind als number im Store.
name·label?·min?·max?·step?·unit?·value?·disabled?
SubmitAbsende-Button — sammelt alle Feldwerte des umgebenden Form und löst submitForm aus; genau EINER pro Form, keine on-Bindings nötig. Nicht für allgemeine Aktions-Buttons außerhalb eines Form verwenden.
label
Tourdata pack-tourdata · 5 Typen
EntityGraphFokus-Stern der Verknüpfungen EINER Buchung (Shape = get_booking_graph, per $ref durchreichen: center←center, nodes←nodes, edges←edges). Zentrum + EIN Ring: Reise, Kunde (booking_count), Teilnehmer, Feedback (survey_count), Abreisen (booking_count je Abreise; vergangene links gedeckt, künftige rechts im Akzent, is_current markiert). trail (optional, vom Host geführt) rendert die Herkunfts-Kette als Mini-Stubs links. BINDUNG: on.press nimmt EINE Action für den ganzen Graph — der Renderer ergänzt die getroffene Knoten-Identität als args.node {type,id,key} (Muster Chips-select). Form zwingend on: { press: { action, args } } — ohne Wrapper verwirft die Validierung die Bindung.
center·nodes·edges?·trail?
TripCardReise-Karte (eine Reise aus search_trips/get_trip). Felder mappen 1:1: code←trip_code, name←name, title←title, category←trip_category (NICHT der Reisename), destination, durationDays←duration_days, startingPrice←starting_price, rating←rating (Skala 0–10; Sentiment-Scores −1…1 hier NICHT verwenden, dann weglassen), isNew←is_new, imageUrl←image_url aus list_enrichments (per $ref; nur wenn vorhanden). Klickbar: on exakt als { 'press': { 'action': 'openEntity', 'args': { 'type': 'trip', 'id': code } } } (Wrapper action+args zwingend, sonst verwirft die Validierung).
code·imageUrl?·name·title?·category?·destination?·durationDays?·startingPrice?·currency?·rating?·isNew?
RecommendationCardAGGREGIERTE KI-Auswertung einer Reise über viele Surveys (aus get_trip_recommendation) — einzelne Kundenstimme → FeedbackCard, die Reise selbst → TripCard. headline, strengths/weaknesses/recommendations als String-Arrays (per $ref auf content.strengths usw.), optional tripCode, surveysConsidered, createdAt.
headline·strengths?·weaknesses?·recommendations?·tripCode?·surveysConsidered?·createdAt?
FeedbackCardEIN einzelnes Kunden-Feedback (Survey + Sentiment-Analyse) mit Zitat und Score — die aggregierte KI-Auswertung vieler Surveys → RecommendationCard. Felder: tripName/tripCode/departure aus search_surveys; author='Vorname Nachname' der Person, driver=Fahrer; sentiment/score/summary/quote/themes aus list_sentiments bzw. get_survey; themes als $ref auf das themes-Array.
tripName?·tripCode?·departure?·author?·driver?·sentiment?·score?·summary?·quote?·themes?
DossierCardReise-Dossier des Gastes (geführte Beratung): der vom Orchestrator geführte Wunsch-Stand — Ziel, Länder (ISO-2), Zeitraum (YYYY-MM-DD), Dauer, Themen, Reiseart, Personen, Budget (CHF), Muss-haben, Merkliste (shortlist: id/title/note) und die Beratungsstufe (stage: verstehen|vorschlagen|vertiefen|termin|uebergabe, 5-Punkte-Anzeige). Erscheint AUTOMATISCH nach jedem update_dossier als In-place-Patch (target 'dossier') — NICHT per render_ui nachbauen. Der Renderer feuert nach dem Rendern ein DOM-CustomEvent 'voegi:dossier' (bubbles, composed, detail = die Dossier-Props ohne title), mit dem die Host-Seite den Stand z.B. im Sidebar-Kopf spiegelt.
title?·destination?·countries?·departure_from?·departure_to?·duration_min?·duration_max?·themes?·trip_type?·party?·budget_chf?·must_haves?·shortlist?·stage?·notes?
Geo pack-geo · 1 Typen
GeoMaplexKarte um einen Punkt: lat/lon Pflicht, zoom 3–18 (Default 14), optional label (Ort-Beschriftung) und markers = [{lat, lon, label?}] (max 10). route=true verbindet die markers in Reihenfolge mit einer Linie (Reiseroute/Etappen); segments = [{from, to, mode}] (Marker-Indizes, mode road|flight|boat|rail|walk|other) zeichnet die Verbindungen nach Verkehrsmittel. Für JEDE Orts-/Wo-Frage das richtige Element — eine Orts-KARTE mit Adresse/Aktionen ist PlaceCard/LocationCard, GeoMap zeigt die Lage selbst. Wo der Host eine Kartenfläche anbietet, erscheint die echte Karte; sonst ein Lageplan mit Pins.
lat·lon·zoom?·label?·markers?·route?·segments?
Robot pack-robot · 1 Typen
RobotFacelexEin Roboter-Gesicht aus zwei animierten Augen, das eine Haltung ausdrückt statt Daten zu zeigen — für leere Zustände, Begrüßungen, Fehlerbilder und Momente, in denen der Assistent seinen eigenen Zustand sichtbar macht (z.B. emotion 'sleepy' für eine ruhende Ansicht, 'curious' während einer Recherche, 'glitch' wenn etwas fehlschlug). Nimm stattdessen Callout, wenn es um eine Aussage mit Text geht, und EmptyState, wenn der Nutzer eine Handlung ableiten soll: RobotFace trägt Stimmung, keine Information. caption setzt eine kurze Bildunterschrift darunter.
emotion?·caption?·label?·size?·animated?
Katalog C · Interaktions-Primitive imperativ · App-global
Der dritte Bereich — weder Katalog A noch B: imperative, transiente, app-globale Primitive (Toast, Sheets, Back-Stack), aufgerufen aus App-Code statt deklariert. Daher API-Referenz statt Live-Render — und (anders als B) nicht in der Figma/design-sync-Bridge. Regel wie bei den Katalogen: eine Quelle, nicht nachbauen.
showToastshowToast(message, duration = 3200, onClick?)showUndoToastshowUndoToast(message, { onUndo, onExpire?, duration = 6500, actionLabel = "Rückgängig" })openBottomSheetopenBottomSheet(host, opts?: { className?, onDismiss? }) → BottomSheetHandlepushBackLayerpushBackLayer(onClose) → BackLayer { close(), zIndex }openMenuSheetopenMenuSheet(host, def: MenuSheetDef { title?, items, accent?, onDismiss? })bzTogglebzToggle({ checked?, disabled?, tone?: "ai", ariaLabel?, onChange? }) → { el, set(checked), setDisabled(b) }