tessera logo tessera — generated, do not edit

Framework graphique solarpunk

Tessera

Une identité graphique écrite une fois, puis dérivée pour chaque support au lieu d'être recopiée : un site, une application Android, un terminal, une feuille imprimée. Ce qu'on recopie à la main finit toujours par diverger.

Une tessera est la pièce unitaire d'un vitrail : un morceau de verre serti dans le plomb. Tout ce que l'outil produit est fait de ça. Une description en quinze lignes de YAML devient un SVG, puis un thème web, un VectorDrawable Android, une illustration imprimable.

Le fond de ce bloc en est un : une scène composée, seedée, dont la règle est que le milieu reste vide — c'est là que ce paragraphe est écrit. Il n'a pas de viewBox, donc ses massifs sont ancrés aux coins et non étirés, et il est inliné dans la page : posé en background-image il serait un document séparé, n'hériterait d'aucune custom property, et les quatre boutons ci-dessous ne le repeindraient pas.

Le principe

Un seul chemin, du texte jusqu'à l'image

Tessera n'est pas une banque d'images. C'est une grammaire de style, un vocabulaire de motifs et de rôles de couleur, et des générateurs déterministes. Même source et même seed donnent la même image, au bit près, ce qui permet à un humain de reproduire et à un agent d'itérer.

La source

Quinze lignes de YAML

Un LLM ne sait pas dessiner, mais il écrit très bien du YAML qui respecte un schéma. Un humain écrit le même fichier.

Le rendu

Un sous-ensemble strict de SVG

Uniquement ce qu'un VectorDrawable Android sait représenter : des path, des remplissages, des dégradés à deux arrêts. Ni filtre, ni masque, ni texte.

Les cibles

Dérivées, jamais redessinées

Web, Android, raster. Chaque sortie embarque sa source : une image retrouvée dans dix ans se régénère.

La grammaire

Ce qui fait qu'une image est de Tessera

Sept règles, chacune tirée d'une référence précise plutôt que d'un goût général. Elles contraignent la façon de dessiner, pas seulement le rendu.

Le plomb
Tout contour est un trait épais et uniforme. Pas de contour fin, pas de contour dégradé.vitrail — le plomb ferme chaque pièce de verre
Les aplats
L'intérieur d'une forme est une couleur unie, ou un dégradé à deux arrêts. Jamais d'ombre portée, jamais de flou.verre coloré, sérigraphie
La ligne coup de fouet
Les courbes sont des Béziers à tension asymétrique : lentes au départ, rapides à la fin.Art nouveau — Mucha, Horta
L'hexagone
La géométrie de structure est hexagonale, jamais carrée : grilles, pavages, cadres.baubotanik, alvéoles, panneaux solaires
Le soleil
Un rayonnement est le motif de lumière par défaut. Il remplace le halo blanc habituel des interfaces.solarpunk
La lumière chaude
Les fonds sont chauds et jamais neutres. Le blanc et le noir purs sont refusés par check.papier, crépuscule
Le végétal déborde
Une feuille peut sortir du cadre d'un demi-plomb : le vivant n'est pas contenu.forêt comestible, baubotanik

La palette

Des rôles, pas des couleurs

Les couleurs sont décrites en OKLCH, où deux teintes de même clarté se lisent comme également claires. Un site, une application ou une icône ne référence jamais leaf : elle référence ok. Changer de schéma ne change donc aucun fichier consommateur.

D'autres palettes

La grammaire tient, les couleurs changent

Trois palettes complètes, toutes acceptées par tessera palette check : mêmes rôles, mêmes règles de contraste, mêmes seuils. holly est rouge et vert, la combinaison classique du vitrail — et le pire cas possible, puisque rouge et vert sont les deux bouts de l'axe que la dichromatie efface. harbor est sa contre-épreuve sur l'axe bleu-jaune, celui qu'elle conserve.

Les trois passent check sans une erreur, et c'est bien le sujet : les seuils de contraste ne disent rien de ce qui se passe quand un axe disparaît. La distance affichée sous chaque palette est celle que palette check --json mesure entre ok et error sous deutéranopie — elle n'est pas recalculée ici.

