Komponenten

Formensprache

Achteck mit gekappten Ecken — nie ein Radius, nie eine Spitze.

Farben — dieselbe Form, andere Bedeutung

Die Form ist farbunabhängig. Alle Werte in oklch, unverändert aus globals.css.

Marke--goldPrimär, Ring, Akzent
Marke gedämpft--gold-dimSekundäre Stimme
Fehler--destructiveZerstörende Aktionen
Warnung--warningWartet auf Freigabe
Fläche--cardKarten, Panels
Fase--bevelKante der Schräge — deckend

Kappung — zwei Reihen

Ein Wert kann nicht funktionieren: Kontrollen bleiben subtil (auf einem 32-px-Knopf war mehr zu krass), Flächen tragen die Schräge deutlich, sonst wirkt sie zaghaft.

Kontrolle klein
Kontrolle
Marke
Karte
Panel

Formensprache

Formensprache

Die Tessera-Form: Kappung statt Rundung, Kante als evenodd-Ring, gemessene Bevel-Stufen. Grundlage aller weiteren Items.

Die Formensprache reist als Datei, byte-identisch — nicht als übersetzte Tokens. Damit gibt es eine Quelle und nichts, was auseinanderlaufen kann. Wer sie zieht, bekommt auch die Reparaturregeln, und die müssen unlayered bleiben: in Tailwind v4 schlägt der @layer-Rang die Spezifität. Ebenso zu wissen: handgeschriebene @layer utilities-Klassen bekommen keine responsiven Varianten — sm:tsr-cut wird nie erzeugt.

npx shadcn@latest add @tessera/form

Primitive

Button

Kappung an der Groessenvariante, nicht an der Aufrufstelle. Umriss-Variante traegt die Kante als Ring.

Die Kappung hängt an der Größenvariante, nicht an der Aufrufstelle. Vorher stand sie in der className jedes Aufrufs — 19 Stellen, von denen einzelne immer vergessen wurden. Die Umriss-Variante trägt ihre Kante als Ring, nicht als border: auf einer Kappung überlebt ein Rahmen nur die geraden Kanten, die Schrägen bleiben leer.

npx shadcn@latest add @tessera/button

Zieht mit: @tessera/form, utils

Card

Kappung 12px, Kante als Ring. Keine Rundung, kein ring-Utility — beide sind auf einer Kappung unsichtbar.

Eine Karte
Kappung 12px, Kante als Ring.
Der Rand läuft über die Schrägen weiter — das war der ursprüngliche Fehler.

Kein ring-1. Ein ring liegt außerhalb der Box und wird von der Kappung vollständig entfernt — nicht halb, gar nicht. Dasselbe gilt für outline und box-shadow. Übrig bleiben zwei Wege: der evenodd-Ring im Pseudoelement oder farbige Polsterung auf einer gleich geformten Hülle.

npx shadcn@latest add @tessera/card

Zieht mit: @tessera/form, utils

Dialog

Kappung 15px, mit Kopf, Fuss und Beschreibung. Traegt eine eigene Regel fuer den responsiven Fall, in dem der Dialog erst ab sm eine Kappung bekommt.

npx shadcn@latest add @tessera/dialog

Zieht mit: @tessera/form, utils

Input

Traegt die Form, aber bewusst keine Huelle: die Kante kommt von FieldShell, weil sonst die className der Aufrufstellen mehrdeutig wird.

Trägt die Form, aber bewusst keine Hülle. Die Kante käme sonst aus der className von zwanzig Aufrufstellen und wäre dort mehrdeutig —tailwind-merge lässt etwa p-3.5 gegen py-(--card-spacing) gewinnen. Für Felder mit Kante: FieldShell.

npx shadcn@latest add @tessera/input

Zieht mit: @tessera/form, utils

Tooltip

Kappung und Ring statt Schatten.

Kappung und Ring statt Schatten.

npx shadcn@latest add @tessera/tooltip

Zieht mit: @tessera/form, utils

Sheet

Seitliches Panel auf Radix-Dialog. Kappung ueber die Rollen-Selektoren der Formensprache.

