# 0012 — Sites de plongée en champ de hauteur authoré - Statut : accepté - Date : 2026-10-06 - Remplace : aucun ## Contexte Le seul terrain de production est une formule analytique codée dans `vehicle_test_environment.gd`. La tranche 3 exige un site conçu à la main, lisible au sonar (ADR 0010 : surface unique), avec une route sûre et une route risquée, et le sonar a besoin de distinguer roche et sable par cellule, pas par corps. Il faut un contrat de données pour le terrain, son stockage dans le dépôt et sa production. ## Décision 1. Un site de plongée est décrit par une ressource typée `DiveSiteDefinition` (`game/domain/sites/`) : identifiant, terrain, limites jouables, point de départ, placements d'objets et routes de contrôle. 2. Le terrain est un champ de hauteur à surface unique `SiteTerrainData` : grille régulière de `columns × rows` cellules de `cell_size_m` mètres, élévations en mètres (axe Y monde, négatif sous la surface) dans un `PackedFloat32Array`, matériau sonar par cellule dans un `PackedByteArray` (`SonarMaterial.Value`, ROCK ou SAND). Repère : +X est, +Z sud, +Y haut ; la colonne croît avec +X, la ligne avec +Z ; la cellule `(0, 0)` est à `(origin_x_m, origin_z_m)`. 3. Les données sont cuites hors exécution par `tools/bake_site_terrain.gd` à partir d'une recette déclarative de primitives géomorphologiques nommées (plateau, crête, piton, sillon, rupture de pente, rides, rugosité déterministe par graine). La recette est le document d'auteur versionné ; le résultat est écrit en `.res` binaire sous `content/sites/`. Le jeu ne génère jamais de terrain à l'exécution. `tools/` dépend du domaine (`game/domain/`) et de rien d'autre ; aucun code sous `game/` ou `content/` ne dépend de `tools/`, ce que la barrière d'architecture vérifie. 4. Un PNG 16 bits n'est pas utilisé pour les hauteurs : le chargeur d'images de Godot ramène les PNG 16 bits en 8 bits, soit des marches de 0,27 m sur 68 m de dénivelé. Un PNG 8 bits de prévisualisation est produit pour la revue humaine seulement. 5. Un seul acteur de monde, `BathymetricTerrainActor`, construit le maillage visuel et la `HeightMapShape3D` depuis le même champ ; un test compare les deux. Il expose `sonar_material_at(position)` et `sonar_reflectivity_at(position)` que l'acquisition sonar privilégie sur les métadonnées de corps. 6. Les limites de la zone jouable sont une règle applicative (`PlayableBoundsRule`) qui produit un avertissement ; elles ne sont jamais un mur de terrain (ADR 0010). ## Conséquences - L'environnement de test du véhicule devient une définition de site cuite, sans formule analytique dans `game/`. - Toute modification de terrain passe par la recette puis une cuisson ; les fichiers `.res` sont des artefacts dérivés mais versionnés pour que le chargement du site reste sous 3 s et que le jeu n'ait pas besoin de l'outil. - Les tests de contrat de contenu peuvent vérifier profondeur, position et dégagement des placements contre le champ de hauteur réel. - Une sculpture manuelle (Blender) ultérieure devra ré-exporter vers le même `SiteTerrainData` ; le contrat ne change pas. ## Alternatives considérées - **Plugin de terrain externe** : rejeté, dépendance et ADR supplémentaires sans besoin démontré ; une heightmap tuilée suffit à la V1. - **Génération à l'exécution depuis la recette** : rejeté, le plan impose un site conçu à la main et un chargement borné ; la cuisson garantit un artefact figé et revu. - **Heightmap PNG 16 bits** : rejeté pour la raison de précision ci-dessus. - **Maillage sculpté sans champ de hauteur** : rejeté, le sonar et les tests ont besoin d'une requête de hauteur et de matériau par position.