# Blueprint Factory : handoff pour agent IA

> **À lire en premier.** Ce document résume tout le contexte du projet *Blueprint Factory* (Kage Games) pour un agent qui arrive sur le projet.
> Point d'entrée public : <https://kg.g.caute.re/factory/>. Cette page **contient ce document en entier**, rendu en HTML statique : aucun JavaScript n'est nécessaire pour le lire. Versions alternatives : [`handoff.md`](handoff.md) (ce texte en Markdown brut), [`llms.txt`](llms.txt) (index court) et [`context.json`](context.json) (inventaire lisible par machine).
>
> - **État figé au :** 10 novembre 2026, vers 23 h (heure de Paris), au commit `2700872`. Le handoff a été ajouté en `8b7432b`, puis rendu dans l'accueil.
> - **Langue du projet :** français, pour l'UI, les docs, les commits et les échanges avec le propriétaire.
> - **Convention de ce document :** chaque fait vient du dépôt, des docs ou de l'historique des demandes. Ce qui n'est pas vérifié est marqué **[à confirmer]**.

---

## Sommaire

1. [En bref](#1-en-bref)
2. [Règles dures, à ne jamais enfreindre](#2-règles-dures-à-ne-jamais-enfreindre)
3. [But et vision](#3-but-et-vision)
4. [Index des livrables en ligne](#4-index-des-livrables-en-ligne)
5. [Chronologie (commits)](#5-chronologie-commits)
6. [Glossaire](#6-glossaire)
7. [Architecture du dépôt](#7-architecture-du-dépôt)
8. [Principes de conception transverses](#8-principes-de-conception-transverses)
9. [V1 : bâtiments de colonie (spec → SVG → 3D)](#9-v1--bâtiments-de-colonie-spec--svg--3d)
10. [Kit KX : cargo spatial modulaire](#10-kit-kx--cargo-spatial-modulaire)
11. [Configurateur et galerie de variantes KX](#11-configurateur-et-galerie-de-variantes-kx)
12. [Chaîne factory en 9 étapes](#12-chaîne-factory-en-9-étapes)
13. [Kit OX : avant-poste minier sur astéroïde](#13-kit-ox--avant-poste-minier-sur-astéroïde)
14. [Kit GX : grille voxel pour pixel art](#14-kit-gx--grille-voxel-pour-pixel-art)
15. [Référentiel IA](#15-référentiel-ia)
16. [Formats de fichiers et schémas](#16-formats-de-fichiers-et-schémas)
17. [Commandes : build, lint, tests, export](#17-commandes--build-lint-tests-export)
18. [Palette : jamais de vert](#18-palette--jamais-de-vert)
19. [Budgets triangles et poids web](#19-budgets-triangles-et-poids-web)
20. [Données gameplay](#20-données-gameplay)
21. [Problèmes connus](#21-problèmes-connus)
22. [Journal des décisions](#22-journal-des-décisions)
23. [Questions ouvertes et prochaines étapes](#23-questions-ouvertes-et-prochaines-étapes)
24. [Conventions de travail pour un agent](#24-conventions-de-travail-pour-un-agent)
25. [Contexte : Deep City](#25-contexte--deep-city)
26. [Données publiques lisibles par machine](#26-données-publiques-lisibles-par-machine)
27. [Ce qui n'a pas pu être confirmé](#27-ce-qui-na-pas-pu-être-confirmé)

---

## 1. En bref

- **Quoi :** une « usine à assets » pour jeux. On part d'une **spec JSON paramétrique**, on en tire des **plans techniques SVG cotés** (plusieurs vues), puis de la **3D Blender** en trois versions (filaire, plein, texturé). Le tout est exporté en GLB (avec Draco pour le web) et vérifié jusqu'à l'import dans Godot 4.7.2.
- **Pourquoi :** les assets 3D générés directement, ceux du kit colonie, étaient « imprécis ». Le plan sert de référence à la 3D, et ce sont les **mêmes sommets** qui produisent le SVG et le maillage. Les cotes du plan sont donc celles du GLB par construction.
- **Kits livrés :**
  - **KX** : cargo spatial, avec 14 composants, 5 modules, 3 coques à slots vides et 4 assemblages.
  - **OX** : avant-poste minier sur astéroïde, dérivé de KX. Il a 12 composants propres plus 10 hérités de KX, 7 bâtiments, 3 parcelles et 3 assemblages.
  - **GX** : KX quantifié sur une grille voxel pour le pixel art, avec 15 composants, 5 modules, 3 coques et 4 assemblages.
- **Outils web :** une visionneuse 3D par kit, un configurateur KX (glisser-déposer, validation en direct), une galerie de variantes générées par seed, et une page qui illustre la chaîne de production en 9 étapes sur l'assemblage AX-02.
- **Qualité :** un lint par kit (KX 119/119, OX 150/150, GX 107/107), un QA de chaîne, des tests Playwright headless pour chaque page et un contrôle d'import Godot.
- **Règle visuelle absolue :** **aucun vert**, nulle part : art, UI, SVG et matériaux. Les lints le vérifient.
- **Déploiement :** par **overlays** tar.gz (préfixe `launcher/`), qui ne font qu'ajouter ou remplacer des fichiers. Ils sont appliqués par un **opérateur d'infrastructure**, jamais par l'agent de développement.
- **Phase :** exploratoire. Le propriétaire explore le principe « factory / composant ». Les pistes OX et GX sont des explorations, pas des choix figés.

## 2. Règles dures, à ne jamais enfreindre

1. **Pas de vert** dans les chartes graphiques, les UI, les SVG ou les matériaux. Est interdite toute teinte entre 70° et 170° avec une saturation ≥ 0,25 et une valeur ≥ 0,15. Voir [§18](#18-palette--jamais-de-vert).
2. **Aucun secret** dans le chat, les logs, git ou les pages publiques : clés, jetons, mots de passe, adresses internes.
3. **Ne jamais déployer soi-même.** On prépare un overlay, on le documente (taille, sha256, liste des fichiers) et un opérateur le fusionne.
4. **Overlays uniquement** : des fichiers ajoutés ou remplacés un par un.
   - Ne **jamais** lancer le `build-site.sh` complet du lanceur : il échoue, car des builds de POC ne sont plus présents.
   - Ne **jamais** remplacer le `Caddyfile`.
   - Ne **jamais** livrer un `factory/` entier qui écraserait les sous-pages (voir [§21](#21-problèmes-connus) sur `add-factory.sh`).
5. **Ne jamais toucher** au DNS, à l'edge (proxy), au VPN ni aux ACL réseau.
6. **Ne pas câbler `jobs.json`** (file de jobs d'un autre outil, hors périmètre).
7. **Unreal Engine est exclu** (décision du propriétaire : « oublie Unreal Engine »). Le moteur cible des exports est **Godot 4.7.2**.
8. Les étapes **Steamworks** restent entre les mains du propriétaire. N'en engage aucune.
9. **Documenter la chaîne** : chaque étape doit avoir un script, un artefact et une trace (README, planche, capture).
10. **Vérifier chaque affirmation** avant de la reporter : un lint, un test ou un `curl` doit le confirmer. Une page en ligne n'est « en ligne » qu'une fois qu'elle a répondu 200.

## 3. But et vision

- **Demande d'origine (9 nov. 2026) :** les assets 3D du kit colonie étaient imprécis. Plutôt que générer directement une image ou un mesh, il fallait d'abord produire des **plans 2D SVG multi-vues** (dessus, face, profil, iso) qui servent de **référence** à la 3D. La 3D est ensuite déclinée en **filaire, plein et texturé**. Consigne : « Tente une V1 et on ajustera. »
- **Vision qui s'en est dégagée :** un système de **familles d'objets cohérentes par construction**. Une charte mesurée (grille, rivets, biseaux, bordé, interface d'accroche, palette) est imposée à des composants paramétriques. Ces composants forment des modules, les modules se posent dans des slots vides de coques ou de parcelles, et les assemblages ne sont que des données. Un lint garantit la ressemblance.
- **Pistes explorées ensuite à la demande du propriétaire :**
  - la même méthode pour les **bâtiments d'un avant-poste minier sur astéroïde** (OX) ;
  - une géométrie **volontairement sur grille** pour un rendu pixel art ultérieur (GX) ;
  - des idées de décomposition et d'étapes pour la factory, dont sont sortis le configurateur, la galerie de variantes et la chaîne en 9 étapes.
- **Utilisateurs visés :** les jeux du studio, Godot en priorité (export `.tscn` avec collisions et ancres), et des agents IA, puisque les specs sont lisibles, diffables et éditables par une IA.
- **Contrainte d'hébergement :** les pages tournent sur un petit serveur (2 vCPU, sans GPU) et dans le navigateur du visiteur. D'où la compression Draco, les textures JPEG, le filaire calculé côté client et l'occlusion des SVG.

## 4. Index des livrables en ligne

Base : `https://kg.g.caute.re`. Le lanceur général du studio est à la racine `/`.

### Factory

| URL | Contenu | Source dans le dépôt |
|---|---|---|
| [/factory/](https://kg.g.caute.re/factory/) | Accueil pour une IA et pour un humain. On y trouve d'abord ce handoff complet, en HTML statique, puis la visionneuse V1 en bas de page : 3 bâtiments (habitat S, QG, aire d'atterrissage) en filaire, plein ou texturé, avec le plan SVG à côté | `viewer/index.html` (généré depuis `src/handoff/home.template.html` + `viewer/handoff.md`), `viewer.js`, `viewer.css` |
| [/factory/handoff.md](https://kg.g.caute.re/factory/handoff.md) | Ce document | `viewer/handoff.md` |
| [/factory/llms.txt](https://kg.g.caute.re/factory/llms.txt) | Index court pour LLM | `viewer/llms.txt` |
| [/factory/context.json](https://kg.g.caute.re/factory/context.json) | Inventaire lisible par machine | `viewer/context.json` (généré) |
| [/factory/referential/](https://kg.g.caute.re/factory/referential/) | Référentiel IA : 6 rendus IA (depuis le plan et depuis la 3D) comparés à leurs sources | `viewer/referential/` |
| [/factory/kit/](https://kg.g.caute.re/factory/kit/) | Kit KX en 4 niveaux : composants, modules, coques, assemblages | `viewer/kit/` |
| [/factory/kit/configurator/](https://kg.g.caute.re/factory/kit/configurator/) | Configurateur KX : une coque plus des modules, validation en direct, budgets, export AX | `viewer/kit/configurator/` |
| [/factory/kit/variants/](https://kg.g.caute.re/factory/kit/variants/) | Galerie de 20 variantes KX par seed | `viewer/kit/variants/` |
| [/factory/chain/](https://kg.g.caute.re/factory/chain/) | Chaîne en 9 étapes appliquée à AX-02, avec ses artefacts téléchargeables | `viewer/chain/`, assemblée par `src/chain/chain_site.py` |
| [/factory/outpost/](https://kg.g.caute.re/factory/outpost/) | Kit OX en 4 niveaux : composants, bâtiments, parcelles, assemblages | `viewer/outpost/` |
| [/factory/grid/](https://kg.g.caute.re/factory/grid/) | Kit GX en 5 onglets (les 4 niveaux plus « Méthodes ») : voxels 3D et sprites pixel art | `viewer/grid/` |

**Liens profonds utiles :**

- Accueil : `/factory/#<id>/<mode>`, par exemple `#command_hq/tex`. Les ids sont `habitat_s`, `command_hq` et `landing_pad` ; les modes `wire`, `solid` et `tex`.
- Kit KX : `/factory/kit/#<niveau>/<id>/<mode>`. Les niveaux sont `components`, `modules`, `hulls` et `assemblies`. Exemple : `#assemblies/asm_mixte/tex`.
- Kit OX : `/factory/outpost/#<niveau>/<id>/<mode>`. Les niveaux sont `components`, `buildings`, `plots` et `assemblies`.
- Kit GX : `/factory/grid/#<niveau>/<id>` ou `#methods`.
- Configurateur : état complet dans le hash, par exemple `#h=l&f=S1-bio,S2-cry,S4a-liq,S4b-liq-r&sn=L7KX-204&w=1&st=orange`.
  - `h` est la coque (s, m ou l) et `f` la liste des slots sous la forme `slot-module[-r]` ;
  - `sn` est l'immatriculation, `w` l'usure de 0 à 3 et `st` la bande de flotte.
- Galerie : `?base=1&n=20` ; `?sheet&mode=tex` donne la planche statique.

### Contexte jeu (Deep City)

Ces pages servent de contexte seulement : elles ne font pas partie de la factory. Voir [§25](#25-contexte--deep-city).

| URL | Version |
|---|---|
| [/play/deep-city/](https://kg.g.caute.re/play/deep-city/) | Deep City v0.1 (MVP, Godot 4.7.2), commit `60d370a` |
| [/play/deep-city-v2/](https://kg.g.caute.re/play/deep-city-v2/) | Deep City v0.2 « 3 étages » (Godot), commit `244c82e` |
| [/play/deep-city-v3/](https://kg.g.caute.re/play/deep-city-v3/) | Deep Colony : Kepler-Ombre v0.3, reskin sur planète alien (Godot), commit `6eb99f4` |
| [/play/deep-city-love2d/](https://kg.g.caute.re/play/deep-city-love2d/), [/play/deep-city-raylib/](https://kg.g.caute.re/play/deep-city-raylib/), [/play/deep-city-phaser/](https://kg.g.caute.re/play/deep-city-phaser/), [/play/deep-city-vanilla/](https://kg.g.caute.re/play/deep-city-vanilla/) | Portages du MVP vers d'autres moteurs |

## 5. Chronologie (commits)

Dépôt git `blueprint-factory` (local, **sans remote**). Les heures sont celles de Paris.

| Date | Commit | Jalon |
|---|---|---|
| 09/11 21:37 | `87098a6` | **V1** : spec JSON → plans SVG cotés + Blender filaire/plein/texturé pour `habitat_s`, `command_hq` et `landing_pad`, avec contrôle d'import Godot |
| 09/11 21:54 | `75fc04d` | Visionneuse 3D web (three.js) et textures cuites `<id>_tex.glb`. `build.sh` gère la cuisson et les assets de la visionneuse |
| 10/11 10:21 | `85673ea` | **Kit KX** : charte mesurée, 14 composants, 5 modules, 3 coques à slots vides, 4 assemblages, lint (110 contrôles à l'époque), visionneuse `/factory/kit/` (Draco), référentiel IA |
| 10/11 11:06 | `0da1d14` | Kit KX : 10 rendus PNG (Cycles « hangar » et versions cinématiques), plus une planche contact |
| 10/11 17:10 | `51bbbde` | Chaîne en 9 étapes illustrée sur AX-02 : blockout, usure par seed, bake AO, QA, export `.tscn` Godot, planche et vignettes |
| 10/11 17:21 | `8c6bb9c` | Chaîne **9/9 réelle** : brief → spec déterministe, carte ID cuite, fiche gameplay calculée, plafonds de triangles, page `/factory/chain/` |
| 10/11 17:22 | `1278dc3` | **Kit GX** : grille voxel (g = U/2), 15 composants, 5 modules, 3 coques, 4 assemblages. Comparaison des méthodes A, B, B′ et C, sprites 4 et 8 directions, lint 107/107 |
| 10/11 17:34 | `477f208` | **Configurateur KX** et **galerie de variantes** par seed. Ajout de `stats.json` ; lint 119/119, test 28/28 |
| 10/11 17:36 | `94009ef` | **Kit OX** : avant-poste sur astéroïde, avec 12 composants OX + 10 KX, 7 bâtiments, 3 parcelles, 3 assemblages ; lint 150/150 |
| 10/11 22:14 | `2700872` | **Correctif mémoire Draco** : un seul `DRACOLoader` partagé, et le contexte WebGL est libéré avant de quitter la page (voir [§21](#21-problèmes-connus)) |
| 10/11 23:29 | `8b7432b` | Accueil factory transformé en handoff : `handoff.md`, `llms.txt`, `context.json` |
| 10/11 ~23 h 50 | *(commit suivant)* | Accueil v2 : ce handoff rendu en entier en HTML statique dans `/factory/`, avec le préambule « Pour un agent IA » et la visionneuse sous le contexte |

**Publication :**

- Toutes ces étapes ont été mises en ligne par overlays successifs le 10/11 : kit, référentiel, configurateur, chaîne, avant-poste, grille, nav, puis le correctif Draco.
- L'opérateur a vérifié chaque sha256 et testé chaque page publique (HTTP 200).

## 6. Glossaire

| Terme | Définition |
|---|---|
| **Factory / Blueprint factory** | La chaîne spec → plan SVG → 3D → export, et par extension le projet |
| **Spec** | Fichier JSON paramétrique : la **source de vérité**. Le SVG et le GLB en sont des sorties |
| **Planche** | Plan technique A3 en SVG (unités en mm sur la feuille, cotes en m), avec calques, cotes, nomenclature et cartouche |
| **KX** | Kit de style cargo spatial. Préfixe des modules (`KX-LIQ`…) et de l'interface **KX-4** |
| **HX** | Coque KX (*hull*) : `HX-S` caboteur, `HX-M` cargo moyen, `HX-L` long-courrier |
| **AX** | Assemblage KX : `AX-01` à `AX-04`. C'est une coque plus des modules, décrite en données |
| **OX** | Kit avant-poste minier sur astéroïde, dérivé de KX. Bâtiments `OX-HAB`, `OX-DRL`… |
| **PX** | Parcelle d'astéroïde OX à slots vides : `PX-S`, `PX-M`, `PX-L` |
| **OA** | Assemblage OX : `OA-01` à `OA-03`. C'est une parcelle, des bâtiments et des tubes de liaison |
| **F1 / F2** | Emprises OX : F1 = 4,00 × 4,00 m ; F2 = 10,00 × 4,00 m (= 2 × F1 + un couloir de 2,00) |
| **OX-4** | Socle commun des bâtiments OX : ancrages ANC, vérins LEG, plancher à +0,70, ombilicale UMB au centre |
| **GX** | Kit KX quantifié sur grille voxel, pour le pixel art. Coques `GH-S/M/L`, assemblages `GA-01` à `GA-04`, interface **GX-4** |
| **G8 / G4** | Résolutions GX : G8 = 1 voxel pour 0,125 m (8 vox/m), le modèle de référence ; G4 = 1 voxel pour 0,25 m (= U), un LOD dérivé par sous-échantillonnage 2×2×2 qui n'est jamais modélisé |
| **U / u** | Grille KX : **U = 0,25 m** ; u = U/5 = 0,05 m. Toute cote structurelle est un multiple de u |
| **g** | Pas voxel GX : **1 voxel = g = U/2 = 0,125 m** |
| **Slot** | Emplacement vide d'une coque (C1/C2) ou d'une parcelle (F1/F2). Seules les interfaces y sont dessinées, jamais le module |
| **C1 / C2** | Classes de slot KX. C1 = 3,00 × 2,00 × 2,00 m (12U × 8U × 8U). C2 = 6,25 × 2,00 × 2,00 m = 2 × C1 + une nervure de 0,25. Un C2 accepte 1 × C2, ou 2 × C1 dans les sous-slots `a`/`b` à ±1,625 |
| **Interface KX-4** | Accroche commune : 8 coins **KXC** (cubes de 0,20, jaune `#f2b705`), 4 verrous **KXL** au plancher, 4 bras **KXB** en tête, 1 ombilicale **UMB** (2 sur un C2) |
| **Composant** | Pièce paramétrique d'identité, réutilisée en micro (modules) ou en macro (coques) : RVT, BVL, PNL, RIB, KXC, KXL, KXB, UMB, IFP, VNT, RNG, BCN, PIP, DOR |
| **Module** | Conteneur cargo KX qui se pose dans un slot : LIQ (citerne), BOX (fret sec), ORE (minerai), CRY (cryogénie), BIO (vivarium, en C2) |
| **Denrée / code denrée** | Type de cargaison avec sa couleur : LIQ, BOX, ORE, CRYO, BIO |
| **Famille (OX)** | Fonction d'un bâtiment, qui fixe sa couleur : VIE, EXT, TRT, NRJ, COM. Elle reprend les 5 teintes de denrée KX |
| **Micro / macro** | Classes d'échelle : rivets Ø0,03 au pas 0,15 (micro) ou Ø0,06 au pas 0,30 (macro), biseaux XXS à S ou M à XL |
| **Habillage / livery** | Immatriculation, bande de flotte et usure de 0 à 3, sans toucher à la géométrie |
| **Seed** | Graine du générateur déterministe (mulberry32) des variantes, ou de l'usure dans la chaîne (4471 pour AX-02) |
| **Lint** | Contrôles automatiques de conformité à la charte : `tools/kit_lint.py`, `ox_lint.py`, `grid_lint.py` |
| **Overlay** | Archive tar.gz de fichiers à poser par-dessus le site déployé (préfixe `launcher/site/...`) |
| **Méthode A / B / B′ / C** | Méthodes de rendu pixel art comparées dans GX (voir [§14](#14-kit-gx--grille-voxel-pour-pixel-art)) |

## 7. Architecture du dépôt

```text
blueprint-factory/
├── README.md                 # vue d'ensemble V1 + kit KX + régénération de ces pages
├── build.sh                  # V1 (3 bâtiments) : SVG → Blender → bake → viewer/assets → Godot
├── build-kit.sh              # Kit KX : SVG + mesh + lint + Blender + bake + GLB web Draco + assets
├── build-outpost.sh          # Kit OX (même structure, FAST=1 = sans Blender)
├── build-grid.sh             # Kit GX : voxels + sprites A + Blender (B, B′) + quantification + lint
├── specs/
│   ├── habitat_s.json, command_hq.json, landing_pad.json   # V1
│   ├── kit/   style-kit.json · stats.json · modules/ · hulls/ · assemblies/
│   ├── outpost/ style-outpost.json · buildings/ · plots/ · assemblies/
│   ├── grid/  grid-kit.json · modules/ · hulls/ · assemblies/
│   └── briefs/ax02-mixte.brief.txt
├── src/
│   ├── geom.py spec.py project.py blueprint.py factory.py sheets.py   # V1 (pur Python)
│   ├── blender_bridge.py bake_textures.py kit_web_glb.py               # Blender (partagés KX/OX)
│   ├── viewer_assets.py godot_check.gd                                # V1
│   ├── kit_core.py kit_parts.py kit_modules.py kit_hulls.py kit_sheet.py kit_project.py
│   │   kit_build.py kit_viewer_assets.py kit_config_data.py            # KX
│   ├── ox_core.py ox_parts.py ox_buildings.py ox_plots.py ox_sheet.py
│   │   ox_build.py ox_viewer_assets.py                                 # OX
│   ├── grid/  gx_core gx_parts gx_hulls gx_build gx_raster gx_blender gx_quantize gx_finalize
│   ├── chain/ brief_to_spec chain_blender chain_gameplay chain_tscn chain_qa chain_sheet chain_site
│   └── handoff/build_context.py     # génère viewer/context.json + viewer/index.html (rendu de handoff.md)
│       handoff/home.template.html  # gabarit de l'accueil (préambule IA, nav, visionneuse)
├── tools/   kit_lint.py ox_lint.py grid_lint.py kit_cinematic_renders.py
│            test-viewer.mjs test-kit.mjs test-kit-config.mjs test-kit-nav.mjs
│            test-chain.mjs test-outpost.mjs test-grid.mjs test-factory-home.mjs check-factory-text.py
├── viewer/  # = ce qui est publié sous /factory/
│   ├── index.html viewer.js viewer.css handoff.md llms.txt context.json
│   ├── vendor/three/ (r170, vendorisé, dont le décodeur Draco)
│   ├── assets/ (models, plans, kit, grid, referential, buildings.json)
│   ├── kit/ (index, kit.js, kx3d.js, kxrules.js, kgltf.js, configurator/, variants/)
│   ├── chain/  outpost/  grid/  referential/
├── docs/    planches, captures, README par kit (kit/, outpost/, grid/, chain/), handoff/
└── build/   sorties (une partie est suivie : manifestes, lint, modèles ; mesh/logs/web ignorés)
```

Outils externes : Blender 5.2 (variable `BLENDER`, binaire local), `xvfb-run`, Python 3 avec `cairosvg`, Pillow et numpy, Godot 4.7.2 (optionnel, pour le contrôle d'import), Node et Playwright avec Chrome et SwiftShader pour les tests.

## 8. Principes de conception transverses

1. **La spec est la source de vérité.**
   - Le SVG est une **sortie** inspectable, écrasée à chaque build : il ne faut pas l'éditer.
   - `src/geom.py` (pur Python) construit les maillages. Le SVG est une projection orthogonale de **ces mêmes sommets**, et Blender fait `from_pydata` avec eux aussi.
2. **Triple vérification des cotes :**
   - bbox de chaque pièce dans Blender contre le manifeste (tolérance 0,1 mm) ;
   - bbox du GLB réimporté (1 mm) ;
   - import Godot (tailles et triangles).
   - Le build échoue si une pièce passe sous le sol.
3. **Dessin technique :**
   - projection du **3e dièdre** : dessus au-dessus de la face, profil droit à droite, même échelle, lignes de rappel ;
   - calques Inkscape et attribut `data-part` sur chaque pièce ;
   - échelle automatique de 1:20 à 1:200, silhouette humaine de 1,80 m, cartouche avec le sha256 de la spec.
4. **Repère :** mètres, Z en haut, origine au sol au centre du socle, façade vers −Y (V1). L'export glTF est en Y-up. Dans three.js, un point du kit devient position (x, z, −y), avec rotation.y = rotZ.
5. **Ressemblance par construction :** tous les objets d'un kit sont bâtis avec les **mêmes sous-composants** et les **mêmes métriques**, et un lint le vérifie. Les détails A et B du coin KX sont identiques d'un module à l'autre.
6. **Les coques et parcelles ont des slots vides.** Elles ne dessinent jamais de module ni de bâtiment, seulement les interfaces. Le lint vérifie qu'aucune pièce de module n'apparaît dans un blueprint de coque.
7. **Un assemblage, ce sont des données, pas un nouveau blueprint :** `{slot, module, rot}` (et `links` pour OX). Le build compose le maillage, et la visionneuse compose la même chose dans le navigateur à partir des GLB de la coque et des modules.
8. **Héritage sans copie :**
   - OX *étend* KX (`"extends": "specs/kit/style-kit.json"`) : le code lit les valeurs héritées dans la source unique (`src/kit_core.py`, objet `S`).
   - GX dérive ses métriques de KX (g = U/2) et le lint vérifie le lien.
9. **Déterminisme :** le brief → spec suit des règles fixes, sans IA. Les variantes passent par `generate(seed)` (mulberry32) et l'usure par une seed. Mêmes entrées, mêmes sorties.
10. **Sobriété web :** Draco plus textures JPEG, filaire calculé dans le navigateur, faces cachées retirées des SVG, un seul décodeur Draco partagé.

## 9. V1 : bâtiments de colonie (spec → SVG → 3D)

| ID | Bâtiment | Emprise (tuiles de 2 m) | Hors-tout (m) | Pièces | Triangles |
|---|---|---|---|---|---|
| `habitat_s` | Module habitat S : coque Ø2,80, sas, porte de 0,90 × 2,00, 4 hublots | 2×2 | 3,92 × 3,92 × 4,68 | 32 | 2 404 |
| `command_hq` | QG sur 2 niveaux, PC vitré, terrasse, mât comms, radôme | 3×3 | 5,92 × 5,92 × 7,57 | 57 | 2 642 |
| `landing_pad` | Aire 3×3 : piste, cercle, H, 12 feux, 2 mâts balise | 3×3 | 5,92 × 5,92 × 2,27 | 13 | 1 180 |

- **Écarts mesurés :** ≤ 0,05 mm par pièce et ≤ 0,0002 mm sur le GLB réimporté. Godot 4.7.2 a importé les 6 GLB sur 6, avec 1 MeshInstance3D chacun.
- **Textures cuites** (`<id>_tex.glb`) : UV *smart project*, atlas de 2048 px, bake de la couleur, des normales et de l'émission, un seul matériau PBR.
- **Primitives de spec :** `box`, `prism` (+ `chamfer`/`taper`), `cylinder`/`frustum`, `tube`, `dome`, avec `at`, `rot`, `repeat` et `polar`. Composants : `door`, `window`, `hublot`, `ladder`, `railing`.
- **Calques et matériaux :**
  - `layer` vaut `structure`, `openings`, `equipment` ou `markings` ;
  - `mat` vaut `panel`, `anthracite`, `accent`, `emissive`, `glass`, `metal`, `pad` ou `paint`.
- **Limites V1 :**
  - le SVG est une sortie seulement ;
  - pas de booléens : les ouvertures sont en saillie, pas percées ;
  - pas de coupes en V1, alors que les kits suivants en ont ;
  - pas de LOD ni de collisions.

## 10. Kit KX : cargo spatial modulaire

Source : `specs/kit/style-kit.json` (version 1.0). Doc détaillée : `docs/kit/README.md`. Page : [/factory/kit/](https://kg.g.caute.re/factory/kit/).

### 10.1 Métriques imposées

- **Grille :** U = 0,25 m, u = U/5 = 0,05 m. Toute cote structurelle est un multiple de u, et c'est vérifié.
- **Slots :** C1 = 3,00 × 2,00 × 2,00 ; C2 = 6,25 = 2 × C1 + une nervure de 0,25. Le jeu est de 0,05 par face, donc l'enveloppe d'un module C1 fait 2,90 × 1,90 × 1,90.
- **Interface KX-4 :**
  - 8 coins **KXC** (cubes de 0,20, biseau XS, couleur `iface` `#f2b705`) ;
  - 4 verrous **KXL** au plancher du slot, à l'aplomb des coins (retrait de 0,10) ;
  - 4 bras **KXB** en tête : la mâchoire tombe sur les coins hauts ;
  - 1 ombilicale **UMB** au centre (mâle sous le module, femelle sur la coque, entraxe des brides de 100 mm). Un C2 en a 2, à ±1,625.
- **Rivets :** micro Ø0,03 au pas 0,15, marge ≥ 0,05 (modules et composants) ; macro Ø0,06 au pas 0,30 (coques). Les rangées sont centrées : n = floor((L − 2·edge)/pitch) + 1.
- **Biseaux à 45° :** XXS 0,01 · XS 0,025 · S 0,05 · M 0,10 · L 0,20 · XL 0,40. La taille vaut environ 1/10 de la plus petite section, arrondie à la taille inférieure.
- **Bordé :** plaques de 0,50 sur les modules et de 1,00 sur les coques, joints de 0,01. Les joints SVG et ceux de la texture cuite ont le même pas.
- **Cadre :** lisse de 0,10 (biseau XS), nervures de 0,10 × 0,20 au pas de 0,50.
- **Marquage :** bande code denrée de 0,15 de haut à z = 1,45, hachures de 0,10, ID de 0,20.
- **Traits (en mm sur la feuille) :** contour 0,35 · détail 0,20 · joint 0,10 · caché 0,13 · slot 0,30 (orange, pointillé) · coupe hachurée à 45°.
- **Typographie :** IBM Plex Sans Condensed et IBM Plex Mono.

### 10.2 Contenu

**Composants (14)** : `src/kit_parts.py`

| Code | Nom | Triangles |
|---|---|---|
| RVT | Rangée de rivets | 108 |
| BVL | Profil biseauté | 28 |
| PNL | Plaque de bordé | 228 |
| RIB | Nervure de renfort | 252 |
| KXC | Pièce de coin KX | 104 |
| KXL | Verrou tournant KX | 224 |
| KXB | Bras de serrage KX | 268 |
| UMB | Prise ombilicale KX | 376 |
| IFP | Plaque d'interface de slot | 2 076 |
| VNT | Grille d'aération | 200 |
| RNG | Poignée / échelon | 200 |
| BCN | Feu balise | 162 |
| PIP | Raccord de tuyauterie | 480 |
| DOR | Porte cargo | 1 168 |

**Modules (5)** : `specs/kit/modules/*.json` → `src/kit_modules.py`

| Code | Nom | Classe | Corps | Triangles |
|---|---|---|---|---|
| KX-LIQ | Module citerne | C1 | tank | 5 430 |
| KX-BOX | Module conteneur sec | C1 | box | 11 200 |
| KX-ORE | Module vrac minerai | C1 | hopper | 5 164 |
| KX-CRY | Module cryogénique | C1 | cryo | 8 456 |
| KX-BIO | Module vivarium | C2 | vivarium | 16 880 |

Tous les modules partagent le même châssis : 8 KXC, 12 lisses BVL rivetées, un plancher, une UMB mâle dessous, une bande code et un ID. Seul le **corps** change.

**Coques (3), toutes à slots vides** : `specs/kit/hulls/*.json` → `src/kit_hulls.py`

| Code | Nom | Disposition des slots | Tuyères | Triangles |
|---|---|---|---|---|
| HX-S | Coque caboteur | 1 colonne : C1, C1 | 2 | 16 924 |
| HX-M | Coque cargo moyen | 2 colonnes × 3 rangs de C1 (6 slots) | 3 | 32 744 |
| HX-L | Coque long-courrier | 1 colonne : C2 / C1 / C1 / C2 / C1 | 2 | 41 076 |

La planche d'une coque montre le dessus, l'élévation et le profil, la coupe A-A (quille, poste, propulsion) et la coupe B-B à travers un slot.

**Assemblages (4)** : `specs/kit/assemblies/*.json`

| Code | Nom | Coque | Remplissage | Triangles |
|---|---|---|---|---|
| AX-01 | Caboteur citerne + fret | HX-S | S1 LIQ, S2 BOX (180°) | 33 554 |
| AX-02 | Cargo moyen mixte | HX-M | S1–S2 CRY, S3 BOX, S4 LIQ (180°), S5 ORE, S6 ORE (180°) | 76 614 |
| AX-03 | Minéralier partiel | HX-M | S1 LIQ, S2 **vide**, S3–S6 ORE (en alternant 0° et 180°) | 58 830 |
| AX-04 | Long-courrier vivarium | HX-L | S1 BIO (C2), S2 CRY, S3 BOX, S4 = 2 × LIQ (a, b), S5 CRY | 96 928 |

**Repère des assemblages :** +x vers l'avant, +z vers le haut. y < 0 est tribord, y > 0 bâbord. S1 = avant tribord, S2 = avant bâbord, et ainsi de suite.

### 10.3 Lint KX (`tools/kit_lint.py`, 119 contrôles)

| Groupe | Ce qui est vérifié |
|---|---|
| charte | U = 5u, slots sur la grille, C2 = 2 × C1 + nervure |
| rivets / biseaux / grille | pas, marges, série de biseaux à 45°, enveloppes sur u |
| interface | 8 coins par module, verrous et bras alignés |
| slots vides | aucun module dans un blueprint de coque |
| assemblage | coins, verrous, bras et ombilicales à 1 mm près |
| liens | chaque composant est utilisé, chaque module loge dans au moins une coque |
| configurateur | stats complètes, AX-01..04 dans les budgets, missions, `config.json` à jour |
| palette | aucun vert dans les SVG, la visionneuse, la charte, `stats.json` et les matériaux Blender |

Résultat vérifié le 10/11 au soir : `KIT_LINT OK 119/119`. Le lint écrit dans `build/kit/lint.json`, un fichier suivi par git (voir [§21](#21-problèmes-connus)).

### 10.4 Rendus

Dix rendus sont décrits dans `docs/kit/renders/README.md` : des originaux Blender Cycles en 1920×1080 et des passes cinématiques IA en 1280×720.

- La version Blender est conservée quand la version IA dévie trop : vue éclatée, coques à slots vides, pylônes ajoutés par l'IA.
- Une planche contact est fournie.

## 11. Configurateur et galerie de variantes KX

### 11.1 Configurateur ([/factory/kit/configurator/](https://kg.g.caute.re/factory/kit/configurator/))

- **Interaction :**
  - choisir une coque ;
  - déposer des modules par **glisser-déposer**, sur le plan 2D ou directement sur la 3D (raycast, surbrillance orange si le dépôt est accepté, rouge sinon) ;
  - ou **cliquer** sur un module pour l'armer, puis sur un slot ;
  - `R` tourne le module de 180°, `Suppr` le retire.
- **Règles** (`viewer/kit/kxrules.js`, partagé avec la galerie) :
  - **taille :** un C1 va dans un slot C1 ou un demi-slot `a`/`b` de C2 ; un C2 prend un slot C2 entier ;
  - **orientation :** rotZ ∈ {0, 180} ;
  - **interface KX-4 :** même calcul que le lint, à 1 mm près ;
  - **slot vide :** autorisé, mais signalé ;
  - **budgets :** charge utile et énergie du bus ombilical (`specs/kit/stats.json`).
- **Résumé affiché :** masse, coût, jauges de charge et d'énergie, capacité par denrée. Les 4 assemblages AX sont proposés en presets.
- **Export / import** au format AX : `id, code, name, hull, description, fill[{slot, module, sub?, rot?}]`, plus `livery` et `seed` optionnels. Exemple : `docs/kit/variants/cfg_exemple.json`.
- **Habillage**, sans toucher à la géométrie :
  - immatriculation `<lettre coque><3 alnum>-<3 chiffres>` (alphabet sans I, O ni Q) ;
  - bande de flotte orange, jaune, cyan, rouge ou blanc ;
  - usure de 0 à 3 (neuf, service, usé, épave) : encrassement vers `rock` `#4a3f36` et écaillage déterministe.
- **Données :** `python3 src/kit_config_data.py` génère `viewer/assets/kit/config.json` (stats, presets, ancres d'habillage, `half_c2` = 1,625).

### 11.2 Galerie de variantes ([/factory/kit/variants/](https://kg.g.caute.re/factory/kit/variants/))

`generate(seed)` est déterministe (mulberry32) et procède ainsi :

1. Tirage d'une coque pondérée (S 3, M 4, L 3).
2. Tirage d'une mission : Citernier, Vraquier, Frigorifique, Mixte ou Bétailler. Elle pondère les denrées.
3. Remplissage des slots :
   - chaque slot reste vide avec p = 0,12 ;
   - un C2 reçoit un BIO avec p = 0,8 en Bétailler et 0,15 sinon, et 2 × C1 dans les autres cas.
4. Rotation de 180° avec p = 0,4.
5. Habillage.
6. Correction des budgets : le module fautif est remplacé par une denrée plus légère, ou le slot est vidé.

Le résultat :

- 20 vignettes par défaut ;
- un clic ouvre la variante dans le configurateur, avec le même état ;
- planche statique : `docs/kit/variants/kx-variants-sheet.png` ; specs des seeds 1 à 20 : `docs/kit/variants/variants-seeds-1-20.json`.

**Mémoire :** la galerie rend 20 vignettes 3D. Depuis `2700872`, `viewer/kit/kgltf.js` fournit un chargeur GLB partagé (un seul `DRACOLoader`, 1 worker wasm, cache, file d'attente). Il libère le renderer et le décodeur à la navigation. Un échec de chargement affiche l'erreur au lieu d'un « Chargement… » qui reste bloqué.

## 12. Chaîne factory en 9 étapes

Page : [/factory/chain/](https://kg.g.caute.re/factory/chain/), sur AX-02 « Cargo moyen mixte ». Les 9 étapes sont toutes **réelles** depuis `8c6bb9c`. Doc : `docs/chain/README.md`. Planche : `docs/chain/chain-9-steps.png`.

| # | Étape | Script / commande | Artefact |
|---|---|---|---|
| 1 | Brief | `specs/briefs/ax02-mixte.brief.txt` (texte « clé : valeur ») | brief |
| 2 | Spec JSON | `python3 src/chain/brief_to_spec.py specs/briefs/ax02-mixte.brief.txt --check specs/kit/assemblies/asm_mixte.json` (règles fixes, **sans IA**) | `build/chain/ax02-mixte.spec.json`, identique à `asm_mixte.json` |
| 3 | Blockout | `xvfb-run -a $BLENDER --background --python src/chain/chain_blender.py -- --pass blockout --out build/chain --seed 4471` | volumes issus du manifeste, grille U |
| 4 | Plan SVG | `python3 src/kit_build.py` | `build/kit/blueprints/asm_mixte.svg` |
| 5 | Kitbash 3D | `src/blender_bridge.py` (via `./build-kit.sh`) | rendus plein, filaire et texturé |
| 6 | Usure | `chain_blender.py --pass wear --seed 4471` | bruit + AO, chocs Voronoï, pochoirs série et slot |
| 7 | Bake | `--pass ao_bake` (AO 512² sur l'atlas de `hull_m_tex.glb`), `bake_textures.py` (normales), `--pass id_bake` (carte ID, EMIT 1024²) | cartes, atlas, `id_legend.json` |
| 8 | QA | `python3 src/chain/chain_qa.py` | `kit_lint.py`, plafonds de triangles, brief ≡ spec, gameplay vs configurateur, symétrie de coque (98,6 % de pièces miroir), aucun vert dans les rendus |
| 9 | Export Godot | `python3 src/chain/chain_gameplay.py && python3 src/chain/chain_tscn.py`, puis Godot headless `--import` et `-s check.gd` | `asm_mixte.tscn` (9 collisions, 6 ancres Marker3D) et `asm_mixte.gameplay.json`. Contrôle : `TSCN_OK AX-02 meshes=1 collisions=9 ancres=6 masse_t=102.5 cout_cr=18200` |

**Fin de chaîne :**

- `python3 src/chain/chain_sheet.py && python3 src/chain/chain_site.py` produit la planche et la page ;
- `node tools/test-chain.mjs <url>/factory/chain/` teste la page.

Les artefacts de chaque étape sont publics sous `/factory/chain/artifacts/` : brief, spec, `style-kit.json`, `hull_m.json`, `.tscn`, fiche gameplay, rapport QA, cartes cuites…

**Format du brief** (extrait réel) :

```text
code       : AX-02
nom        : Cargo moyen mixte
rôle       : cargo
gabarit    : moyen
slots      : 6 × C1
cargaison  : 2 cryo, 1 sec, 1 liquide, 2 minerai
placement  : avant → arrière, tribord puis bâbord
retourner  : liquide, minerai @ bâbord
ton        : lisible de loin, châssis KX commun, interface jaune visible, usure modérée
usure_seed : 4471
```

## 13. Kit OX : avant-poste minier sur astéroïde

Source : `specs/outpost/style-outpost.json` (version 0.1, `extends` KX). Doc : `docs/outpost/README.md`. Page : [/factory/outpost/](https://kg.g.caute.re/factory/outpost/).

### 13.1 Héritage KX, sans copie

OX reprend de KX la grille U/u, les rivets, les biseaux, le bordé, le cadre, les marquages, les traits, la typo et la palette. Il hérite aussi de 10 composants KX : RVT, BVL, RIB, KXC, UMB, VNT, RNG, BCN, PIP et DOR.

- Les scripts Blender sont les mêmes, sans modification : `blender_bridge.py`, `bake_textures.py`, `kit_web_glb.py`.
- Le cadre des planches vient de `kit_sheet.py`.

### 13.2 Métriques propres à OX

- **Maille de lotissement :** Λ = 6,00 (24U), soit une emprise F1 de 4,00 plus un couloir de 2,00. Chaque centre de slot est un nœud de maille.
- **Emprises :** F1 = 4,00 × 4,00 ; F2 = 10,00 × 4,00. Le jeu est de 1U par face, donc l'enveloppe F1 fait 3,50 × 3,50. Un slot F2 accepte 1 × F2, ou 2 × F1 sur les sous-slots `a` (+3,00) et `b` (−3,00).
- **Socle OX-4 :**
  - des ancrages **ANC** (retrait de 0,10) qui reçoivent des vérins **LEG** (2U), placés sous les KXC jaunes ;
  - un plancher à +0,70 ;
  - une **UMB** au centre, avec un jeu UMB ↔ borne **HUB** vérifié entre 50 et 100 mm (74 mm mesurés).
- **Ports PRT :** axe à +1,75 (7U), collier de 1U qui affleure l'emprise, bride jaune de Ø1,80 à 16 boulons.
- **Tubes TUB :** Ø1,50, longueur n × 0,50. Entre deux voisins, un tube fait 2,00, avec un tréteau **SUP** au milieu.
- **Terrain :** terrasse à +1,20, origine de slot à +1,30, régolithe en cellules de 1,00 avec cratères et blocs.
- **Familles :** VIE `#2f7fd0` · EXT `#e0573a` · TRT `#c8962e` · NRJ `#8fd3ff` · COM `#b06ad8`. Ce sont les teintes de denrée KX : aucune nouvelle couleur, aucun vert.

### 13.3 Contenu

- **Composants OX (12) :**

  | Code | Rôle | Code | Rôle |
  |---|---|---|---|
  | ANC | ancrage régolithe | SUP | tréteau |
  | LEG | vérin | MMS | blindage Whipple |
  | HUB | borne de service | RAD | radiateur |
  | SPD | semelle de slot | SOL | panneau solaire |
  | PRT | port de liaison | ANT | antenne |
  | TUB | tube de liaison | SAS | sas d'accès |

- **Bâtiments (7) :**

  | Code | Bâtiment | Classe | Famille | Ports | Triangles |
  |---|---|---|---|---|---|
  | OX-HAB | Habitat pressurisé | F1 | VIE | E W N | 9 166 |
  | OX-DRL | Foreuse | F1 | EXT | W | 8 686 |
  | OX-REF | Raffinerie | F2 | TRT | E W Sa Sb | 16 316 |
  | OX-SIL | Silo à minerai | F1 | TRT | – | 8 846 |
  | OX-PWR | Centrale solaire | F1 | NRJ | – | 7 014 |
  | OX-COM | Relais de communication | F1 | COM | – | 9 346 |
  | OX-HGR | Hangar à engins | F2 | VIE | E Sa Na | 16 692 |

- **Parcelles :**
  - PX-S, Prospection : 3 × F1 (14 070 tris) ;
  - PX-M, Exploitation : 4 × F1 + 1 × F2 (23 820) ;
  - PX-L, Base : 5 × F1 + 3 × F2 (40 234).
- **Assemblages :**
  - OA-01, Avant-poste de prospection : PX-S, 3 bâtiments, 1 tube (40 476 tris) ;
  - OA-02, Exploitation minière : PX-M, 5 bâtiments, 3 tubes (80 140) ;
  - OA-03, Base minière complète : PX-L, les 7 types en 9 bâtiments (le slot S7 est un F2 garni de 2 × F1), 6 tubes (**143 872**, voir [§19](#19-budgets-triangles-et-poids-web)).

Un assemblage contient `fill` (`{slot, sub, building, rot}`) et `links` (`[slotA, portA, slotB, portB]`). Le build route chaque tube entre les brides. Il produit l'assemblage complet, plus un `lnk_*` qui ne contient que les tubes et les tréteaux.

### 13.4 Lint OX (`tools/ox_lint.py`, 150 contrôles)

Il vérifie :

- les classes de slot ;
- les vérins sur les ancrages et l'alignement UMB ↔ HUB ;
- l'emprise dans la terrasse ;
- les tubes : face à face, coaxiaux, de longueur n × 0,50, posés dans un couloir ;
- les ports libres, listés comme obturés ;
- l'absence de bâtiment sur une parcelle ;
- l'absence de vert.

Vérifié le 10/11 au soir : `OX_LINT OK 150/150`.

## 14. Kit GX : grille voxel pour pixel art

Source : `specs/grid/grid-kit.json` (version 0.1). Doc : `docs/grid/README.md`. Page : [/factory/grid/](https://kg.g.caute.re/factory/grid/).

### 14.1 Charte

- **1 voxel = g = U/2 = 0,125 m** (G8 : 8 vox/m). G4 (1 vox = U) en est un LOD dérivé par sous-échantillonnage 2×2×2, jamais modélisé.
- **Slots :** C1 = 24 × 16 × 16 vox (= 3 × 2 × 2 m, comme KX) ; C2 = 50 (2 × C1 + 2). Le jeu est de 1 vox, et le module se pose sur z = 1. Enveloppes : C1 = 22 × 14 × 14, C2 = 48 × 14 × 14.
- **Interface GX-4 :**
  - 8 coins de 2 × 2 × 2 en jaune `#f2b705`, avec un trou de 1 px ;
  - 4 verrous de 2 × 2 dans la couche 0 ;
  - des mâchoires en z = 15 ;
  - une ombilicale de 4 × 4.
- **Détails au pixel :**
  - **rivet = 1 pixel** : un drapeau de surface, pas un voxel ;
  - **chanfrein** en marches de 1 voxel à 45° : 0 marche sous 6 vox, 1 sous 16, 2 sous 32, 3 au-delà ;
  - joints tous les 4 vox (modules) ou 8 vox (coques) ;
  - bande code en z = 11.
- **Palette indexée de 53 couleurs, sans vert :**
  - 0 = transparent ;
  - 4 couleurs fixes : encre `#14161c`, ombre `#262a33`, slot `#ff9a3c` et slot caché `#8a5426` ;
  - 16 matériaux × 3 tons (hi, mid, lo).
  - Exports : `gx_palette.gpl`, `.hex` et `.png`.
- **Éclairage fixe en repère écran :** dessus = hi, face gauche = mid, face droite = lo. Un contour de 1 px en encre entoure la silhouette, et une rupture de profondeur de plus de 2 vox donne 1 px d'ombre.
- **Projection :** iso 2:1 entière, P = [[−2,2,0],[1,1,−2]]. La vue 3/4 de dessus utilise P = [[−2,0,0],[0,2,−2]].

### 14.2 Contenu

- **Composants (15) :** CRN, LCK, ARM, UMB, RVT, BVL, PNL, RIB, VNT, BCN, PIP, DOR, WIN, HAZ, IFP (codes `GX-*`).
- **Modules (5) :** GX-LIQ, GX-BOX, GX-ORE et GX-CRY en C1 (22 × 14 × 14), GX-BIO en C2 (48 × 14 × 14).
- **Coques (3), à slots vides :** GH-S (107 × 20 × 42 vox), GH-M (147 × 38 × 45) et GH-L (257 × 20 × 44).
- **Assemblages (4) :** GA-01 à GA-04, les mêmes que AX-01 à AX-04, composés dans le navigateur.

### 14.3 Méthodes comparées et verdict

| Méthode | Principe | Résultat |
|---|---|---|
| **A** : raster voxel direct (`src/grid/gx_raster.py`) | Projection 2:1 entière : chaque voxel est un tampon de 12 px. Peintre vectorisé numpy, plus le contour | PNG indexé natif, lignes 2:1 parfaites, rivets à 1 px, 4 directions + 3/4, normales et profondeur. 27 objets en environ 2 s |
| **A · G4** | Même raster sur la grille divisée par 2 | Bon LOD lointain (icônes, carte). Les rivets et les joints sont perdus, les coins conservés |
| **B** : Blender (`gx_blender.py` + `gx_quantize.py`) | Faces voxel en ortho, Workbench FLAT sans AA, puis quantification palette | 8 directions (45°). Environ 82 % de pixels exacts, escaliers irréguliers, pas de rivets |
| **B′** : maillage lisse KX | GLB KX rendu en basse résolution, puis quantifié | **0 % de pixels exacts** (écart d'environ 11). Un modèle lisse ne devient pas du pixel art lisible |
| **C** : pixel en direct (visionneuse) | three.js rendu à 1/2 ou 1/4 de résolution, au plus proche voisin | Utile pour cadrer. Scintille en rotation, pas de contour |

**Verdict, qui sert de décision :**

- la géométrie **naît sur la grille**, et le rendu est un **raster entier voxel par voxel en Python** (méthode A) ;
- Blender en ortho (B) n'est gardé **que pour les 8 directions** ou une caméra libre, et demande des retouches ;
- **G4** sert pour les vues lointaines et les icônes ;
- C est un outil de cadrage ;
- on ne part pas d'un modèle KX lisse.

### 14.4 Lint et limites

- **Lint GX** (`tools/grid_lint.py`, 107 contrôles) :
  - lien avec KX ;
  - palette : 64 couleurs au plus, pas de vert, bases issues de KX ;
  - chanfreins, rivets, modules, coques et assemblages : 0 collision, alignement coins ↔ verrous ↔ mâchoires ;
  - sprites indexés dans la palette exacte.
  - Vérifié le 10/11 : 107/107.
- **Limites :**
  - les sprites G8 des coques sont grands (jusqu'à 560 × 370 px pour GH-L) ;
  - l'éclairage est fixe à l'écran ;
  - les 8 directions de la méthode B ne sont pas retouchées ;
  - la carte de normales contient des teintes cyan-vert. C'est une donnée technique, exclue du contrôle « sans vert » de la palette art.

## 15. Référentiel IA

Page : [/factory/referential/](https://kg.g.caute.re/factory/referential/), une grille 3 × 2.

- **Principe :** pour chacun des 3 bâtiments V1, une image est générée par un modèle d'image à partir du **plan technique**, et une autre à partir de la **prévisualisation 3D texturée**.
- **But :** juger à quel point le modèle d'image respecte le référentiel (proportions, pièces nommées, matériaux).
- **Fichiers :** sources dans `viewer/assets/referential/sources/`, rendus dans `viewer/assets/referential/`.
- **Constat :** les rendus Blender restent la référence quand l'IA dévie (voir aussi les rendus KX, [§10.4](#104-rendus)).

## 16. Formats de fichiers et schémas

Toutes les specs sont du JSON UTF-8. Les clés `_doc` et `_rule` sont des commentaires lus par les humains et les agents.

### 16.1 Spec bâtiment V1 (`specs/<id>.json`)

```json
{ "id": "habitat_s", "name": "Module habitat S", "code": "HAB-S", "tiles": [2, 2], "description": "…",
  "parts": [ { "id": "hull", "label": "Coque pressurisée Ø2.80", "layer": "structure", "mat": "panel",
               "prims": [ { "type": "cylinder", "r": 1.40, "h": 2.60, "at": [0, 0.30, 0.45] } ] } ],
  "dims": [ … ], "levels": [ … ], "decals": [ … ] }
```

- Les primitives acceptent `repeat` et `polar` (`{n, r, start, center, skip}`).
- Une entrée de `dims` donne `view`, `parts`, `axis` et `side`.
- Le code de référence est `src/spec.py`.

### 16.2 Charte KX (`specs/kit/style-kit.json`)

Clés de premier niveau :

- `grid {U, u}` ;
- `slots {C1, C2, clearance, rib_gap}` ;
- `interface {name: "KX-4", casting, twistlock_inset, umbilical, plate_t}` ;
- `rivet {micro, macro}` ;
- `bevel {angle_deg, sizes, ratio}` ;
- `plates`, `frame`, `markings` ;
- `palette {…, codes{LIQ,BOX,ORE,CRYO,BIO}}` ;
- `strokes`, `type`, `scale_classes` ;
- `budget.triangles {component, module, hull, assembly}` ;
- `gameplay {units, cargo{<denrée>: {density}}, modules{<id>: {usable, tare_t, cost_cr}}, hulls{<id>: {dry_t, cost_cr}}}`.

### 16.3 Module KX (`specs/kit/modules/<id>.json`)

```json
{"id": "mod_liq", "code": "KX-LIQ", "name": "Module citerne", "cls": "C1", "body": "tank", "cargo": "LIQ",
 "goods": "Liquides : eau, carburant, solvants", "description": "…"}
```

- `cls` vaut `C1` ou `C2`.
- `body` vaut `tank`, `box`, `hopper`, `cryo` ou `vivarium`.

### 16.4 Coque KX (`specs/kit/hulls/<id>.json`)

```json
{"id": "hull_m", "code": "HX-M", "name": "Coque cargo moyen", "description": "…",
 "rows": [["C1", "C1"], ["C1", "C1"], ["C1", "C1"]], "fore_len": 5.0, "aft_len": 3.4, "keel_h": 1.60, "engines": 3, "skid_h": 1.00}
```

`rows` liste les rangs de l'avant vers l'arrière. Chaque rang contient une ou deux colonnes (tribord puis bâbord). Les slots sont numérotés S1, S2… dans cet ordre.

### 16.5 Assemblage KX (`specs/kit/assemblies/<id>.json`), qui est aussi le format d'export du configurateur

```json
{"id": "asm_mixte", "code": "AX-02", "name": "Cargo moyen mixte", "hull": "hull_m", "description": "…",
 "fill": [{"slot": "S1", "module": "mod_cryo"}, {"slot": "S4", "module": "mod_liq", "rot": 180}]}
```

- `sub` vaut `a` ou `b` pour un C1 posé dans un C2.
- `rot` vaut 0 ou 180 (0 par défaut).
- L'export du configurateur ajoute `livery` et `seed`, qui sont optionnels.

### 16.6 Stats gameplay KX (`specs/kit/stats.json`)

- `modules.<id>` : `{tare_t, load_t, cap, unit, power_kw, label}`.
- `hulls.<id>` : `{dry_t, payload_t, power_kw, crew}`.
- `livery` : bandes de flotte, couleur d'encrassement, niveaux d'usure et format d'immatriculation.
- `generator` : `{hull_weights, p_empty, p_rot180, p_bio, missions}`.
- `_rules` : définitions de la masse, de la charge utile, de l'énergie et des slots.

### 16.7 Charte OX (`specs/outpost/style-outpost.json`)

- Héritage : `extends`, `inherits[]`.
- Métriques : `lattice {pitch, corridor}`, `footprints {F1, F2, clearance}`, `socle {name: "OX-4", anchor_inset, pile, leg_h, deck_z, hub_top, umb_gap, …}`, `port {z, tube_d, flange_d, collar, bolts, segment}`.
- Environnement et équipements : `terrain`, `shield`, `radiator`, `solar`.
- Couleurs : `families{VIE,EXT,TRT,NRJ,COM}`, `palette_add`.

### 16.8 Bâtiment, parcelle et assemblage OX

```json
{"id": "bld_hab", "code": "OX-HAB", "name": "Habitat pressurisé", "cls": "F1", "body": "habitat", "family": "VIE", "ports": ["E", "W", "N"], "role": "…", "description": "…"}
{"id": "plot_m", "code": "PX-M", "name": "Parcelle d'exploitation", "seed": 23, "craters": 5, "rocks": 30,
 "slots": [{"id": "S1", "cls": "F1", "node": [0, 0]}, {"id": "S4", "cls": "F2", "node": [0, 1]}]}
{"id": "oa_exploitation", "code": "OA-02", "plot": "plot_m",
 "fill": [{"slot": "S1", "building": "bld_drl", "rot": 180}], "links": [["S1", "W", "S2", "W"], ["S2", "N", "S4", "Sa"]]}
```

### 16.9 Charte et objets GX

- **Charte** (`specs/grid/grid-kit.json`) : `grid {g, per_U, lod}`, `slots` (en voxels), `interface`, `rivet`, `bevel {steps}`, `plates`, `frame`, `markings`, `render {tones, light, outline, iso.P, oblique.P, aa:false}`, `palette {fixed, materials[16], ramp}`.
- **Objets :** `specs/grid/modules/gmod_*.json`, `hulls/ghull_*.json` (`rows`, `fore`, `aft`, `keel_h`, `skid_h` en voxels) et `assemblies/gasm_*.json` (même `fill` que KX).
- **Sorties :**
  - `viewer/assets/grid/grid.json` : catalogue, palette, lint ;
  - `vox/<id>.json` : grille dense en base64, ordre x, y, z ;
  - `sprites/<id>/g8_d0..3.png`, `g4_d*.png`, `g8_oblique.png`, plus les normales et la profondeur ;
  - `sprites_b/<id>/b_d0..7.png` ;
  - `sheets/<id>.png` et `.json` (atlas).

### 16.10 Sorties de build communes

| Fichier | Contenu |
|---|---|
| `build/<kit>/blueprints/<id>.svg` | Planche A3 (calques, `data-part`) |
| `build/<kit>/manifest/<id>.dims.json` | Toutes les cotes, bbox par pièce, triangles |
| `build/<kit>/mesh/<id>.mesh.json` | Sommets et faces, les mêmes que le SVG (non suivi par git) |
| `build/<kit>/models/<id>.glb`, `<id>_tex.glb` | GLB plein et texturé |
| `build/<kit>/web/*.glb` | GLB web (Draco + JPEG), copiés dans `viewer/…` |
| `build/<kit>/lint.json` | Résultat du lint (`{ok, items[{group, check, ok, detail}]}`) |
| `viewer/assets/kit/kit.json`, `viewer/outpost/data/ox.json`, `viewer/assets/grid/grid.json` | Catalogues lus par les visionneuses : style, objets, triangles, lint |

## 17. Commandes : build, lint, tests, export

À lancer depuis la racine du dépôt `blueprint-factory/`. `BLENDER` vaut par défaut le binaire Blender 5.2 local.

```bash
# V1
./build.sh                         # 3 bâtiments : SVG, Blender, bake, assets visionneuse, Godot (≈ 2 min 25)
./build.sh specs/habitat_s.json    # un seul bâtiment
python3 src/factory.py specs/*.json   # SVG + manifestes seuls (< 1 s)

# Kits
./build-kit.sh       ; FAST=1 ./build-kit.sh       # KX (FAST = sans Blender)
./build-outpost.sh   ; FAST=1 ./build-outpost.sh   # OX
./build-grid.sh      ; FAST=1 ./build-grid.sh      # GX (≈ 25–50 s complet)
python3 src/kit_config_data.py                     # stats, presets, ancres → viewer/assets/kit/config.json

# Lints (rapides, sans Blender)
python3 tools/kit_lint.py    # → build/kit/lint.json      (attendu : KIT_LINT OK 119/119)
python3 tools/ox_lint.py     # → build/outpost/lint.json  (attendu : OX_LINT OK 150/150)
python3 tools/grid_lint.py   # → build/grid/lint.json     (attendu : [gx-lint] 107/107)
python3 src/chain/chain_qa.py   # QA de la chaîne AX-02 (attendu : CHAIN_QA OK)

# Ce handoff
python3 src/handoff/build_context.py   # régénère viewer/context.json et viewer/index.html (handoff.md rendu en HTML)
python3 src/handoff/build_context.py --check   # échoue si context.json ou index.html n'est pas à jour
PYTHONPATH=/tmp/pylib python3 tools/check-factory-text.py <url-factory>   # lecture « comme un LLM » via html2text : 27/27 sections
```

### 17.1 Tests navigateur (Playwright headless, Chrome et SwiftShader)

On sert `viewer/` (ou un site qui contient `factory/`) en HTTP local, puis on lance :

```bash
python3 -m http.server 8782 -d viewer &
node tools/test-viewer.mjs      http://127.0.0.1:8782/ docs        # accueil V1 : rotation, modes, captures
node tools/test-kit.mjs         http://127.0.0.1:8782/ docs/kit    # 4 niveaux KX, modes, coupe, éclaté
node tools/test-kit-config.mjs  http://127.0.0.1:8782/ docs/kit    # configurateur + galerie (28 contrôles)
node tools/test-kit-nav.mjs     http://127.0.0.1:8782/             # stress mémoire galerie → configurateur
node tools/test-outpost.mjs     http://127.0.0.1:8782/ docs/outpost
node tools/test-grid.mjs        http://127.0.0.1:8782/ docs/grid
node tools/test-chain.mjs       http://127.0.0.1:8782/chain/       # 10 images, liens d'artefacts en 200
node tools/test-factory-home.mjs http://127.0.0.1:8782/            # accueil v2 : source statique (27 h2), sans JS, ancres, liens, fichiers
```

- Les tests échouent sur toute erreur ou tout avertissement console, toute requête en échec et toute réponse HTTP ≥ 400.
- Ils utilisent `playwright-core` (chemin pnpm local) et `/usr/bin/google-chrome` avec `--use-angle=swiftshader`.

### 17.2 Export Blender, GLB et Draco

1. **Contrôle et export :** `src/blender_bridge.py` (Blender headless sous `xvfb-run`) vérifie chaque pièce contre le manifeste, puis exporte `<id>.glb`, `.fbx`, `_wire.glb` (glTF LINES) et les rendus filaire, plein et texturé.
2. **Textures :** `src/bake_textures.py` cuit les textures PBR (atlas de 512 pour les composants, 1024 pour les modules et bâtiments, 2048 pour les coques et parcelles) dans `<id>_tex.glb`.
3. **Web :** `src/kit_web_glb.py` produit les GLB web avec compression **Draco**, et des textures **JPEG** pour les `_tex` (option `--jpeg`).
4. **Visionneuses :** elles décodent avec le `DRACOLoader` de three r170 vendorisé, via le chargeur partagé `viewer/kit/kgltf.js`.
5. **Godot :** `src/godot_check.gd` (V1) et `build/chain/godot/check.gd` (chaîne) contrôlent l'import dans Godot 4.7.2 headless.

## 18. Palette : jamais de vert

- **Règle :** pas de vert, ni dans l'art, ni dans l'UI, ni dans les SVG, ni dans les matériaux. Est interdite toute couleur de teinte **70° à 170°** dont la saturation est ≥ 0,25 et la valeur ≥ 0,15 (HSV).
- **Contrôle :** `kit_lint`, `ox_lint` et `grid_lint` scannent les SVG, le CSS et le JS des visionneuses, les chartes, `stats.json` et les matériaux Blender. `chain_qa` compte les pixels verts des rendus (0 sur 198 400).
- **Palette de base KX :**

| Rôle | Hex |
|---|---|
| Fond | `#0a1a33` |
| Encre | `#eef7ff` |
| Cyan (traits) | `#62d6ff` |
| Marquage | `#ffad5c` |
| Slot (orange) | `#ff9a3c` |
| Coupe | `#ff6f61` |
| Coque | `#c9ccd2` |
| Cadre | `#3a3f4a` |
| Tôle | `#9aa3b0` |
| Interface (jaune) | `#f2b705` |
| Roche / encrassement | `#4a3f36` |

- **Codes denrée :** LIQ `#2f7fd0` · BOX `#e0573a` · ORE `#c8962e` · CRYO `#8fd3ff` · BIO `#b06ad8`.
- **Bandes de flotte :** orange `#ffad5c`, jaune `#f2b705`, cyan `#62d6ff`, rouge `#ff6f61` et blanc `#eef7ff`.
- **Seule exception tolérée :** les cartes de normales techniques (encodage standard), jamais affichées comme art.
- **Éclairage des rendus 3D :** neutre ou froid (soleil blanc froid, fill bleuté). C'était déjà l'un des correctifs de la V1 par rapport au kit colonie.

## 19. Budgets triangles et poids web

- **Plafonds** (`style-kit.json` → `budget.triangles`) : composant ≤ 2 500 · module ≤ 20 000 · coque ≤ 45 000 · **assemblage ≤ 100 000**. Ils sont vérifiés par `src/chain/chain_qa.py` sur les 26 objets KX. AX-04, avec 96 928 tris, est le plus proche du plafond ; AX-02 (76 614) en est à 77 %.
- **Fourchettes KX constatées :**
  - composants : 28 à 2 076 ;
  - modules : 5 164 à 16 880 ;
  - coques : 16 924 à 41 076 ;
  - assemblages : 33 554 à 96 928.
- **OX n'a pas de budget déclaré.** OA-03 compte 143 872 tris, ce qui dépasserait le plafond d'assemblage KX s'il s'appliquait (voir [§21](#21-problèmes-connus)).
- **Poids web KX :**
  - 44 GLB web (Draco + JPEG), environ 6,2 Mo en tout ;
  - la coque texturée la plus lourde fait environ 1,1 Mo, un module plein 30 à 77 Kio, un composant 1 à 14 Kio.
- **Filaire :** calculé dans le navigateur (`EdgesGeometry` à 20°, même règle que les arêtes vives du SVG). Aucun GLB filaire n'est en ligne.
- **SVG :** le retrait des faces totalement cachées fait passer les planches KX de 34 à 12 Mo.

## 20. Données gameplay

**Définitions :**

- Configurateur (`stats.json`) : **masse = coque à vide + Σ(tare + charge pleine)**. La charge utile Σ(tare + charge) doit rester ≤ `payload_t`, et l'énergie Σ `power_kw` ≤ `power_kw` de la coque.
- Chaîne (`style-kit.json` → `gameplay`) : volume utile = enveloppe × `usable`, et charge = volume utile × densité.
  - Densités en t/m³ : LIQ 1,00 · BOX 0,60 · ORE 2,33 · CRYO 0,69 · BIO 0,32.
  - Les densités ont été choisies pour retrouver les charges du configurateur, avec un écart maximal de 0,37 % contrôlé en QA.

**Modules :**

| Module | Tare + charge (t) | Capacité | Énergie | Coût (cr) |
|---|---|---|---|---|
| KX-LIQ | 2,2 + 8 | 8 000 L | 0,5 kW | 700 |
| KX-BOX | 2,4 + 6 | 10 m³ | 0 | 900 |
| KX-ORE | 3,1 + 14 | 6 m³ | 0 | 500 |
| KX-CRY | 3,4 + 4,5 | 6,5 m³ | 6 kW | 1 800 |
| KX-BIO (C2) | 6,8 + 7 | 22 m³ | 9 kW | 3 200 |

**Coques :**

| Coque | À vide | Charge utile max | Énergie | Équipage | Coût (cr) |
|---|---|---|---|---|---|
| HX-S | 18 t | 24 t | 8 kW | 2 | 7 000 |
| HX-M | 34 t | 80 t | 16 kW | 3 | 12 000 |
| HX-L | 46 t | 90 t | 24 kW | 4 | 19 000 |

**Fiche AX-02 (chaîne, étape 9)** : capacité **43,1 m³** · charge 51,0 t · masse **102,5 t** · coût **18 200 cr**.

**Assemblages selon la règle du configurateur** (recalculés depuis `stats.json` pour ce document) :

| AX | Masse | Charge utile / max | Énergie / max | Coût |
|---|---|---|---|---|
| AX-01 | 36,6 t | 18,6 / 24 t | 0,5 / 8 kW | 8 600 cr |
| AX-02 | 102,6 t | 68,6 / 80 t | 12,5 / 16 kW | 18 200 cr |
| AX-03 | 112,6 t | 78,6 / 80 t (98 %) | 0,5 / 16 kW | 14 700 cr |
| AX-04 | 104,4 t | 58,4 / 90 t | 22 / 24 kW | 28 100 cr |

AX-02 pèse 102,6 t selon le configurateur et 102,5 t selon la chaîne : l'écart vient des deux modes de calcul (forfait d'un côté, volume × densité de l'autre). Il est voulu et contrôlé.

Les budgets sont de vraies contraintes de jeu : 6 × ORE sur HX-M (102,6 t de charge) est refusé, tout comme 2 × CRY sur HX-S (12 kW).

## 21. Problèmes connus

| # | Problème | Détail / cause | Piste |
|---|---|---|---|
| 1 | **Le badge du kit affiche « LINT 110/110 »** alors que le vrai chiffre est **119/119** | `viewer/kit/kit.js` lit `kit.lint` dans `viewer/assets/kit/kit.json`, qui embarque `build/kit/lint.json` au moment de sa génération par `src/kit_viewer_assets.py`. Ce `kit.json` date d'avant l'ajout des 9 contrôles du configurateur | Attention : `kit_viewer_assets.py` ne garde les clés `glb`/`tex` que si `build/kit/web/` existe, or ce dossier n'est pas suivi par git. Il faut donc soit lancer `./build-kit.sh` en entier, soit remplacer **seulement** la clé `lint` de `kit.json` par le contenu de `build/kit/lint.json`. Ensuite, livrer un overlay qui ne contient que `factory/assets/kit/kit.json` |
| 2 | **Usure peu visible en vue d'ensemble** | Les niveaux d'usure 1 à 3 du configurateur et l'usure de la chaîne se voient de près, mais très peu à la distance de vue d'ensemble | Plus de contraste ou d'échelle sur les taches et l'écaillage, ou un niveau par défaut plus marqué |
| 3 | **Mémoire Draco (OOM)** : corrigé dans `2700872` | Ouvrir le configurateur depuis la galerie, dans le même onglet, provoquait « RuntimeError: Aborted(out of memory) », parce que 20 vignettes laissaient le worker wasm et les renderers en mémoire | Il faut garder `kgltf.js` (un seul `DRACOLoader`) et appeler `dispose*` à la navigation. Test : `tools/test-kit-nav.mjs` |
| 4 | **Cache navigateur sur `/factory/*`** | Après une mise en ligne, un navigateur qui a déjà visité la page peut garder l'ancien JS | Demander un rechargement forcé (Ctrl+Maj+R). Sinon, versionner les URL des scripts **[piste, non faite]** |
| 5 | **`launcher/scripts/add-factory.sh` est dangereux pour la prod** | Il fait `rm -rf site/factory`, ne recopie que `index.html`, `viewer.*`, `vendor/` et `assets/`, ce qui **effacerait** kit, chaîne, avant-poste, grille et référentiel. En mode `--overlay`, il embarque aussi le `Caddyfile` | Ne pas l'utiliser pour livrer. Il faut des overlays fichier par fichier. À réécrire en mode additif |
| 6 | **OX n'a pas de budget triangles** | `style-outpost.json` n'a pas de `budget`, et `chain_qa` ne contrôle que les 26 objets KX. OA-03 compte 143 872 tris, PX-L 40 234 | Décider d'un plafond OX (question ouverte) |
| 7 | **`build/kit/lint.json` est suivi par git et réécrit par chaque lint** | Le compteur de fichiers scannés par la palette varie (43 → 44 fichiers depuis l'ajout de `kgltf.js`), ce qui laisse un diff parasite | `git checkout build/kit/lint.json` après un lint de vérification, ou committer volontairement |
| 8 | **Dépôt sans remote** | Le dépôt git n'existe que sur la machine de travail du propriétaire | Demander au propriétaire comment accéder au dépôt. À défaut, partir des fichiers publics (§26) |
| 9 | **Incohérence historique d'overlay** | L'overlay du référentiel utilisait le préfixe `factory/…` au lieu de `launcher/site/factory/…` | Toujours utiliser `launcher/site/…` |
| 10 | **Le `viewer/index.html` du dépôt était en retard sur la prod** | Les 5 liens de nav (Configurateur, Variantes, Chaîne, Avant-poste, Kit GX) avaient été ajoutés directement dans la version en ligne. Ils sont réintégrés depuis `8b7432b`. L'accueil est désormais **généré**, il ne faut plus l'éditer à la main | Toujours repartir du fichier en ligne avant de modifier l'accueil |
| 11 | **Carte de normales GX** | Elle contient des teintes cyan-vert (encodage standard) | Exception technique documentée, à ne pas afficher comme art |
| 12 | **Limites V1 et chaîne** | Pas de booléens (ouvertures en saillie) ; le SVG n'est qu'une sortie ; collisions et ancres Godot seulement pour AX-02 ; UV *smart project* peu optimisées | Voir §23 |
| 13 | **Dossiers non suivis** | `build/chain/` et `build/grid/` sont des sorties régénérables, non suivies et non ignorées | Les ajouter au `.gitignore` ou les committer, au choix |

## 22. Journal des décisions

| # | Décision | Justification |
|---|---|---|
| D1 | La **spec JSON** est la source de vérité, et le SVG une sortie | Parser un SVG en 3D est fragile. La spec est lisible, diffable et éditable par une IA |
| D2 | Les **mêmes sommets** servent au SVG et à Blender, avec une triple vérification des cotes | La précision était le but de la V1 : les cotes du plan sont égales aux dimensions du GLB par construction |
| D3 | Projection du 3e dièdre, calques Inkscape, `data-part` | Pour se lire comme un dessin technique et rester inspectable |
| D4 | Repère en m, Z-up, export Y-up, grille colonie de 2 m et socle de 0,30 | Compatibilité avec le kit colonie et Godot |
| D5 | **Aucun vert**, éclairage neutre ou froid | Charte du propriétaire. Corrige aussi le rendu « tout brun » du kit colonie |
| D6 | `habitat_s` passe à 2×2 tuiles | À l'échelle humaine réelle (porte de 2,00, plafond d'environ 2,3 m), il ne tient pas sur 2 × 2 m |
| D7 | Charte **mesurée** et composants communs, vérifiés par un lint (KX) | Faire **ressembler** des objets différents par construction, pas à l'œil |
| D8 | Coques à **slots vides** ; assemblage = **données** | Séparer le contenant du contenu, réutiliser les GLB et composer côté client |
| D9 | Filaire côté client, Draco + JPEG, occlusion des SVG | Serveur à 2 vCPU sans GPU : poids divisé, rendu identique |
| D10 | Les rendus Blender priment quand le rendu IA dévie | Fidélité au référentiel (vue éclatée, slots vides) |
| D11 | OX **étend** KX sans copier ; la couleur dépend de la **famille** | Si KX change, OX suit. Aucune nouvelle couleur |
| D12 | GX : g = U/2, **méthode A**, B seulement pour 8 directions, G4 pour le lointain et les icônes | Comparaison mesurée : A donne un pixel exact, B′ lisse donne 0 % |
| D13 | Brief → spec **sans IA**, par règles fixes | Déterminisme et vérification brief ≡ spec |
| D14 | Densités choisies pour retrouver les charges du configurateur | Un seul jeu de chiffres gameplay, avec un écart ≤ 0,37 % |
| D15 | Variantes avec `generate(seed)` mulberry32, et correction plutôt que rejet | Reproductibilité, et 100 % des variantes valides |
| D16 | Un seul `DRACOLoader` partagé, `dispose` à la navigation | Correctif de l'OOM galerie → configurateur |
| D17 | Déploiement par **overlays** appliqués par un opérateur, jamais par le `build-site.sh` complet ni par le `Caddyfile` | Les builds de POC manquent, donc le build complet échoue. Il faut aussi isoler les risques et garder des sauvegardes côté opérateur |
| D18 | Godot 4.7.2 comme moteur cible, Unreal exclu | Décision du propriétaire (« oublie Unreal Engine ») |
| D19 | Le handoff vit **sur la page publique** (`handoff.md`, `llms.txt`, `context.json`) | Demande du propriétaire : l'agent entrant reçoit `/factory/` comme point d'entrée |

## 23. Questions ouvertes et prochaines étapes

**Questions ouvertes** (à trancher avec le propriétaire) :

1. Quel jeu consomme les kits ? Deep City (2D vue de dessus), un *colony builder*, un jeu spatial ? **[non décidé]**
2. Faut-il retenir la 3D ou le pixel art ? GX reste une exploration, et le verdict A ne porte que sur la méthode de rendu.
3. Quel budget de triangles pour OX (OA-03 à 143 872) ?
4. Faut-il une édition inverse (SVG annoté → patch de spec) ou un éditeur web de spec avec aperçu SVG en direct ?
5. Faut-il étendre la chaîne en 9 étapes à tous les AX, aux OA, et à GX ?
6. Comment l'agent entrant accède-t-il au dépôt (remote) ?

**Prochaines étapes suggérées**, triées du moins cher au plus cher :

1. Corriger le badge LINT du kit (régénérer `kit.json`, overlay d'un fichier).
2. Rendre l'usure lisible en vue d'ensemble.
3. Rendre `add-factory.sh` additif, sans `rm -rf` ni `Caddyfile`, ou le marquer « dev seulement ».
4. Versionner les URL des JS des visionneuses pour éviter les problèmes de cache.
5. Ajouter un budget OX et le contrôler dans `ox_lint`.
6. Généraliser l'export Godot `.tscn` (collisions, ancres Marker3D) aux 4 AX et 3 OA.
7. GX : retoucher les 8 directions B, étendre GX à OX (bâtiments voxel), viser des sprites plus petits en G4.
8. Ajouter des booléens (ouvertures percées), des LOD, et des UV mieux dépliées que le *smart project*.
9. Migrer le reste du kit colonie (23 bâtiments `poc-blender`) spec par spec.

## 24. Conventions de travail pour un agent

- **Langue :** tout en français (UI, docs, commits), sur un ton direct et technique.
- **Commits :**
  - préfixe du périmètre, puis un résumé dense avec les chiffres vérifiés (lint, tests, compteurs) ;
  - corps du message : la cause et le correctif.
  - Exemples réels :
    - « Kit KX : configurateur (…) ; stats.json, lint 119/119, test 28/28 » ;
    - « Kit KX/OX : libérer Draco et le contexte WebGL avant de quitter la page ».
  - Un jalon par commit. Ne pas committer de secrets ni de chemins de clés.
- **Avant de modifier une page publiée :** repartir du fichier **en ligne**, qui peut différer du dépôt (voir §21 n°10).
- **Livraison par overlay :**
  1. Construire une archive `launcher-factory-<sujet>-overlay.tar.gz` dont tous les chemins commencent par `launcher/site/…` (par exemple `launcher/site/factory/kit/index.html`).
  2. N'y mettre que des fichiers **ajoutés ou remplacés** : pas de suppression, pas de dossier entier qui écraserait un voisin, pas de `Caddyfile`, pas de `games.json` sans accord.
  3. Indiquer la taille en octets, le sha256 et la liste exacte des fichiers.
  4. Un **opérateur** vérifie le sha256, sauvegarde les fichiers remplacés, extrait l'archive en se limitant à `site/factory` et teste les URL publiques.
  5. Après la fusion, revérifier soi-même chaque URL (HTTP 200, type MIME) si le réseau le permet.
- **Vérifier chaque affirmation :**
  - lancer le lint du kit touché, le test Playwright de la page touchée et `chain_qa` si les chiffres gameplay ou les budgets bougent ;
  - un chiffre cité doit sortir d'un fichier ou d'une commande.
- **Documenter chaque étape :** README du kit, planche ou capture dans `docs/`, et mise à jour de ce handoff : éditer `viewer/handoff.md`, puis lancer `python3 src/handoff/build_context.py`, qui réécrit `context.json` **et** `index.html`.
- **Nommage :**
  - ids en minuscules : `mod_*`, `hull_*`, `asm_*`, `cmp_*`, `bld_*`, `plot_*`, `oa_*`, `oxc_*`, `gmod_*`, `ghull_*`, `gasm_*`, `gx_*` ;
  - codes en majuscules : `KX-LIQ`, `HX-M`, `AX-02`, `OX-HAB`, `PX-M`, `OA-02`, `GX-LIQ`, `GH-M`, `GA-02`.
- **Parallélisme :** plusieurs agents ont déjà travaillé en même temps dans ce dépôt. Ne touchez pas aux fichiers partagés (`factory/index.html`, `kit.json`) sans les relire juste avant, et fusionnez à la main.

## 25. Contexte : Deep City

Ce projet est distinct de la factory et n'est donné ici que comme contexte. Deep City est un hybride action-RPG en vue de dessus et jeu de gestion : un donjon (ennemis, coffres, loot) et une ville (étal de marché, vente). La version de référence est en **Godot 4.7.2** (GL Compatibility, export web sans threads), avec du pixel art procédural sans vert.

| Version | Lien | Commit | Contenu |
|---|---|---|---|
| v0.1 MVP | [/play/deep-city/](https://kg.g.caute.re/play/deep-city/) | `60d370a` | Marché du Puits, donjon Les Profondeurs, loot et vente, pierre ancienne et 3 cinématiques (météore, dragon, séisme) |
| v0.2 | [/play/deep-city-v2/](https://kg.g.caute.re/play/deep-city-v2/) | `244c82e` | 3 étages (Profondeurs, Galeries, Cœur de pierre), 10 nouvelles créatures, loot par étage |
| v0.3 « Deep Colony : Kepler-Ombre » | [/play/deep-city-v3/](https://kg.g.caute.re/play/deep-city-v3/) | `6eb99f4` | Reskin sur planète alien : ciel violet, deux soleils, faune bioluminescente, 3 biomes, jauge d'O₂ et poches d'air, comptoir à 3 marchands, monolithe xéno |

- Des portages du MVP existent en Love2D, Raylib, Phaser et Canvas TypeScript.
- Tests du jeu : playtests headless Godot (`DC_TEST`, `DC_TEST=floors`, `DC_TEST=v3`) et captures (`DC_SHOTS`).
- **Lien avec la factory :** aucune intégration n'est faite à ce jour. Les kits visent l'export Godot (`.tscn`), et le pixel art GX pourrait servir un jeu 2D comme Deep City **[hypothèse, non décidé]**.

## 26. Données publiques lisibles par machine

Tout ceci est servi sous `https://kg.g.caute.re/factory/` et peut remplacer l'accès au dépôt pour se faire une idée :

| URL | Contenu |
|---|---|
| `context.json` | Inventaire de ce handoff : kits, objets, chemins des specs, URL, commits, métriques, problèmes |
| `chain/artifacts/style-kit.json` | Charte KX complète, avec budgets et gameplay |
| `chain/artifacts/asm_mixte.json`, `hull_m.json`, `ax02-mixte.brief.txt`, `ax02-mixte.spec.json` | Spec AX-02, coque, brief et spec générée |
| `chain/artifacts/asm_mixte.gameplay.json`, `asm_mixte.tscn`, `qa_report.txt`, `kit_lint.txt`, `id_legend.json`, `wear_seed.json` | Sorties des étapes 6 à 9 |
| `assets/kit/kit.json` | Catalogue KX (style, objets, triangles, lint, avec le badge en retard) |
| `assets/kit/config.json` | Stats, presets AX, coûts, ancres d'habillage |
| `outpost/data/ox.json` | Catalogue OX (style OX et KX, objets, triangles, lint) |
| `assets/grid/grid.json`, `assets/grid/gx_palette.gpl`, `gx_palette.hex` | Catalogue GX, spec et palette |
| `assets/buildings.json` | Bâtiments V1 |
| `assets/kit/models/`, `outpost/data/models/`, `assets/models/` | GLB (Draco pour les kits) |
| `assets/kit/svg/`, `outpost/data/svg/`, `assets/plans/` | Planches SVG |

## 27. Ce qui n'a pas pu être confirmé

- Le contenu exact de la liste d'« idées de décomposition et d'étapes » donnée au propriétaire le 10/11 n'est pas reproduit ici. On sait seulement que le configurateur, la galerie et la chaîne en 9 étapes en sont issus.
- Avant de rédiger, l'accueil en ligne a été relu en HTTPS : il est identique à la base utilisée. Toutes les URL publiques citées ici ont répondu 200 le 10/11 au soir, sauf `handoff.md`, `llms.txt` et `context.json`, qui attendaient leur overlay. Le contenu des autres sous-pages n'a pas été comparé octet par octet avec le dépôt. Les tests locaux tournent sur une reconstitution, c'est-à-dire les overlays appliqués dans l'ordre.
- Le correctif du badge (§21 n°1) n'a pas été appliqué ni testé. Seule la cause a été vérifiée dans le code.
- Le défaut d'usure peu visible à distance (§21 n°2) a été constaté pendant les travaux, mais n'a pas été mesuré.