Kappung 15px über die Rollen-Selektoren. Ein geöffnetes Sheet überdeckte den Katalog — am besten im app-shell auf schmalen Schirmen zu sehen.

npx shadcn@latest add @tessera/sheet

Zieht mit: @tessera/form, utils

Skeleton

Ladeplatzhalter. Traegt keine Kante — eine Flaeche, die noch niemand ist.

npx shadcn@latest add @tessera/skeleton

Zieht mit: @tessera/form, utils

Separator

Trennlinie in Haarstaerke.

Über der Linie

Unter der Linie

npx shadcn@latest add @tessera/separator

Zieht mit: @tessera/form, utils

Tabs

Base-UI-Tabs. Die Kappung der Ausloeser kommt zentral ueber [role=tab] aus der Formensprache.

Jeder Auslöser trägt die Marken-Kappung über [role=tab].
npx shadcn@latest add @tessera/tabs

Zieht mit: @tessera/form, utils

ScrollArea

Scroll-Flaeche mit eigener, schmaler Leiste.

npx shadcn@latest add @tessera/scroll-area

Zieht mit: @tessera/form, utils

Collapsible

Auf- und zuklappender Ast, traegerlos — die Form kommt vom Inhalt.

npx shadcn@latest add @tessera/collapsible

Zieht mit: @tessera/form, utils

Table

Datentabelle mit Kopf, Fuss und Zeilenmarkierung. Grundlage jedes Gitters.

Pakete der Registry — drei von zwölf.
PaketFassungGröße
@dev0zzz.tessera.at/sdk0.4.1184 kB
@dev0zzz.tessera.at/cli0.2.092 kB
@dev0zzz.tessera.at/ui0.1.3311 kB
Gesamt587 kB
npx shadcn@latest add @tessera/table

Zieht mit: @tessera/form, utils

Pagination

Seitenwechsel als nav mit Liste und aria-current. Bringt paginationRange mit — welche Zahlen sichtbar sind, entscheidet nicht die Aufrufstelle.

Seite 7 von 42

npx shadcn@latest add @tessera/pagination

Zieht mit: @tessera/form, @tessera/button, utils

ColumnResizer

Ziehgriff fuer Spaltenbreiten. Button mit role=separator statt div — mit Pfeiltasten bedienbar, Breite als aria-valuenow.

FassungKanal
v0.5.2 — FormenspracheRadicle
v0.5.1 — DialogeRadicle

180 px — Pfeiltasten ±8, mit Umschalt ±80, Doppelklick setzt zurück

npx shadcn@latest add @tessera/column-resizer

Zieht mit: @tessera/form, utils

DataGrid

Tabelle mit Sortierung, Auswahl und ziehbaren Spalten. Haelt keinen Zustand — sortiert wird bei jeder ernsthaften Menge auf dem Server.

v0.0.0Radiclezurückgezogen2026-01-01120
v0.0.1GitHubsigniert2026-02-02157
v0.0.2npmjssigniert2026-03-03194
v0.0.3RadicleEntwurf2026-04-04231
v0.1.0GitHubsigniert2026-05-05268
v0.1.1npmjssigniert2026-06-06305
v0.1.2RadicleEntwurf2026-07-07342
v0.1.3GitHubzurückgezogen2026-08-08379
npx shadcn@latest add @tessera/data-grid

Zieht mit: @tessera/form, @tessera/table, @tessera/checkbox, @tessera/column-resizer, @tessera/skeleton, utils

Checkbox

Kaestchen — benannte Ausnahme der Formensprache: es behaelt seine eigene Form.

npx shadcn@latest add @tessera/checkbox

Zieht mit: @tessera/form, utils

Label

Beschriftung eines Feldes, verknuepft ueber htmlFor.

npx shadcn@latest add @tessera/label

Zieht mit: @tessera/form, utils

Textarea

Mehrzeiliges Feld. Ohne Ziehgriff — der sitzt in der Ecke, die die Kappung wegschneidet; die Hoehe kommt aus rows, das Mitwachsen schaltet die Aufrufstelle zu.

npx shadcn@latest add @tessera/textarea

Zieht mit: @tessera/form, utils

InputGroup

