---
name: design-generate
description: >
  Génère un prototype HTML fidèle au design system d'un front pysae (React+Tailwind : shift, moby/client_react),
  à partir des critères d'acceptation d'un ticket : feature entière (écrans + états) en vraies classes-tokens,
  vérifiée par l'oracle déterministe `design check` et la couverture `design coverage`, prête pour la revue PM
  et le handoff dev. Réservé aux features COMMODITY (problème + solution connus, zéro composant neuf).
  Use when the user says /design-generate, /design, 'prototype cette feature', 'génère les maquettes',
  'génère un proto', 'proto design', 'fais une maquette HTML', 'prototype ce ticket', 'maquette cette feature',
  'design generate', 'prototype this feature', 'generate the mockups', 'build an HTML prototype',
  'make a UI proto', 'prototype this ticket', or wants a faithful HTML prototype of a commodity UI feature
  before development. Distinct from /design-autopilot-batch, which runs this skill unattended over many
  tickets at once — /design-generate prototypes a single ticket interactively.
---

# Design Generate — prototype HTML fidèle au design system

Génère un prototype de feature en **HTML à vraies classes-tokens**, vérifié par l'oracle déterministe, prêt pour la revue PM et le handoff dev.

**Scope** : fronts React+Tailwind (shift, moby/client_react). Features **commodity** uniquement.

## Required tools

- `glab`
- `chrome-mcp`
- `node`

Run `pysae-ai-tools tools require glab chrome-mcp node` before starting; if it exits non-zero, abort and report the install command from stderr to the user.

## Project configuration

