From f5d8d41a0071aa40e9e440d275d45df2c3ba86e7 Mon Sep 17 00:00:00 2001 From: Pierre MARTIN Date: Tue, 3 Nov 2026 01:22:21 +0100 Subject: [PATCH] Charte graphique : copie du design system et journal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Couleurs des deux thèmes (mêmes noms que web/app.css), styles des composants, guide de marque et dessin de référence du plateau dans docs/identite/charte/, avec les liens vers le design system et les maquettes d'écrans. Coquille corrigée dans l'ADR 0010. Co-Authored-By: Claude Opus 5.5 --- docs/adr/0010-identite-visuelle.md | 2 +- docs/identite/README.md | 5 + docs/identite/charte/README.md | 41 ++ docs/identite/charte/board.js | 74 ++++ docs/identite/charte/bundle.css | 165 ++++++++ docs/identite/charte/guide-de-marque.md | 61 +++ docs/identite/charte/tokens.json | 530 ++++++++++++++++++++++++ docs/journal.md | 21 + 8 files changed, 898 insertions(+), 1 deletion(-) create mode 100644 docs/identite/charte/README.md create mode 100644 docs/identite/charte/board.js create mode 100644 docs/identite/charte/bundle.css create mode 100644 docs/identite/charte/guide-de-marque.md create mode 100644 docs/identite/charte/tokens.json diff --git a/docs/adr/0010-identite-visuelle.md b/docs/adr/0010-identite-visuelle.md index 62119a9..4dc67b6 100644 --- a/docs/adr/0010-identite-visuelle.md +++ b/docs/adr/0010-identite-visuelle.md @@ -29,7 +29,7 @@ couleur, en monochrome et en taille réelle d'icône (48 et 24 px). noyer et brique, comme les flèches d'un plateau. En monochrome, les quatre flèches prennent la couleur du texte. - **Icône d'application** : symbole sur fond ivoire `#F3EAD8`. -- **Police** : Alegreya Sans (SIL Open Font License 1.1), pour le logotype et, +- **Police** : Alegreya Sans (SIL Open Font License 1.1), pour le logotype et pour l'interface. Pierre a validé cette dépendance, ainsi que fontTools (MIT), outil de développement qui sert à régénérer le logotype, le 2026-11-03. diff --git a/docs/identite/README.md b/docs/identite/README.md index af8d616..06f6fe3 100644 --- a/docs/identite/README.md +++ b/docs/identite/README.md @@ -46,3 +46,8 @@ python3 -I docs/identite/generer-logo.py build/police/AlegreyaSans-Bold.ttf docs Les PNG sont des rendus des SVG par Chrome sans interface (`google-chrome --headless --screenshot`), à la taille indiquée dans leur nom. + +## Charte graphique + +La charte complète (couleurs des deux thèmes, typographie, composants) est dans +`charte/`, avec les liens vers le design system et les maquettes d'écrans. diff --git a/docs/identite/charte/README.md b/docs/identite/charte/README.md new file mode 100644 index 0000000..e3801f1 --- /dev/null +++ b/docs/identite/charte/README.md @@ -0,0 +1,41 @@ +# Charte graphique d'Ustagammon + +Copie de travail du design system, pour l'appliquer à la PWA sans dépendre +d'un accès à claude.ai. La référence vivante, avec aperçus dans les deux thèmes : + +- Design system : https://claude.ai/artifact/K2Z7MPE58XXJzv19n5r11M +- Maquettes des écrans (accueil, plateau, leçon, fin de partie, thème sombre) : + https://claude.ai/artifact/CQw6vbDpi6XQqVWQa4sANe + +Décisions : ADR 0010. Fichiers du logo et des icônes : `../logo/`. + +## Fichiers + +| Fichier | Contenu | +| --- | --- | +| `guide-de-marque.md` | Règles d'usage : ton, couleurs, typographie, formes, mouvement, icônes, composants | +| `tokens.json` | Toutes les valeurs, thèmes clair et sombre, avec une note d'usage par couleur | +| `bundle.css` | Styles des composants ; mêmes noms de classes que `web/app.css` | +| `board.js` | Dessin de référence du plateau (repère 640 × 520), pour comparaison | + +## Appliquer la charte à `web/` + +1. **Couleurs** : les variables du plateau de `web/app.css` (`--frame`, `--bed`, + `--point-a`, `--checker-player`…) ont les mêmes noms dans `tokens.json` ; + reprendre leurs valeurs, thème clair dans `:root`, thème sombre dans le bloc + `prefers-color-scheme: dark`. Remplacer l'accent vert provisoire par la + brique (`--accent`, `--highlight`, `--target`) et ajouter les couleurs + nouvelles (`surface`, `accent-soft`, `verdict-*`, `focus`, `last-move` en laiton). +2. **Police** : embarquer Alegreya Sans (Regular, Italic, Medium, Bold, + ExtraBold) dans `web/`, avec sa licence OFL, en `@font-face`, et l'ajouter + au cache du service worker (hors ligne). +3. **Composants** : reprendre de `bundle.css` les boutons ronds + (`radius-pill`), le filet intérieur des pions, l'anneau de focus et la zone + de consigne. +4. **Icônes et logo** : remplacer `web/icons/` par les fichiers de + `../logo/` (icônes any et maskable, favicon), mettre le logo horizontal + dans la barre haute, et la couleur `theme-color` du manifeste à `#4A2E1F`. + +Les contrastes de tous les textes ont été vérifiés par calcul (4,5:1 au moins +dans les deux thèmes) ; les marques du plateau, à 3:1 contre au moins un de +leurs voisins. diff --git a/docs/identite/charte/board.js b/docs/identite/charte/board.js new file mode 100644 index 0000000..cce1f44 --- /dev/null +++ b/docs/identite/charte/board.js @@ -0,0 +1,74 @@ +/* Dessin de référence du plateau Ustagammon, en SVG, avec les classes de bundle.css. + * Repère : 640 × 520, comme web/app.css (.board, aspect-ratio 640 / 520). + * Numérotation du point de vue du joueur : 1 à 12 en bas (de droite à gauche), + * 13 à 24 en haut (de gauche à droite). Le joueur a les pions ivoire. */ +window.UstaBoard = (function () { + var W = 640, H = 520, SIDE = 16, TB = 28, PW = 43, BAR = 40, PH = 190, R = 20; + var TRAY_X = 580, TRAY_W = 44; + + function colX(col) { return SIDE + col * PW + (col >= 6 ? BAR : 0); } + function place(point) { // point 1..24 → {col, top} + return point <= 12 ? { col: 12 - point, top: false } : { col: point - 13, top: true }; + } + function checker(cx, cy, side, extra) { + var c = side === "player" ? "player" : "computer"; + return '' + + ''; + } + function die(x, y, n, side) { + var s = 36, p = { 1: [[.5, .5]], 2: [[.27, .27], [.73, .73]], 3: [[.27, .27], [.5, .5], [.73, .73]], + 4: [[.27, .27], [.73, .27], [.27, .73], [.73, .73]], 5: [[.27, .27], [.73, .27], [.5, .5], [.27, .73], [.73, .73]], + 6: [[.27, .25], [.73, .25], [.27, .5], [.73, .5], [.27, .75], [.73, .75]] }[n]; + var out = ''; + p.forEach(function (q) { out += ''; }); + return out; + } + + /* state = { checkers: {point: [side, n]}, selected: point, movable: [points], + * targets: [points], lastMove: [points], dice: [a, b], diceSide, cube } */ + function svg(state) { + var o = ''; + o += ''; + o += ''; + o += ''; + o += ''; + o += ''; + for (var point = 1; point <= 24; point++) { + var pl = place(point), x = colX(pl.col), cls = (pl.col % 2 === 0) === pl.top ? "point-a" : "point-b"; + var base = pl.top ? TB : H - TB, apex = pl.top ? TB + PH : H - TB - PH; + o += ''; + if ((state.targets || []).indexOf(point) >= 0) + o += ''; + if ((state.lastMove || []).indexOf(point) >= 0) + o += ''; + o += '' + point + ''; + var c = (state.checkers || {})[point]; + if (c) { + var shown = Math.min(c[1], 5); + for (var i = 0; i < shown; i++) { + var cy = pl.top ? TB + R + 1 + i * (2 * R + 1) : H - TB - R - 1 - i * (2 * R + 1); + var extra = ""; + if (i === shown - 1 && state.selected === point) extra = "selected"; + else if (i === shown - 1 && (state.movable || []).indexOf(point) >= 0) extra = "movable"; + o += checker(x + PW / 2, cy, c[0], extra); + if (i === shown - 1 && c[1] > 5) + o += '' + c[1] + ''; + } + } + } + if (state.dice) { + var dx = colX(8) + 6, dy = H / 2 - 18, side = state.diceSide || "player"; + o += die(dx, dy, state.dice[0], side) + die(dx + 46, dy, state.dice[1], side); + } + if (state.cube) { + var bx = SIDE + 6 * PW + 2; + o += ''; + o += '' + state.cube + ''; + } + return o + ''; + } + + var OPENING = { 24: ["player", 2], 13: ["player", 5], 8: ["player", 3], 6: ["player", 5], + 1: ["computer", 2], 12: ["computer", 5], 17: ["computer", 3], 19: ["computer", 5] }; + return { svg: svg, OPENING: OPENING }; +})(); diff --git a/docs/identite/charte/bundle.css b/docs/identite/charte/bundle.css new file mode 100644 index 0000000..f30bfdf --- /dev/null +++ b/docs/identite/charte/bundle.css @@ -0,0 +1,165 @@ +/* Ustagammon — styles des composants. + * Toutes les valeurs viennent de tokens.json (variables CSS du même nom). + * Les noms de classes reprennent ceux de web/app.css : ce fichier peut être + * recopié dans l'application presque tel quel. */ + +body { + margin: 0; + font-family: var(--font-sans); + font-size: 17px; + line-height: 25px; + color: var(--text); + background: var(--background); +} + +a { color: var(--accent); text-underline-offset: 3px; } + +:focus-visible { + outline: 3px solid var(--focus); + outline-offset: 2px; +} + +/* ------------------------------------------------------------ Barre haute */ + +.topbar { + display: flex; + gap: var(--space-2); + align-items: center; + padding-block: var(--space-2); +} +.topbar .brand { flex: 1; display: flex; align-items: center; min-width: 0; } +.topbar .brand img { height: 32px; width: auto; display: block; } +.topbar h1 { flex: 1; margin: 0; font-size: 20px; line-height: 26px; font-weight: 700; } + +/* ---------------------------------------------------------------- Boutons */ + +button, .button { + min-height: var(--button-height); + padding: 0 20px; + font: inherit; + font-weight: 700; + color: var(--on-accent); + background: var(--accent); + border: 2px solid var(--accent); + border-radius: var(--radius-pill); + cursor: pointer; +} +button.secondary, .button.secondary { + color: var(--text); + background: transparent; + border-color: var(--border-strong); +} +button.quiet, .button.quiet { + min-height: 44px; + padding: 0 12px; + color: var(--text); + background: transparent; + border-color: transparent; + font-weight: 500; +} +.topbar button { min-height: 44px; padding: 0 14px; font-size: 15px; } +button:disabled { opacity: 0.45; cursor: default; } + +.actions { display: flex; flex-wrap: wrap; gap: var(--space-2); } +.actions button { flex: 1; } + +/* ------------------------------------------------------- Zone de consigne */ + +.pips { margin: var(--space-1) 0 0; font-size: 15px; line-height: 20px; color: var(--muted); text-align: center; font-variant-numeric: tabular-nums; } +.info, .prompt { min-height: 25px; margin: 6px 0; } +.info { color: var(--muted); } +.prompt { font-weight: 700; } +.prompt.thinking::after { content: ""; animation: thinking 1.2s steps(4, end) infinite; } +@keyframes thinking { 0% { content: ""; } 25% { content: "."; } 50% { content: ".."; } 75% { content: "..."; } } +@media (prefers-reduced-motion: reduce) { .prompt.thinking::after { animation: none; content: "…"; } } + +/* ---------------------------------------------------------------- Plateau */ + +.board { display: block; width: 100%; height: auto; user-select: none; -webkit-tap-highlight-color: transparent; } +.board-frame { fill: var(--frame); } +.board-bed { fill: var(--bed); } +.board-bar { fill: var(--bar); } +.board-tray { fill: var(--tray); } +.point-a { fill: var(--point-a); } +.point-b { fill: var(--point-b); } +.point-number { fill: var(--point-number); font-size: 13px; font-weight: 500; text-anchor: middle; font-family: var(--font-sans); } +.checker { stroke-width: 2; } +.checker-player { fill: var(--checker-player); stroke: var(--checker-player-edge); } +.checker-computer { fill: var(--checker-computer); stroke: var(--checker-computer-edge); } +.checker-ring { fill: none; stroke-width: 1.5; } +.checker-player + .checker-ring, .ring-player { stroke: var(--checker-player-edge); } +.ring-computer { stroke: var(--checker-computer-edge); } +.checker.movable { stroke: var(--highlight); stroke-width: 3; } +.checker.selected { stroke: var(--highlight); stroke-width: 6; } +.checker-count { font-size: 18px; font-weight: 700; text-anchor: middle; font-family: var(--font-sans); } +.count-player { fill: var(--count-player); } +.count-computer { fill: var(--count-computer); } +.target-zone { fill: var(--target); } +.last-move { fill: var(--last-move); } +.die-player { fill: var(--die-player); stroke: var(--checker-player-edge); stroke-width: 1.5; } +.die-computer { fill: var(--die-computer); stroke: var(--checker-computer-edge); stroke-width: 1.5; } +.pip-player { fill: var(--pip-player); } +.pip-computer { fill: var(--pip-computer); } +.cube-face { fill: var(--cube); stroke: var(--checker-player-edge); stroke-width: 2; } +.cube-value { fill: var(--cube-text); font-size: 17px; font-weight: 800; text-anchor: middle; font-family: var(--font-sans); } + +/* ------------------------------------------------------------------ Cartes */ + +.card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-md); + box-shadow: var(--shadow-raised); + padding: var(--space-4); + display: flex; + flex-direction: column; + gap: var(--space-2); +} +.overline { font-size: 13px; line-height: 16px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); } + +/* --------------------------------------------------- Appréciation d'un coup */ + +.verdict { + display: inline-flex; + align-items: center; + gap: var(--space-1); + font-weight: 700; + font-size: 15px; + line-height: 20px; +} +.verdict svg { width: 18px; height: 18px; flex: none; } +.verdict-good { color: var(--verdict-good); } +.verdict-doubtful { color: var(--verdict-doubtful); } +.verdict-bad { color: var(--verdict-bad); } + +/* -------------------------------------------------------- Fiche de glossaire */ + +.glossary-card h3 { margin: 0; font-size: 20px; line-height: 26px; font-weight: 700; } +.glossary-card .en { color: var(--muted); font-size: 15px; line-height: 20px; font-style: italic; } +.glossary-card p { margin: 0; } +.glossary-card .see { font-size: 15px; line-height: 20px; color: var(--muted); } + +/* ------------------------------------------------ Demander à une IA (prompt) */ + +.ask-ai { display: flex; flex-direction: column; gap: var(--space-2); } +.ask-ai pre { + margin: 0; + max-height: 7.5em; + overflow: auto; + padding: var(--space-3); + background: var(--surface-sunken); + border-radius: var(--radius-md); + font: 15px/20px var(--font-sans); + white-space: pre-wrap; + color: var(--text); +} +.ask-ai .done { color: var(--verdict-good); font-weight: 700; font-size: 15px; } + +/* ---------------------------------------------------------- Carte de leçon */ + +.lesson-card { flex-direction: row; align-items: center; gap: var(--space-3); } +.lesson-card .body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; } +.lesson-card h3 { margin: 0; font-size: 17px; line-height: 25px; font-weight: 700; } +.lesson-card .state { font-size: 15px; line-height: 20px; color: var(--muted); } +.progress { height: 6px; border-radius: var(--radius-pill); background: var(--surface-sunken); overflow: hidden; } +.progress > span { display: block; height: 100%; background: var(--accent); border-radius: inherit; } diff --git a/docs/identite/charte/guide-de-marque.md b/docs/identite/charte/guide-de-marque.md new file mode 100644 index 0000000..5b98500 --- /dev/null +++ b/docs/identite/charte/guide-de-marque.md @@ -0,0 +1,61 @@ +Ustagammon apprend le backgammon comme on l'apprend à une table de café : quelqu'un qui sait montre à quelqu'un qui découvre. L'interface est **chaleureuse, artisanale, claire et intemporelle**, discrètement turque par la matière (le bois, l'ivoire, la brique), jamais par le folklore. Elle doit donner envie à un débutant sans paraître naïve à un joueur confirmé : un maître bienveillant, pas un logiciel d'analyse, pas un casino. + +Ce système s'applique à la PWA (`web/`). Les noms des couleurs du plateau sont exactement ceux des variables de `web/app.css` ; `components/bundle.css` reprend ses noms de classes et peut y être recopié. + +## Contenus et ton + +- **Vouvoiement**, phrases courtes, verbes d'action. Le joueur est « vous », l'adversaire est « l'ordinateur » (ou le nom d'un joueur réel). +- **Les mots du jeu**, toujours les mêmes, ceux du glossaire (`docs/glossaire/`) : flèche, pion, barre, videau, compte de points, sortir. Un terme technique s'explique la première fois qu'il apparaît, avec un lien vers sa fiche. +- **Les boutons disent ce qu'ils font** : « Lancer les dés », « Annuler », « Doubler », « Prendre », « Passer », « Nouvelle partie ». Pas de « OK », pas de « Valider ». Les textes de l'app vivent dans `app/src/ui/texts.ts`. +- **Le maître encourage, il ne juge pas.** « Bien joué : ce coup protège votre point 8. » plutôt que « Coup correct (−0,012) ». Les chiffres d'équité ne viennent que sur demande. +- **Les erreurs disent quoi faire** : « Ce pion ne peut pas aller là : la flèche est tenue par deux pions adverses. » +- **Ni émoji, ni point d'exclamation en série, ni majuscules de réclame.** Les capitales sont réservées au style `overline`. +- Le nom s'écrit **Ustagammon**, en un mot, majuscule initiale. + +## Couleurs + +La palette, c'est le bois, les pions et le café, avec **un seul accent : le rouge brique** (`accent`). + +- Fond de page `background`, cartes et panneaux `surface`, zones en retrait `surface-sunken`. +- Texte `text` ; texte secondaire `muted`, jamais pour une consigne. +- `accent` est rare et a toujours un sens : le bouton principal de l'écran (un seul), un lien, le pion sélectionné (`highlight`), la case où il peut aller (`target`), le focus clavier (`focus`). Ce n'est jamais une couleur de décoration ni une couleur d'erreur. +- `accent-soft` : fond léger pour signaler « c'est à vous », avec du texte `text` dessus. +- Les appréciations de coups ont leurs propres couleurs, distinctes de la brique : `verdict-good` (vert), `verdict-doubtful` (ocre), `verdict-bad` (lie-de-vin). **Toujours avec le mot et l'icône**, jamais la couleur seule. +- `brand-laiton` (via `last-move`) marque le dernier coup joué, comme les charnières en laiton d'un plateau de tavla. Rien d'autre. +- Le plateau : cadre `frame` en noyer, fond `bed`, flèches alternées `point-a` (noyer clair) et `point-b` (chêne), barre `bar`, sorties `tray`. Le joueur a les pions ivoire (`checker-player`, l'apprenti), l'ordinateur les pions noyer (`checker-computer`, le maître), comme dans le logo. +- **À éviter** : le vert feutre de casino, le noir et or, les dégradés, les néons. + +Les deux thèmes, clair et sombre, sont complets. Tous les textes atteignent 4,5:1 sur leurs fonds dans les deux thèmes ; les contours et marques porteuses de sens, 3:1. + +## Typographie + +Une seule famille, **Alegreya Sans** (licence SIL OFL, fichiers dans `fonts/`), sans empattement humaniste, chaleureuse et lisible en petit. À embarquer dans l'app : elle doit fonctionner hors ligne. + +- `display` (32px, 800) : un seul par écran, accueil et fin de partie. +- `title` (24px) : titre d'écran ; `heading` (20px) : titre de section ou de carte. +- `body` (17px) : tout le texte à lire, jamais plus petit. `body-strong` pour la consigne du moment et les boutons. `body-italic` pour la parole du maître ou un exemple. +- `caption` (15px) : compte de points, légendes. `overline` (13px, capitales espacées) : étiquette au-dessus d'un titre, avec parcimonie. +- Chiffres alignés (`font-variant-numeric: tabular-nums`) dès que des nombres se comparent (compte de points, scores). + +## Formes, espace et profondeur + +- **Boutons ronds comme des pions** : `radius-pill`, hauteur `button-height` (48px). Aucune cible tactile sous 44px. +- Cartes et fiches : `radius-md`, contour `border`, ombre `shadow-raised` et rien de plus profond. Dés et videau : `radius-sm`. +- Espacements : `space-1` à `space-8`. Gouttière de page `space-4` sur téléphone ; écart entre blocs `space-6`. Contenu limité à `page-width` sur grand écran. +- Le plateau occupe toute la largeur sur téléphone ; c'est lui le héros de l'écran de jeu, pas les panneaux autour. +- Focus clavier : anneau `focus` plein de 3px, décalé de 2px, sur tous les éléments interactifs. + +## Mouvement + +Sobre et utile : un pion glisse vers sa flèche (150 à 250 ms, sans rebond), les dés roulent brièvement. Les trois points de « l'ordinateur réfléchit » sont la seule animation en boucle. Tout s'arrête avec `prefers-reduced-motion`. + +## Iconographie + +- Le **symbole** (deux pions sur une flèche, le 8 caché) et le **logotype** (les « mm » en flèches) sont dans le groupe Logos ; versions couleur, sombre, noire et blanche. Ne jamais les redessiner, déformer ou recolorer. +- Barre haute : `logo-horizontal-couleur.svg` en thème clair, `logo-horizontal-sombre.svg` en thème sombre, 32px de haut. +- Icônes d'interface : traits simples de 2px à bouts ronds, dessinés en SVG dans le code (pas de police d'icônes, pas d'émoji). Les seules icônes du système pour l'instant : les trois appréciations de coups (coche, point d'interrogation, croix) et la copie (deux feuillets). +- Dés, pions et videau sont dessinés en SVG avec les couleurs du plateau, jamais en images. + +## Composants + +Plateau (`Board`) et ses pièces (`Checker`, `Die`, `DoublingCube`), boutons (`Button`), barre haute (`TopBar`), zone de consigne (`GamePrompt`), appréciation d'un coup (`MoveVerdict`), fiche de glossaire (`GlossaryCard`), carte de leçon (`LessonCard`) et « Demander à une IA » (`AskAI`). Chacun a sa fiche avec ses règles d'usage et un aperçu dans les deux thèmes. diff --git a/docs/identite/charte/tokens.json b/docs/identite/charte/tokens.json new file mode 100644 index 0000000..611b4d5 --- /dev/null +++ b/docs/identite/charte/tokens.json @@ -0,0 +1,530 @@ +{ + "name": "Ustagammon", + "version": 1, + "color": { + "themes": [ + { + "id": "light", + "name": "Clair" + }, + { + "id": "dark", + "name": "Sombre" + } + ], + "tokens": [ + { + "name": "background", + "value": { + "light": "#F5EFE5", + "dark": "#17110D" + }, + "usage": "Fond de page (papier ivoire / café torréfié)." + }, + { + "name": "surface", + "value": { + "light": "#FFFCF6", + "dark": "#221913" + }, + "usage": "Fond des cartes, fiches de glossaire, panneaux posés sur `background`." + }, + { + "name": "surface-sunken", + "value": { + "light": "#ECE3D4", + "dark": "#2C211A" + }, + "usage": "Zones en retrait : bloc de prompt à copier, piste de progression." + }, + { + "name": "text", + "value": { + "light": "#2B1D15", + "dark": "#EFE5D5" + }, + "usage": "Texte courant et titres, sur `background`, `surface` et `surface-sunken`." + }, + { + "name": "muted", + "value": { + "light": "#6B5C50", + "dark": "#A99886" + }, + "usage": "Texte secondaire (compte de points, légendes, aide), sur `background` et `surface`." + }, + { + "name": "border", + "value": { + "light": "#DED2C0", + "dark": "#3A2D24" + }, + "usage": "Séparateurs et contours décoratifs de cartes (ne porte aucun sens)." + }, + { + "name": "border-strong", + "value": { + "light": "#8E7D6A", + "dark": "#7D6B5B" + }, + "usage": "Contour des boutons secondaires et des champs : 3:1 sur `background` et `surface`." + }, + { + "name": "accent", + "value": { + "light": "#A8432B", + "dark": "#D0694B" + }, + "usage": "Rouge brique, l'accent unique : bouton principal, liens, case où le pion peut aller, focus. Texte en brique sur `background` et `surface`." + }, + { + "name": "on-accent", + "value": { + "light": "#FFFFFF", + "dark": "#1A110C" + }, + "usage": "Texte et icônes posés sur un aplat `accent`." + }, + { + "name": "accent-soft", + "value": { + "light": "#F1D9CF", + "dark": "#4A2519" + }, + "usage": "Fond léger d'accent : puce « à toi de jouer », sélection dans une liste. Texte `text` dessus." + }, + { + "name": "focus", + "value": { + "light": "#A8432B", + "dark": "#E58A6E" + }, + "usage": "Anneau de focus clavier, 3 px plein, décalé de 2 px : 3:1 sur tous les fonds." + }, + { + "name": "error", + "value": { + "light": "#8C1C3A", + "dark": "#F08FA6" + }, + "usage": "Message d'erreur technique (texte), toujours accompagné d'un mot. Lie-de-vin, distinct de la brique." + }, + { + "name": "verdict-good", + "value": { + "light": "#2F6B4F", + "dark": "#7CCBA4" + }, + "usage": "« Bon coup » : texte et icône, toujours avec le mot. Sur `background` et `surface`." + }, + { + "name": "verdict-doubtful", + "value": { + "light": "#7E5A0F", + "dark": "#E0B04F" + }, + "usage": "« Imprécision » (doubtful) : texte et icône, toujours avec le mot." + }, + { + "name": "verdict-bad", + "value": { + "light": "#8C1C3A", + "dark": "#F08FA6" + }, + "usage": "« Erreur » et « grosse erreur » (bad, very bad) : texte et icône, toujours avec le mot." + }, + { + "name": "brand-noyer", + "value": { + "light": "#4A2E1F", + "dark": "#4A2E1F" + }, + "usage": "Noyer du logo : pion maître. Ne sert pas au texte de l'interface." + }, + { + "name": "brand-ivoire", + "value": { + "light": "#F3EAD8", + "dark": "#F3EAD8" + }, + "usage": "Ivoire du logo : pion apprenti, fond de l'icône d'application." + }, + { + "name": "brand-laiton", + "value": { + "light": "#8F6A1C", + "dark": "#D6A64A" + }, + "usage": "Laiton, comme les charnières d'un plateau de tavla : marque du dernier coup joué, rien d'autre." + }, + { + "name": "frame", + "value": { + "light": "#4A2E1F", + "dark": "#2A1A10" + }, + "usage": "Cadre du plateau (noyer)." + }, + { + "name": "bed", + "value": { + "light": "#E9DCC4", + "dark": "#4A3626" + }, + "usage": "Fond du plateau, entre les flèches." + }, + { + "name": "bar", + "value": { + "light": "#3F2619", + "dark": "#24170E" + }, + "usage": "Barre centrale." + }, + { + "name": "tray", + "value": { + "light": "#3A2418", + "dark": "#22150D" + }, + "usage": "Plateaux de sortie, à droite." + }, + { + "name": "point-a", + "value": { + "light": "#6B4430", + "dark": "#3A2519" + }, + "usage": "Flèches sombres (noyer clair), une sur deux." + }, + { + "name": "point-b", + "value": { + "light": "#C9AE88", + "dark": "#7E6142" + }, + "usage": "Flèches claires (chêne), une sur deux." + }, + { + "name": "point-number", + "value": { + "light": "#F3EAD8", + "dark": "#CDBFA8" + }, + "usage": "Numéros des flèches, posés sur `frame`." + }, + { + "name": "checker-player", + "value": { + "light": "#F7F0E2", + "dark": "#EDE3CF" + }, + "usage": "Pions du joueur : ivoire, l'apprenti." + }, + { + "name": "checker-player-edge", + "value": { + "light": "#8C7A62", + "dark": "#8E7C64" + }, + "usage": "Contour et filet des pions du joueur." + }, + { + "name": "checker-computer", + "value": { + "light": "#2E1C12", + "dark": "#140D09" + }, + "usage": "Pions de l'ordinateur : noyer sombre, le maître." + }, + { + "name": "checker-computer-edge", + "value": { + "light": "#120A05", + "dark": "#A8957D" + }, + "usage": "Contour et filet des pions de l'ordinateur ; clair en thème sombre pour rester visible." + }, + { + "name": "count-player", + "value": { + "light": "#2B1D15", + "dark": "#2B1D15" + }, + "usage": "Nombre écrit sur une pile de pions du joueur." + }, + { + "name": "count-computer", + "value": { + "light": "#F3EAD8", + "dark": "#F3EAD8" + }, + "usage": "Nombre écrit sur une pile de pions de l'ordinateur." + }, + { + "name": "die-player", + "value": { + "light": "#F7F0E2", + "dark": "#EDE3CF" + }, + "usage": "Dés du joueur." + }, + { + "name": "pip-player", + "value": { + "light": "#2B1D15", + "dark": "#2B1D15" + }, + "usage": "Points des dés du joueur." + }, + { + "name": "die-computer", + "value": { + "light": "#2E1C12", + "dark": "#140D09" + }, + "usage": "Dés de l'ordinateur." + }, + { + "name": "pip-computer", + "value": { + "light": "#F3EAD8", + "dark": "#EDE3CF" + }, + "usage": "Points des dés de l'ordinateur." + }, + { + "name": "cube", + "value": { + "light": "#F7F0E2", + "dark": "#EDE3CF" + }, + "usage": "Face du videau." + }, + { + "name": "cube-text", + "value": { + "light": "#2B1D15", + "dark": "#2B1D15" + }, + "usage": "Valeur du videau (2, 4, 8…)." + }, + { + "name": "highlight", + "value": { + "light": "#A8432B", + "dark": "#E07A5A" + }, + "usage": "Contour d'un pion jouable ou sélectionné du joueur : la brique. Il contraste à 3:1 au moins avec le pion ivoire (clair) ou avec le fond du plateau (sombre)." + }, + { + "name": "target", + "value": { + "light": "rgba(168,67,43,0.32)", + "dark": "rgba(224,122,90,0.38)" + }, + "usage": "Voile sur la flèche où le pion sélectionné peut aller." + }, + { + "name": "last-move", + "value": { + "light": "{brand-laiton}", + "dark": "{brand-laiton}" + }, + "usage": "Marque du dernier coup joué (laiton)." + } + ] + }, + "type": { + "fonts": [ + { + "family": "Alegreya Sans", + "file": "fonts/AlegreyaSans-Regular.ttf", + "weight": "400" + }, + { + "family": "Alegreya Sans", + "file": "fonts/AlegreyaSans-Italic.ttf", + "weight": "400", + "style": "italic" + }, + { + "family": "Alegreya Sans", + "file": "fonts/AlegreyaSans-Medium.ttf", + "weight": "500" + }, + { + "family": "Alegreya Sans", + "file": "fonts/AlegreyaSans-Bold.ttf", + "weight": "700" + }, + { + "family": "Alegreya Sans", + "file": "fonts/AlegreyaSans-ExtraBold.ttf", + "weight": "800" + } + ], + "families": { + "sans": "\"Alegreya Sans\", \"Gill Sans\", \"Segoe UI\", system-ui, sans-serif" + }, + "groups": [ + { + "name": "Titres", + "family": "sans", + "styles": [ + { + "name": "display", + "fontSize": "32px", + "lineHeight": "36px", + "fontWeight": 800, + "letterSpacing": "-0.01em", + "sample": "Une partie contre le maître", + "usage": "Titre d'accueil et de fin de partie, une fois par écran." + }, + { + "name": "title", + "fontSize": "24px", + "lineHeight": "30px", + "fontWeight": 700, + "sample": "Le point 8", + "usage": "Titre d'écran (leçon, aide)." + }, + { + "name": "heading", + "fontSize": "20px", + "lineHeight": "26px", + "fontWeight": 700, + "sample": "Les ouvertures", + "usage": "Sous-titre de section, titre de carte." + } + ] + }, + { + "name": "Texte", + "family": "sans", + "styles": [ + { + "name": "body", + "fontSize": "17px", + "lineHeight": "25px", + "fontWeight": 400, + "sample": "Ce pion peut rejoindre votre point 8.", + "usage": "Texte courant ; jamais en dessous de 17px pour le contenu à lire." + }, + { + "name": "body-strong", + "fontSize": "17px", + "lineHeight": "25px", + "fontWeight": 700, + "sample": "À vous de jouer : 6 et 1.", + "usage": "Consigne du moment (zone prompt), boutons." + }, + { + "name": "body-italic", + "fontSize": "17px", + "lineHeight": "25px", + "fontWeight": 400, + "fontStyle": "italic", + "sample": "Philippe aurait joué 13/7 8/7.", + "usage": "Parole du maître, citation, exemple." + }, + { + "name": "caption", + "fontSize": "15px", + "lineHeight": "20px", + "fontWeight": 400, + "sample": "Vous : 167 · Ordinateur : 152", + "usage": "Compte de points, légendes, mentions." + }, + { + "name": "overline", + "fontSize": "13px", + "lineHeight": "16px", + "fontWeight": 700, + "letterSpacing": "0.08em", + "sample": "LEÇON 3 SUR 12", + "usage": "Étiquette en capitales au-dessus d'un titre ; avec parcimonie." + } + ] + } + ] + }, + "spacing": { + "tokens": [ + { + "name": "space-1", + "value": "4px", + "usage": "Écart entre une icône et son texte." + }, + { + "name": "space-2", + "value": "8px", + "usage": "Écart entre boutons voisins, marges internes serrées." + }, + { + "name": "space-3", + "value": "12px", + "usage": "Marge interne des puces et du bloc prompt." + }, + { + "name": "space-4", + "value": "16px", + "usage": "Gouttière latérale de page sur téléphone, marge interne des cartes." + }, + { + "name": "space-6", + "value": "24px", + "usage": "Écart entre blocs d'un écran." + }, + { + "name": "space-8", + "value": "32px", + "usage": "Écart entre sections." + }, + { + "name": "button-height", + "value": "48px", + "usage": "Hauteur des boutons ; aucune cible tactile sous 44px." + }, + { + "name": "page-width", + "value": "40rem", + "usage": "Largeur maximale du contenu sur grand écran." + } + ] + }, + "radius": { + "tokens": [ + { + "name": "radius-sm", + "value": "6px", + "usage": "Dés, videau, puces de verdict." + }, + { + "name": "radius-md", + "value": "12px", + "usage": "Cartes, fiches, bloc prompt." + }, + { + "name": "radius-pill", + "value": "999px", + "usage": "Boutons : ronds comme des pions." + } + ] + }, + "shadow": { + "tokens": [ + { + "name": "shadow-raised", + "value": { + "light": "0 1px 2px rgba(43,29,21,0.10)", + "dark": "0 1px 2px rgba(0,0,0,0.40)" + }, + "usage": "Seule ombre permise : cartes posées sur le fond. Rien de plus profond." + } + ] + }, + "meta": { + "source": "Brief créatif + ADR 0010 + web/app.css (noms des variables du plateau)" + } +} diff --git a/docs/journal.md b/docs/journal.md index 0828303..d321746 100644 --- a/docs/journal.md +++ b/docs/journal.md @@ -89,3 +89,24 @@ Une entrée datée par session : ce qui a été fait, décidé, et la suite. - Sous Firefox sur PC, un tour de l'ordinateur a pris jusqu'à 5,1 s (Chromium : 0,4 s) ; Firefox sur le téléphone reste à mesurer. - Validation par Pierre de Playwright (Apache-2.0), outil de `make test-browser`. + +## 2026-11-03 (nuit) : identité visuelle + +**Fait** +- Identité choisie par Pierre en trois tours sur une planche de travail : + accent brique, symbole « P3d » (deux pions sur une flèche, le 8 caché), + logotype « L3 » (les « mm » en flèches), icône sur fond ivoire. ADR 0010, + fichiers du logo et des icônes dans `docs/identite/logo/` (MR !12). +- Design system publié (https://claude.ai/artifact/K2Z7MPE58XXJzv19n5r11M) : + couleurs des deux thèmes reprenant les noms de variables de `web/app.css`, + Alegreya Sans, onze composants, contrastes vérifiés par calcul. Copie dans + `docs/identite/charte/`. +- Maquettes des quatre écrans et du thème sombre + (https://claude.ai/artifact/CQw6vbDpi6XQqVWQa4sANe). + +**Reste à faire** +- Appliquer la charte à la PWA (couleurs, police embarquée, icônes, logo) : + à planifier pour l'agent développeur, voir `docs/identite/charte/README.md`. +- Les maquettes proposent des éléments de produit qui ne sont pas encore + décidés (leçons, « Conseil du maître », bilan de fin de partie) : à valider + par Pierre avant toute mise en œuvre. -- 2.54.0