Feld mit Beiwerk — Lupe davor, Knopf dahinter, Zaehler darunter. Die zweite Huelle neben FieldShell, weiterhin genau ein Feld pro Huelle.

Zeilen/Seite
0/140
npx shadcn@latest add @tessera/input-group

Zieht mit: @tessera/form, @tessera/input, @tessera/textarea, utils

Popover

Freie Flaeche an einem Ausloeser. Kein Menue — die Pfeiltasten bleiben unangetastet, damit ein Formular darin bedienbar ist.

npx shadcn@latest add @tessera/popover

Zieht mit: @tessera/form, utils

Calendar

Monatsraster auf react-day-picker. Der Balken einer Spanne bleibt ein Rechteck — gekappt wird der Tagesknopf darauf.

August 2026
August 2026
npx shadcn@latest add @tessera/calendar

Zieht mit: @tessera/form, @tessera/button, utils

DatePicker

Datum und Zeitraum aus einem Kalender im Popover. Der Ausloeser ist ein Feld, kein Knopf; getippt wird nicht.

npx shadcn@latest add @tessera/date-picker

Zieht mit: @tessera/form, @tessera/calendar, @tessera/popover, utils

Select

Auswahl aus einer festen Liste. Der Ausloeser ist ein Feld, keine Schaltflaeche — Hoehe und Kappung folgen dem Input.

Kanal
npx shadcn@latest add @tessera/select

Zieht mit: @tessera/form, utils

Combobox

Auswahl mit Tippen, einfach und mehrfach. Die Mehrfachauswahl steckt mit drin — Chips als Huelle, ein Chip je gewaehltem Wert.

npx shadcn@latest add @tessera/combobox

Zieht mit: @tessera/form, utils

ToggleGroup

Segmentierte Auswahl. Die Gruppe traegt die Kappung des Kastens, jeder Knopf darin seine eigene.

npx shadcn@latest add @tessera/toggle-group

Zieht mit: @tessera/form, utils

Atome

Badge

Kappung 6px.

VerifiziertFreigegebenWartet auf FreigabeGesperrtEntwurf
npx shadcn@latest add @tessera/badge

Zieht mit: @tessera/form, utils

CodeBlock

Rendert code oder pre und ersetzt die sieben identischen Klassenketten, die vorher von Hand wiederholt wurden.

npx shadcn@latest add @tessera/button
npx shadcn@latest add @tessera/code-block

Zieht mit: @tessera/form, utils

FieldShell

Kappung und Ring fuer ein einzelnes Feld. Traegt die Kante, die das Input bewusst nicht selbst traegt.

npx shadcn@latest add @tessera/field-shell

Zieht mit: @tessera/form, utils

Toggle

Zweiwertiger Umschalter, gekappt.

Beitrag öffentlich
Zaps erlauben
Gesperrt
npx shadcn@latest add @tessera/toggle

Zieht mit: @tessera/form, utils

SearchInput

Suchfeld mit Lupe, gekappt und mit Kante.

npx shadcn@latest add @tessera/search-input

Zieht mit: @tessera/form, @tessera/input, utils

TesseraStart

Der Marken-Knopf.

Gefüllt, nie umrandet-mit-hohlem-Kern. Das Gold gehört der Hauptaktion, und die ist Create @handle — diese Knöpfe sieht nur, wer abgemeldet ist, und der ist meist neu hier. Drei Entwürfe liegen dahinter: Goldrand mit hohlem Kern (überkonstruiert), Gold für beide (dann sagt die Farbe nicht mehr, was primär ist), Betonung vertauscht. Jetzt leitet die Komponente die Optik aus intent ab, damit eine App sie nicht falsch wählen kann. Beide Füllungen sind deckend, also vom Untergrund unabhängig.

npx shadcn@latest add @tessera/tessera-start

Zieht mit: @tessera/form, @tessera/logo, utils

OrgCrest

Wappen einer Organisation, im Achteck.

npx shadcn@latest add @tessera/org-crest

Zieht mit: @tessera/form, utils

ActorAvatar

Form nach Herkunft: Tessera-Konten im Achteck mit Goldrand, alle anderen rund. Der Rand ist Polsterung auf gleich geformter Huelle, weil ein ring auf einer Kappung verschwindet.