Honour `.pysae-ai-tools.yaml` (this repo's `CLAUDE.md` is NOT in your context at runtime). Check flags with `pysae-ai-tools project flag <path>` (exit 0 = on, 1 = off — no `jq`):

- `design.enabled` — when `pysae-ai-tools project flag design.enabled` exits non-zero, the repo is **not eligible** for design-generate: stop cleanly.
- `design.pages_proto` — when off, don't attempt the GitLab Pages proto deploy; fall back to the local http preview.
- `design.web_root` — non-boolean: read with `pysae-ai-tools project show --json` ; when set, use it as the front's web dir (`design kit --root`, Tailwind CLI cwd) instead of guessing.

## Principes

- **Contrat durable vs proto jetable.** Le contrat = `design.md` (régénéré, jamais stale) + les **critères d'acceptation du ticket**. Il survit à tout. Le proto HTML est **jetable** : régénéré à la demande, jamais une source à conserver. Pour ré-itérer un écran déjà livré, **régénérer depuis le code React actuel**, ne pas ressusciter un vieux HTML.
- **Stockage versionné, pas baladeur.** Le proto vit sur une **branche `design/<iid>`** du repo front (`<iid>` = IID du ticket), dans `design-protos/<iid>/`, rendu en **URL GitLab Pages** liée au ticket. Jamais un fichier qu'on se passe sur Slack. La même URL sert la **revue PM** et le **user-test**.
- **Gate d'éligibilité (bloquant).** Si l'écran introduit un composant neuf ou une interaction custom (drag-drop, livemap, timeline, canvas, animation, multi-step) → **stop** : ce n'est pas commodity, sortir du fast-path (discovery + designer/Figma). Ne jamais forcer le proto hors commodity.

## Procédure

1. **Constitution** — régénérer la constitution du projet (jamais stale) :
   `pysae-ai-tools design kit --root <front> --out design.md`
   C'est le vocabulaire autorisé : tokens (`@theme`) + catalogue `components/ui/`.

2. **Critères d'acceptation → FR** — le ticket est créé via `/glab-issue-create`, donc il porte déjà un template `## Spécifications` + `## Critères d'acceptation`. **Extraire ces critères** (ne pas les réinventer), les mapper en `FR-id → écran → état`, et **faire valider le mapping par le PM** (il valide, il ne réécrit pas). `speckit.clarify` optionnel si un critère est ambigu. Ce mapping est le contrat de couverture (étape 3).

3. **Map de couverture** — pour chaque FR, lister les écrans + états (loading / empty / error / edge **par défaut**). Écrire `design-protos/<iid>/coverage-map.md` qui référence chaque `FR-NNN`. C'est la base de `design coverage`.

4. **Générer** (feature entière, desktop **et** responsive) :
   - Utiliser le skill `frontend-design` s'il est disponible ; sinon appliquer ses principes de rendu inline.
   - **Fidélité composant (bloquant)** : ne PAS approximer le rendu. Avant d'écrire un écran, **lire les vrais composants** que la page réutilise (`components/ui/Button.tsx`, `TableWrapper.tsx`, `EntityModal.tsx`, le `Sidebar.tsx`/`AppShell.tsx` du shell, etc.) **et une vraie page de liste de référence** (ex: `pages/DriversPage.tsx`), puis **reproduire leur markup et leurs classes à l'identique** (copier les chaînes de classes, pas les réinventer). Le proto doit être indiscernable de l'app réelle, pas une maquette « inspirée de ».
   - Benchmarks optionnels : si l'utilisateur en fournit, « regarde-les attentivement, identifie les patterns à reprendre de chacun ; ce que TOI tu y vois compte plus que ce que je décrirais ».
   - **Interactivité & navigabilité (bloquant)** : le proto n'est PAS une capture figée. **Tous les écrans et états du coverage-map doivent être atteignables et l'UI cliquable** : les modales sont **cachées au chargement** (jamais d'overlay bloquant à l'ouverture), s'ouvrent/ferment via les vrais déclencheurs (bouton primaire, icônes d'action de ligne, backdrop, ×), et les états de liste (peuplé / vide / chargement / erreur) sont commutables. JS vanilla inline suffit ; vérifier qu'aucune modale n'a un `display` inline qui écrase la classe de masquage. La page d'entrée s'ouvre sur l'état nominal (liste peuplée), pas sur une modale.
   - **Contraintes dures** : uniquement les classes-tokens de `design.md` ; uniquement les composants `components/ui/` (tout nouveau composant = listé et justifié) ; data mock du **dataset démo** du projet ; zéro style inventé. Valeurs arbitraires Tailwind (`-[...]`) interdites **sauf** si elles référencent un token via `var(--…)` (ex: `text-[var(--color-brand)]` est conforme, `text-[10.5px]` non).
   - Produire `design-protos/<iid>/<écran>.html`. Soit un fichier par écran/état, soit **une page unique navigable** qui commute états + modales (privilégier ce format : un seul lien, tous les écrans).

5. **CSS auto-suffisant** — compiler les classes utilisées contre le `index.css` du front (proto rendu sans le dev-env de l'app). Tailwind 4 : lancer le CLI **depuis le dossier web du front** (là où `node_modules` résout `tailwindcss`), via un entry qui importe le thème et source le dossier proto :
   ```bash
   cd <front>   # ex: shift/app/packages/web
   printf '@import "./src/index.css";\n@source "<abs-protos-dir>";\n' > _proto_entry.css
   npx @tailwindcss/cli -i _proto_entry.css -o <abs-protos-dir>/proto.css
   rm -f _proto_entry.css
   ```
   puis lier `<link rel="stylesheet" href="proto.css">` dans chaque HTML. (Nécessite Node + le `tailwindcss` du front.)

6. **Boucle oracle** (max 5 itérations) — pour chaque écran :
   `pysae-ai-tools design check design-protos/<iid>/<écran>.html --root <front>`
   Corriger les findings par `#N`, relancer jusqu'à `verdict: CLEAN`. Les règles sont bloquantes ; sur un proto `.html`, R3 (primitive vs composant catalogue) est **auto-skippée** (réservée au `.tsx` du gate maquette→code), donc l'oracle vérifie R1/R2/R4 (couleur brute, valeur arbitraire, palette). Si non-convergence après 5 itérations → escalader à l'humain.

7. **Couverture** — `pysae-ai-tools design coverage design-protos/<iid>/spec.md design-protos/<iid>/coverage-map.md`. Combler les `gaps` (générer les écrans des FR manquants), reboucler.

8. **Boucle proto-review (gate fonctionnel + visuel)** — l'oracle et la couverture sont des regex sur le **source** : ils ne voient ni une modale figée au chargement, ni un écran injoignable. Charger le proto dans un navigateur (`chrome-mcp`, proto servi en local pour résoudre `proto.css`) et vérifier qu'il **marche** et qu'il **ressemble à l'app réelle**. Gate fonctionnel (déterministe) : aucun overlay bloquant au load (`display` calculé), chaque écran/état du `coverage-map` atteignable via son **vrai déclencheur**, zéro erreur JS console, aucun déclencheur mort. Gate visuel (vision, adversarial) : fidélité design system + composants catalogue + satisfaction des AC sur screenshots. Findings non vides → patcher (retour step 4) puis **rejouer** oracle (6) + couverture (7) + ce gate ; max 5 itérations, sinon escalader. Procédure détaillée : [`references/proto-review.md`](references/proto-review.md). **Ne pas publier tant que proto-review n'est pas vert.**

9. **Publier (branche `design/<iid>` + Pages)** — committer `design-protos/<iid>/` sur la branche **`design/<iid>`** du front et pousser. Le rendu Pages se déclenche **uniquement via la variable-garde** (le push seul ne crée pas de pipeline) : lancer un pipeline sur la branche avec `DESIGN_PROTO=<iid>` — `glab ci run --branch "design/<iid>" --variables "DESIGN_PROTO:<iid>"` — qui ne tourne **que** le job `pages` (déploiement Pages parallèle, `path_prefix=design-<iid>`). Récupérer l'URL du déploiement (environnement `design-preview/<iid>`) et **la poster en commentaire sur le ticket**. Front non câblé (`design-pages.yml` non inclus) → fallback `python -m http.server` local en signalant que le partage durable passe par Pages.

10. **Gate PM + user-test (même URL)** — partager l'**URL Pages** au PM **et** aux utilisateurs-test : un seul lien sert les deux. Préciser que c'est un **concept au stade design, pas le produit live** (visibilité / mot de passe selon confidentialité). Les changements repassent par 4-9 (régénérer est gratuit, re-push met l'URL à jour, le proto est jetable). Sur validation, poser le **label GitLab** de validation design sur l'issue.

11. **Handoff dev** — préparer une PR React traduisant le proto HTML (class→className, `<button>`→`<Button>` du catalogue `ui/`). Passer à `/code-implement` avec **la branche proto + `design.md` + les AC** en contexte. Le dev affine + backend. `design check` est **rejoué sur le React livré** (gate maquette→code). Une fois le React mergé, la **branche `design/<iid>` est retirée** (proto consommé) ; le contrat (`design.md` + AC du ticket) reste.

## Métrique
Logger les changements d'avis du PM APRÈS le rendu (north star : ce nombre doit chuter).

## Mode auto / CI (`--auto` ou `$CI`)

Mode non-interactif, consommé par `design-autopilot-batch` (`pysae-ai-tools agent design-run`) :

- **Aucune `AskUserQuestion`** : pas de validation interactive du mapping FR→écran (on fait confiance aux AC du ticket). Le gate PM n'est pas attendu inline : il se fait **après**, sur le label `design::review` (posé par l'autopilot avec l'URL Pages).
- **Re-check d'éligibilité défensif** : si, après lecture, l'écran n'est manifestement pas commodity (composant neuf, interaction custom), **escalader** au lieu de générer.
- Dérouler les étapes 1-9 (kit → AC → proto → boucle oracle → boucle proto-review → push branche `design/<iid>` → pipeline `$DESIGN_PROTO` → URL Pages). En cas de non-convergence de l'oracle ou de proto-review (>5), de `chrome-mcp` indisponible, ou de tout blocage, escalader.
- **Émettre en dernière ligne le footer** (parsé par l'autopilot) :
  ```
  <<<DESIGN_RESULT
  {"status": "success", "preview_url": "<url Pages>", "branch": "design/<iid>"}
  DESIGN_RESULT>>>
  ```
  ou, si bloqué :
  ```
  <<<DESIGN_RESULT
  {"status": "escalated", "reason": "<cause courte>"}
  DESIGN_RESULT>>>
  ```