Cliquez sur l'une d'elles : la page entière change de palette, y compris la planche de couleurs et la simulation de la vision des couleurs plus bas. Rien n'est recalculé à la volée — chaque palette est dérivée par palette build et sa feuille est simplement portée sur son propre sélecteur.

Les fichiers sont dans palettes/ : tessera palette check palettes/holly.yaml les juge comme il juge la nôtre.

Les quatre schémas

Le même balisage, quatre fois

Le sélecteur en haut de page n'en montre qu'un à la fois, et c'est justement ce qui cache l'essentiel. Les quatre vignettes ci-dessous sont le même fragment de HTML, au mot près : seul l'attribut data-scheme change. Aucune couleur n'y est écrite, elles ne référencent que des rôles — c'est ce que veut dire « changer de schéma ne touche aucun fichier consommateur ».

noon

Un titre

Du texte de corps, un lien, et les quatre statuts — chacun avec son glyphe.

✓ ok ! warn ✕ err i info

dusk

Un titre

Du texte de corps, un lien, et les quatre statuts — chacun avec son glyphe.

✓ ok ! warn ✕ err i info

night

Un titre

Du texte de corps, un lien, et les quatre statuts — chacun avec son glyphe.

✓ ok ! warn ✕ err i info

paper

Un titre

Du texte de corps, un lien, et les quatre statuts — chacun avec son glyphe.

✓ ok ! warn ✕ err i info

Le quatrième, paper, est à une encre : le verre n'y est pas peint et il ne reste que les traits. C'est le gabarit de pyrogravure — et le test d'accessibilité, puisqu'une interface lisible à une encre reste lisible sans vision des couleurs.

L'accessibilité

Ce que la couleur ne peut pas porter

Le contraste contre le fond, que la section précédente mesure, est la couche la plus superficielle. La vraie question n'est pas « ce texte se lit-il sur ce fond » mais « ces deux choses qui veulent dire des choses différentes se distinguent-elles l'une de l'autre ».

L'œil ne mesure pas une longueur d'onde : il compare trois réponses de cônes, que le cerveau recombine en une clarté et deux axes, rouge–vert et bleu–jaune. Il manque un cône ? Ce n'est pas une couleur qui disparaît, c'est un axe entier. Les quatre rôles de statut ci-dessous sont simulés en direct, avec les matrices de Viénot, Brettel et Mollon appliquées en sRGB linéaire — le même calcul que tessera palette check.

Un statut est un glyphe et une couleur, jamais une couleur seule.

Ce n'est pas une précaution, c'est un résultat. Le plomb doit garder 4,5 de contraste contre chaque pièce de verre, ce qui interdit les remplissages sous l ≈ 0,60 ; il reste environ 0,30 de plage de clarté. Quatre rôles séparés de 0,12 chacun en réclament 0,36. Ça ne rentre pas — et sans vision des couleurs, la clarté est tout ce qui reste. Aucun choix de couleurs ne répare ça, donc la forme porte ce que la couleur ne peut pas porter. C'est aussi la seconde vie du schéma paper : une interface lisible à une encre est une interface lisible sans vision des couleurs.

La typographie

Nommer les caractères, pas les dessiner

Tessera ne dessine pas de police et n'écrit pas de texte dans ses SVG — une icône qui porte du texte ne se traduit pas en VectorDrawable sans embarquer la fonte. Mais il nomme les caractères, exactement comme il nomme les couleurs : un consommateur ne référence jamais Fraunces, il référence display, comme il référence ok et jamais leaf.

Trois rôles suffisent. Le choix des fontes est un défaut, que chacun surcharge dans son propre tessera.yaml ; ce qui ne se surcharge pas, c'est l'obligation de déclarer un fallback et une licence.

Tessera
SOFT 0, WONK 0 — la fonte au repos
Tessera
SOFT 55, WONK 1 — ce que la page utilise

La ligne coup de fouet, mais dans une fonte.

Les deux échantillons sont le même fichier, à deux réglages d'axes près. WONK fait partir les terminaisons de travers, SOFT adoucit les extrémités : c'est la même asymétrie de tension que le paramètre whip du motif stem. C'est pour ça que Fraunces est là, et c'est ça qu'il faudra chercher dans son remplaçant — pas « une serif à fort contraste ».