JJ

Die Form sagt die Herkunft: Tessera-Konten im Achteck mit Goldrand, alle anderen rund. isTesseraActor prüft mit endsWith auf .tessera.at — nie mit includes, sonst könnte sich tessera.at.evil.example als heimisch ausgeben. Bekannte Grenze: Tessera-Konten auf eigener Domain lesen als fremd und bekommen den Kreis.

npx shadcn@latest add @tessera/actor-avatar

Zieht mit: @tessera/form, @tessera/actor-origin, utils

ActorIdentity

Wie ein Konto in Tessera erscheint: Avatar, Anzeigename, darunter das Handle mit @. Eine Figur fuer jede Stelle, an der ein Konto auftaucht.

D
dev0zzz@dev0zzz.tessera.atBaut Tessera. Radicle, Talos, zu viele Achtecke.
Konto
H
Haus Slytherin@haus-slytherin.tessera.at
J
Jemand von woanders@jemand.bsky.social
npx shadcn@latest add @tessera/actor-identity

Zieht mit: @tessera/actor-avatar, @tessera/form, utils

ContentSurface

Die Flaeche, auf der der Anwendungsinhalt sitzt: ein eigener Layer unter der Tab-Leiste, mit Tessera-Kante und optional mit vertikalen Reitern am Rand.

Tab-Leiste der Anwendung

Beschreibung

Der Inhalt steht auf einer eigenen Platte mit Tessera-Kante. Die Reiter am Rand gliedern innerhalb des Tabs weiter und wechseln mit der Fläche, nicht mit der App.

npx shadcn@latest add @tessera/content-surface

Zieht mit: @tessera/form, utils

SearchSyntaxHint

Das Fragezeichen am Suchfeld: zeigt feld:wert, Phrase, Ausschluss und Groessenvergleich mit den echten Feldnamen der Suche. Eine Syntax, die niemand sieht, benutzt niemand.

npx shadcn@latest add @tessera/search-syntax-hint

Zieht mit: @tessera/popover, @tessera/button, @tessera/form

Gefüge

AppShell

Das Grundgeruest einer Tessera-App: Sidebar mit Navigationsbaum, Inhalt als Inset. Kopf, Fuss und Suche sind Slots — Business gehoert in die Page.

Der Inhalt sitzt als eigene Platte neben der Navigation — hier steckt üblicherweise eine PageShell.
npx shadcn@latest add @tessera/app-shell

Zieht mit: @tessera/sidebar, @tessera/collapsible, @tessera/dropdown-menu, @tessera/form, utils

PageShell

Das Geruest jeder Listen- und Werkzeugseite: Kopfzeile mit Brotkrumen und Navigation, Tabs mit URL-Sync und Werkzeugleisten-Registry, darunter die Inhaltsflaeche. Suche ist ein Slot.

42 Einträge

Die Inhaltsfläche gehört der Page — hier stünde ein Grid.

Kopfzeile, Tabs und Werkzeugleiste sind Gerüst, kein Inhalt.

npx shadcn@latest add @tessera/page-shell

Zieht mit: @tessera/content-surface, @tessera/tabs, @tessera/breadcrumb, @tessera/dropdown-menu, @tessera/button, @tessera/badge, @tessera/sidebar, @tessera/form, utils

DetailPage

Vorlage einer Detailseite: Kopfzeile mit Nachbar-Navigation, Hero mit Bild, Titel, Status und Kennzahlen, Tab-Leiste, Slide-in-Panel fuer schmale Schirme.

skytess

rad:z3vhVW… — signierte Provenance

öffentlichsigniertRust1 Patch offen
Letzter Tag v0.9.3Delegates 2Patches offen 1
Auslieferung
Letzter Durchlauf 2026-08-05
v0.9.3Tag
4:12Bauzeit
18,4 MBGröße
Herkunft
cosign, Fulcio-frei
2Delegates
3Signaturen
1Spiegel
Der Rest gehört der Page
Die Vorlage liefert Kopfzeile, Nachbar-Navigation, Hero und Tabs. Was darunter steht — hier Karten, in einer Listenseite ein Grid — bringt die Page mit.
npx shadcn@latest add @tessera/detail-page

Zieht mit: @tessera/page-shell, @tessera/button, @tessera/sheet, @tessera/scroll-area, @tessera/sidebar, @tessera/form, utils

CommandPalette

Eine Suche ueber alles, auf ⌘K: gruppierte Treffer aus mehreren Quellen, Tastaturnavigation, Hervorhebung und Verlauf. Eine tote Quelle nimmt die anderen nicht mit.

Nichts gewählt.

npx shadcn@latest add @tessera/command-palette

Zieht mit: @tessera/dialog, @tessera/search-sources, @tessera/form, utils

SmartGrid

Die vollstaendige Liste: Suche, Facetten, Sortierung, Auswahl, Spaltenbreiten, Seitenwechsel und CSV-Export. Die Suche steckt hinter dem unified-search-Adapter — angeschlossen ist nichts.

Keine Treffer

npx shadcn@latest add @tessera/smart-grid

Zieht mit: @tessera/data-grid, @tessera/pagination, @tessera/select, @tessera/dropdown-menu, @tessera/button, @tessera/badge, @tessera/search-input, @tessera/search-syntax-hint, @tessera/csv-export, @tessera/unified-search, @tessera/form, utils

Bibliothek

actor-origin

isTesseraActor prueft mit endsWith auf .tessera.at — nie mit includes, sonst kann sich tessera.at.evil.example als heimisch ausgeben.

npx shadcn@latest add @tessera/actor-origin

csv-export

CSV und ausschliesslich CSV. Quotet nach RFC 4180, entschaerft fuehrende Formelzeichen und schreibt die Bytefolgenmarkierung, damit Excel Umlaute liest.

npx shadcn@latest add @tessera/csv-export

search-query

Die Abfragesprache des Suchfelds: feld:wert, "exakte Phrase", -ausschluss und datum>2026-01. Zerlegt nur — gefunden wird woanders.

npx shadcn@latest add @tessera/search-query

search-sources

Mehrere Quellen, eine Frage: fragt sie nebeneinander, gruppiert nach Herkunft und laesst eine tote Quelle die anderen nicht mitnehmen. Dazu die Hervorhebung der Treffer.

npx shadcn@latest add @tessera/search-sources

Anmeldung mit Tessera

Der komplette OIDC-Login gegen id.tessera.at: Session als verschluesseltes Cookie (iron-session), Login-/Callback-/Logout-Routen mit PKCE-Transaktions-Cookie, einmaliger Selbstheilung und RP-initiiertem Logout. Kanonische Quelle ist start-simple.

npx shadcn@latest add @tessera/auth-oidc

Regler — Schiene und bewegliches Teil

Kein Registry-Item — der Slider lebt bisher nur in dieser App. Schiene und bewegliches Teil tragen die Form einzeln; das Element selbst bleibt ungeclippt, ein Clip darauf würde den Griff an den Enden abschneiden. Die Goldfüllung braucht den Wert und kommt deshalb aus dem Slider-Atom, nicht aus dem CSS.

Roher input[type=range] — ohne AtomKorrekt geformt, aber einfarbig: die Form steckt im CSS, nur die Füllung braucht den Wert.

Die Regeln

  • Die Form ist ein Token. Eine Definition inapp/tessera-form.css, überall angewandt — nicht pro Komponente nachgebaut.
  • Die Form ist farbunabhängig. Gold, Rot, Amber: gleiche Silhouette, andere Bedeutung.
  • Fokus liegt innen. Im Browser gemessen: alles außerhalb der Form wird abgeschnitten — Umriss, Ring, Schatten.
  • Ausnahmen sind benannt. Kästchen, Radios, Schalter, Avatare und schwebende Ebenen (Menü, Tooltip) behalten ihre Form und ihre Schatten.
  • Das Zeichen wird nicht wiederholt. Es steht groß, wo es wirkt — Kopfzeile, Passkey-Schirm. Nicht in jedem Knopf: Auf der Startseite kam es sonst fünfmal vor. Die Marke trägt hier die Form.
  • ui/ wird nie angefasst. Die Sprache greift über die data-slot-Attribute, die shadcn selbst setzt.