display
Fraunces, une variable à quatre axes. Le titrage, et lui seul.Fraunces — OFL 1.1, fallback Georgia
body
Alegreya Sans, humaniste et chaude, et son italique est dessinée plutôt que penchée par le navigateur. Elle va avec des fonds linen et dusk, pas avec du blanc pur : la lumière chaude appliquée au texte.Alegreya Sans — OFL 1.1, fallback system-ui
mono
IBM Plex Mono, le choix ennuyeux, et c'est la qualité qu'on lui demande. Ligatures coupées : dans du code, != doit rester deux caractères.IBM Plex Mono — OFL 1.1, fallback ui-monospace

La scale — base 17 px, ratio 1,25

step −113,6 pxUne tessera
step 017 pxUne tessera
step 121,25 pxUne tessera
step 226,56 pxUne tessera
step 333,2 pxUne tessera
step 441,5 pxUne tessera

Les tailles sont engendrées, pas choisies : une valeur écrite à la main se détecte en recalculant son step. La measure du texte de corps est celle du tableau ci-dessus, dans la plage 45–75 que type check impose — c'est le défaut le plus fréquent d'un thème.

Les trois familles sont servies depuis ce dépôt et non depuis Google. Une page qui appelle un tiers à chaque visite n'est pas autonome, et cesse de s'afficher correctement le jour où le tiers s'arrête ; la spécification refuse d'ailleurs toute dépendance à l'exécution. Coût réel pour un lecteur francophone : 217 Kio, les plages latines seules.

La prose

Le markdown est un vocabulaire fermé

Les éléments que produit le markdown sont une quinzaine, et la liste est close depuis vingt ans : titres, paragraphes, listes, citation, code, tableau, lien. C'est la même forme que le vocabulaire de motifs — court, fermé, donc dérivable vers chaque cible sans arbitrage humain à chaque fois.

Il est aujourd'hui stylé quatre fois à la main, dans quatre langages : les classes prose de Tailwind pour un blog, un markdownTypography() en Kotlin pour Android, des styles ratatui pour un terminal, du CSS de carte pour Anki. Aucun des quatre ne sait ce que font les trois autres.

Ce que ça donne

Ce bloc est rendu avec les tokens ci-dessus, et rien d'autre. Le sélecteur de schéma en haut de page le reteint comme le reste.

Un filet de citation est du plomb : épais, uniforme, de la couleur outline. Jamais un dégradé, jamais un filet fin.
  • Une liste garde la measure du texte de corps.
  • Un lien prend le rôle link, qui est le seul rôle coloré autorisé à porter du texte.

Et un bloc de code est une pièce de verre : il porte son plomb et son aplat, et il défile horizontalement plutôt que de couper ou de replier. Une ligne de cent caractères sur un écran de 400 dp n'a pas d'autre issue — essayez de faire glisser celle-ci.

# Horizontal scroll is not a cop-out: it is the only honest way out.
fn status_indistinct_under_cvd(palette: &Palette, scheme: &str) -> Vec<Finding> {
    // Eight token families cannot be told apart by colour alone.
    let threshold = 0.10; // five times the perception threshold
}

Un token de code est en gras ou en italique et en couleur, jamais en couleur seule.

Même démonstration que pour les statuts, en pire : huit familles de tokens séparées de 0,12 réclameraient 0,96 de plage de clarté là où le plomb en laisse 0,30. Et il y a plus concret encore — mesuré sur cette palette, aucun rôle coloré ne tient comme texte sur surface en schéma noon : ok fait 2,44, accent_alt 2,71, accent 1,09. Les rôles colorés sont des remplissages clairs, contraints par le plomb ; posés sur un fond clair ils ne sont pas du texte. Le bloc ci-dessus n'a donc que deux encres et quatre distinctions, et c'est exactement pourquoi il reste lisible en paper. Lui donner des couleurs demanderait des rôles de texte qui n'existent pas encore : c'est Q6.

Les icônes

Un vocabulaire fermé, sur une grille de 32

Une icône n'est pas un chemin SVG écrit à la main, mais une composition de motifs : stem, leaf, sun, hex, wave, soil. C'est ce qui garantit le style quel que soit l'auteur, humain ou agent — et c'est vérifiable, puisque lint compte les fois où il a fallu sortir du vocabulaire.

Celles-ci sont rendues par tessera icon render depuis icons/*.yaml, et elles sont tracées en currentColor : une icône line n'a pas de verre à séparer, elle prend donc la couleur du texte là où elle se pose. C'est aussi ce qui la fait survivre au mode contraste forcé, où un remplissage écrit en dur disparaît.

Chacune est montrée deux fois : en grand, et à 24 px — la taille à laquelle elle sert réellement. C'est pour cette seconde ligne que la règle existe : aucune pièce sous deux fois le plomb, faute de quoi le contour se referme sur elle et il ne reste qu'une tache.

Vingt-deux icônes, dont seize de besoins ordinaires — accueil, retour, valider, refuser, ignorer, rechercher. Une seule a eu besoin de l'échappatoire : le triangle d'avertissement, que ni l'hexagone ni la feuille ni le soleil ne donnent et que trois traits ne fermeraient pas. C'est la réponse à une question ouverte depuis le premier jour : 5 % contre un seuil fixé au tiers.

Deux d'entre elles disent le vocabulaire mieux que les autres. delete est un composteur et pas une poubelle : supprimer, ici, c'est rendre à la terre. Et retry est une éolienne à axe vertical, dont les deux pales sont le même stem courbé en sens inverse — réessayer, c'est un cycle qui reprend, et une éolienne est ce qui tourne sans qu'on la relance.

Chaque icône sort deux fois, en SVG et en VectorDrawable Android, et c'est le même dessin : le pathData du XML est octet pour octet le d du SVG. Un seul détail les sépare, et il est piégeux — un viewport de VectorDrawable est ancré en 0,0 et n'a pas d'origine à régler, alors que le viewBox commence en négatif pour porter le bleed. Le décalage passe donc par un <group android:translate> plutôt que par une réécriture des coordonnées : une seule géométrie, émise deux fois, qui ne peut pas diverger.

Ajouter tessera icon add — generated, do not edit Ajouter tessera icon add — generated, do not edit
add
Retour tessera icon back — generated, do not edit Retour tessera icon back — generated, do not edit
back
Valider tessera icon check — generated, do not edit Valider tessera icon check — generated, do not edit
check
Fermer tessera icon close — generated, do not edit Fermer tessera icon close — generated, do not edit
close
Supprimer tessera icon delete — generated, do not edit Supprimer tessera icon delete — generated, do not edit
delete
Modifier tessera icon edit — generated, do not edit Modifier tessera icon edit — generated, do not edit
edit
Erreur tessera icon error — generated, do not edit Erreur tessera icon error — generated, do not edit
error
Suivant tessera icon forward — generated, do not edit Suivant tessera icon forward — generated, do not edit
forward
Une alveole tessera icon hex — generated, do not edit Une alveole tessera icon hex — generated, do not edit
hex
Accueil tessera icon home — generated, do not edit Accueil tessera icon home — generated, do not edit
home
Information tessera icon info — generated, do not edit Information tessera icon info — generated, do not edit
info
Menu tessera icon menu — generated, do not edit Menu tessera icon menu — generated, do not edit
menu
Un reseau tessera icon network — generated, do not edit Un reseau tessera icon network — generated, do not edit
network
Retirer tessera icon remove — generated, do not edit Retirer tessera icon remove — generated, do not edit
remove
Reessayer tessera icon retry — generated, do not edit Reessayer tessera icon retry — generated, do not edit
retry
Rechercher tessera icon search — generated, do not edit Rechercher tessera icon search — generated, do not edit
search
Une pousse qui sort de terre tessera icon seedling — generated, do not edit Une pousse qui sort de terre tessera icon seedling — generated, do not edit
seedling
Reglages tessera icon settings — generated, do not edit Reglages tessera icon settings — generated, do not edit
settings
Ignorer tessera icon skip — generated, do not edit Ignorer tessera icon skip — generated, do not edit
skip
Un soleil tessera icon sun — generated, do not edit Un soleil tessera icon sun — generated, do not edit
sun
Avertissement tessera icon warning — generated, do not edit Avertissement tessera icon warning — generated, do not edit
warning
De l'eau tessera icon wave — generated, do not edit De l'eau tessera icon wave — generated, do not edit
wave

Le style pane — les mêmes fichiers avec leurs aplats de verre — arrive en v0.4. Le même fichier donne les deux : pane sans les remplissages est line, ce qui est une contrainte sur la façon de dessiner et non une option de rendu.

Les marques

Un logo n'est pas une grande icône

Une icône appartient à un jeu, se lit à 24 px et n'a qu'une couleur parce qu'elle prend celle de l'endroit où elle est posée. Une marque est seule, porte son propre verre, et doit survivre à seize pixels dans un onglet — en dessous de tout ce qu'icon lint a jamais vérifié, ses règles ayant été écrites pour 24.

Quatre marques, un seul vocabulaire. Le vitrail de Tessera — celui du haut de cette page, et celui de l'onglet, sont le même fichier —, le feuillage vu de dessus de Canopée, le losange de Continuity, l'atelier nocturne d'Alex. Chacune est montrée en grand et à 20 px ; changez de schéma en haut de page, elles suivent.

Jusqu'à cette version, l'emblème en haut de page était écrit à la main dans le fichier HTML : douze path posés un par un, la seule chose que cette page montrait et que l'outil ne produisait pas. C'est maintenant logos/tessera.yaml, rendu comme le reste.

Canopée ne prend pas la palette de cette page : elle déclare palette: palettes/rhizome.yaml et porte les verts de son propre projet. Ses cames sont noires et épinglées, mais son pourtour garde l'encre mesurée — une marque doit se voir sur le fond où elle atterrit, et un cadre noir sur une page noire est une marque que personne ne trouve.

Alex n'a pas eu besoin qu'on lui invente un sujet : il était écrit deux fois. Sa palette dit d'elle-même « a workshop at night: one lit bench, instruments around it », et son README décrit une configuration nommée Addressed : « a roster, one recipient — that agent answers and the others stay out, even though they are in the room ». Plusieurs, présents, un seul allumé. La version précédente était une ruche : elle disait « plusieurs cellules » et s'arrêtait là.

Deux essais ont été jetés en chemin, et savoir pourquoi vaut mieux que d'y revenir. Six secteurs autour d'un disque central donnent le symbole de radioactivité — impossible de ne plus le voir. Les mêmes six sans le disque font converger six plombs en un point, ce qui se lit comme un spinner de chargement. Deux plombs croisés suffisent.

Et la métaphore avait trois parties dont je n'avais dessiné que deux : il manquait la fenêtre. Avec les seuls deux noirs et la lueur ambre, la marque lisait comme un œil rouge dans le noir plutôt que comme un atelier. Une pièce en info donne la seconde source de lumière — une froide, une chaude — et la nuit reste, parce que le fichier d'Alex appelle son schéma sombre « the honest default » : un terminal l'est.

Continuity ne se dessine pas, elle se transpose : sa marque existait avant Tessera, un losange rouge dans un cercle noir sur blanc. Le cercle blanc devient l'hexagone, et les proportions du losange — ratio 1,32, demi-hauteur à 0,82 du rayon du disque — sont relevées sur l'icône Android existante plutôt que choisies. C'est ce qui fait qu'on reconnaît la même marque.

Son rouge d'origine, #cc0000, a été refusé par palette check : un came noir posé dessus lit 2,94, sous le seuil AA de 4,5, et c'est exactement la règle qui empêche un plomb de disparaître dans son verre. Elle porte donc clay. Ce que ça révèle et qui reste ouvert : une palette n'a aucun moyen de dire « cette couleur est une marque, jamais un fond » — rien n'est posé sur ce losange, et il est refusé parce que le seul rôle qu'il puisse emprunter est un rôle sur lequel on écrit.

Elle a d'abord été une tortue, et le pavage n'y était pour rien. Ce qui faisait la carapace était le plomb de pourtour lourd autour d'un dôme de cellules vertes, plus l'absence totale de lumière. Décaler le réseau, allonger les mailles, monter le désordre : quatre essais, quatre dossières. Il a fallu retirer le rebord et ouvrir des trous de jour entre les feuilles — une canopée vue d'en haut en a, et sans eux le vert uniforme se lit comme de la corne.

La marque de Tessera n'est pas la seule à utiliser l'échappatoire, et c'est délibéré : ses quatre pièces sont des path. Une pièce de verre irrégulière est précisément ce que le vocabulaire de motifs ne couvre pas — un hexagone les donnerait toutes identiques, et un pavage d'hexagones réguliers est une ruche, ce qui est déjà la marque d'Alex.

tessera logo alex — generated, do not edit
alex
tessera logo canopee — generated, do not edit
canopee
tessera logo continuity — generated, do not edit
continuity
tessera logo tessera — generated, do not edit
tessera

tessera logo tessera — generated, do not edit Tessera

Le plomb de ces marques n'est pas outline. C'est --ts-ink-on-surface, l'encre mesurée sur le verre : outline sur surface vaut 1,17 dans le schéma sombre, et le cadre de l'hexagone disparaissait purement et simplement — présent dans le fichier, absent de l'écran.

Le mot n'est pas dans le fichier. Un lockup est la marque à côté du nom composé en display, en HTML : le nom reste sélectionnable, atteint un lecteur d'écran, et obéit au contrat typographique qui existe déjà. Le figer en contours mettrait la fonte deux fois dans le dépôt — le subset qui est servi, et les lettres soudées dans la marque.

Les diagrammes

Tessera ne dessine pas le schéma, il l'habille

Un thème de diagramme est le même geste qu'une palette GIMP : un outil tiers dessine, Tessera lui donne ses couleurs. Les deux schémas ci-dessous ne sont pas des images — ils sont rendus par d2 et par mermaid depuis les thèmes que palette build émet, puis chaque couleur y est remplacée par la variable dont elle vient. Changez de schéma en haut de page : ils se repeignent avec le reste.

d2 — tessera.d2

tessera.yamlcheckwebandroiddiagrammes validecsscolors.xmld2, mermaid

mermaid — tessera-mermaid.json

tessera.yaml

check

web

android

diagrammes

Les deux schémas disent la même chose, et pourtant ils ne reçoivent pas la palette de la même façon. D2 importe son thème par ...@tessera : les couleurs arrivent par vars, le plomb par classes, et un nœud prend une catégorie en nommant une classe. Mermaid n'a pas d'import, et son thème ne sait pas peindre un nœud de diagramme autrement que tous les autres — primaryColor les remplit tous, et les cScale ne servent qu'aux frises et aux camemberts. Les classes doivent donc vivre dans le diagramme : ici elles sont engendrées depuis la palette et ajoutées au rendu, chez un humain elles se collent.

Il reste une chose que mermaid ne peut pas prendre : ses variables de thème n'ont pas de réglage d'épaisseur, donc le plomb y est une couleur et pas un trait. C'est une limite de l'outil et non un choix, et elle se voit — les contours du schéma de gauche sont épais, ceux de droite ne le sont pas. Mermaid est là malgré ça, parce qu'il a deux consommateurs déjà en place : Obsidian le rend nativement, et le thème du blog l'embarque.

Les sources

Ce qu'on écrit réellement

Les deux contrats de tokens — la palette et les caractères — vivent côte à côte dans un seul fichier : une identité graphique est une chose, et la première question devant un dépôt inconnu est où est le fichier. Les dessins, eux, ont un fichier par pièce.

# tessera.yaml — un fichier, une identité
name: tessera

palette:
  space: oklch
  default_scheme: noon
  dark_scheme: dusk
  colors:
    sun:   { l: 0.860, c: 0.150, h: 85 }
    leaf:  { l: 0.620, c: 0.140, h: 140 }
    lead:  { l: 0.220, c: 0.020, h: 280 }
    linen: { l: 0.960, c: 0.015, h: 85 }
  schemes:
    noon:
      bg: linen
      text: soil
      outline: lead
      ok: leaf
      # ... les douze rôles

type:
  stacks:
    display: { family: Fraunces, licence: OFL-1.1,
               fallback: [Georgia, serif],
               axes: { SOFT: 55, WONK: 1 } }
    body:    { family: Alegreya Sans, licence: OFL-1.1,
               fallback: [system-ui, sans-serif] }
    mono:    { family: IBM Plex Mono, licence: OFL-1.1,
               fallback: [ui-monospace, monospace],
               ligatures: false }
  scale:   { base: 17, ratio: 1.25, steps: [-1, 0, 1, 2, 3, 4] }
  measure: 64
# icons/seedling.yaml
name: seedling
grid: 32
lead: 3
bleed: 1.5
motifs:
  - soil: { y: 28, width: 16 }
  - stem:
      from: [16, 28]
      to:   [16, 12]
      whip: 0.15
  - leaf:
      at: [16, 16]
      dir: left
      size: 7
      fill: ok
  - sun: { at: [24, 7], r: 4, fill: accent }
tags: [nature, growth, start]

Les sorties

Une source, chaque cible

ObjetWebAndroidRaster et impression
palette tessera.css, palette.json colors.xml, objet Compose tessera.gpl, swatch.svg, tessera.d2
type tessera.type.css, tessera.prose.css, les woff2 TesseraType.kt, markdownTypography() @media print du schéma paper
icon SVG, sprite <symbol> VectorDrawable PNG de 24 à 512 px
pattern SVG <pattern> tuile par densité JPG grande taille, métadonnées embarquées

L'état

La palette est écritev0.1

Le binaire lit tessera.yaml, le valide et en dérive le CSS, le JSON, les ressources Android, l'objet Compose, la palette GIMP, le swatch de revue et un thème D2. Trente-neuf tests, dont ceux qui épinglent les hexadécimaux et les ratios affichés sur cette page.

La typographie est entrée ensuite, et les icônes ont glissé d'un cran. Le raisonnement est celui d'un consommateur plutôt que d'un goût : le premier usage réel de Tessera est un agent local, dont l'interface est du texte et du markdown rendu, et qui n'a besoin d'aucune icône pour démarrer.

C'est lui qui a révélé les trois défauts corrigés le 19 septembre : deux sorties promises et jamais écrites, qui lui coûtaient 282 lignes de générateur et une seconde conversion OKLCH ; quinze commentaires hexadécimaux faux sur vingt, d'où une règle qui les vérifie ; et un mapping Material 3 qu'aucune valeur fixe ne satisfait, puisque l'encre lisible sur un accent change avec le schéma. Un consommateur qui tourne trouve ce qu'aucune relecture ne trouve.

check a refusé la palette de la spécification le lendemain de son écriture, sur trois points réels : sun hors du gamut sRGB, water trop sombre pour que le plomb reste visible, et une règle de contraste insatisfiable. C'est l'argument pour écrire les règles avant les dessins : une palette qui a l'air juste ne l'est pas.

v0.1La palette : le format, check, build. Faite.
v0.2La typographie et la prose : les trois rôles de caractère, les fontes dans le dépôt, type check et type build. En cours — les fontes y sont, le fichier unique aussi.
v0.3Les icônes line : le vocabulaire de motifs, lint, SVG et VectorDrawable, vingt-deux icônes. Faites — le pathData du XML est octet pour octet le d du SVG.
v0.4Les icônes pane : remplissages par rôle, ressources Android et Compose.
v0.5Les backgrounds : une scène composée, ancrée aux bords, avec une bande de contenu que check mesure. Passés devant les patterns, parce que deux applications web en avaient besoin.
v0.6Les patterns : treillis hexagonal, vigne, et le pavage de verre proprement dit.
v0.7La galerie et schema : un agent produit une icône depuis une phrase.
v0.8Les marques et les favicons : quatre marques, favicon.svg bi-schéma, .ico 16/32, apple-touch-icon et maskable. Faites — cette page sert les siennes.

Ce qui reste ouvert

Trois questions sans réponse

Q4

Le vocabulaire de motifs est-il assez expressif pour vingt icônes d'interface sans recourir à l'échappatoire path ? Si path dépasse un tiers des icônes, le vocabulaire est trop court. Cela ne se tranche pas sur le papier : la v0.3 le mesure en dessinant.

Q5

Sous quelle licence les icônes et les patterns ? CC0 laisse tout prendre, y compris fermer un dérivé. CC BY-SA protège le commun mais pose à chaque application la question de l'œuvre dérivée. Les assets étant générés, la valeur est dans le générateur, pas dans le PNG.

Q9

Le premier consommateur réel utilise Tailwind, qui n'attend pas douze rôles sémantiques mais trois familles de dix rampes. Cette projection est-elle une sortie de Tessera, régénérable et vérifiable ? Ce serait cohérent avec tout le reste, mais ça ferait entrer un thème tiers dans le contrat du framework — et c'est le premier à réclamer des rampes là où Tessera ne promet que des rôles.