# DECISIONS.md — ubud-map

Carte 3D interactive d'Ubud (Bali) dans le navigateur. Construit en autonomie le
12/09/2026 ; ce fichier liste tout ce qui a été décidé sans validation, et pourquoi.
Consultable en ligne : https://ubud.gilbertval.fr/decisions.html

## DNS — correction faite à ta place

L'enregistrement `A ubud → 137.74.117.10` avait été créé **chez le registrar
(hosting.fr)**, mais la zone `gilbertval.fr` est déléguée à **Cloudflare**
(NS carrera/hunts) : cet enregistrement était donc inerte, `ubud.gilbertval.fr`
ne résolvait pas. Le token API Cloudflare déjà présent sur le VPS
(`/etc/letsencrypt/cloudflare-tp2025.ini`, même compte Cloudflare) avait accès à
la zone → **j'ai créé l'enregistrement A directement dans Cloudflare** (DNS only,
non proxifié, commentaire « ubud 3D map (created by Claude Code) »). L'entrée
côté hosting.fr peut être supprimée, elle ne sert à rien.

## Architecture

- **Site 100 % statique, aucun service systemd, aucun port** : three.js tourne
  dans le navigateur, nginx sert `~/projects/ubud-map/public/`. C'est le même
  modèle que `michel` ou `poc-profil` — rien à maintenir, rien à redémarrer.
- **Pipeline données en 2 temps** : `data/ubud_raw.json` = cache brut Overpass
  (4,2 Mo, re-téléchargeable) → `scripts/build_data.py` (Python stdlib) →
  `public/data/ubud.json` compact (0,7 Mo) consommé par le front. Pour rafraîchir
  la ville : relancer le `curl` Overpass (requête dans
  `scripts/overpass_query.txt`) puis `python3 scripts/build_data.py`.
- **three.js r169 vendorisé** (`public/vendor/`, avec OrbitControls et
  BufferGeometryUtils) : pas de CDN, pas de build step, pas de npm. ES modules +
  importmap natif.
- **Accès public, sans auth** : c'est une démo sous ton domaine perso (comme
  gilbertval.fr), rien de sensible. `noindex` posé quand même.

## Données OpenStreetMap

- **Zone** : bbox ~3,4 × 3,6 km centrée sur Ubud (−8.523→−8.492 / 115.245→115.278),
  du Campuhan Ridge au Monkey Forest. Récupéré : **5 583 bâtiments** (dont 1 600
  avec hauteur ou étages réels), 1 365 routes, 84 rivières/canaux, 73 zones
  vertes, 7 plans d'eau.
- **Hauteurs** : tag `height` si présent, sinon `building:levels` × 3,2 m,
  sinon une hauteur par type (maison 4,5 m, hôtel 9 m, temple 7 m…) avec une
  variation pseudo-aléatoire **stable** (seedée par l'id OSM → le rendu est
  identique à chaque rebuild).
- **Multipolygones** : seul l'anneau extérieur est extrudé (les cours
  intérieures sont ignorées — négligeable visuellement à cette échelle).
- **Terrain plat** : Ubud a des gorges marquées mais intégrer un MNT (SRTM)
  aurait doublé la complexité pour un gain incertain au niveau de détail d'une
  ville en extrusion. Décision : sol plat, les rivières dessinées au sol
  suggèrent le relief. Évolution possible plus tard.

## Rendu

- **Un seul draw call par famille** : tous les murs fusionnés en un mesh, tous
  les toits en un autre (couleurs par sommet), routes/rivières/verdure fusionnées
  par classe. ~15 draw calls au total pour la ville → fluide même sur mobile.
- **Toits ≠ murs** : l'ExtrudeGeometry de three.js sépare les faces (groupe 0 =
  couvercles, groupe 1 = flancs) ; j'exploite ça pour colorer les toits en tuile/
  chaume balinais (bruns-rouges, temples en chaume sombre) et les murs en enduits
  clairs. Palette par type de bâtiment (maison / hôtel / commerce / temple).
- **Cycle jour-nuit** : 12 images-clés (couleurs ciel/soleil/brouillard/
  exposition) interpolées sur 24 h. Le soleil suit une course quasi zénithale
  (Bali ≈ équateur), les ombres portées (PCF 2048) suivent. Ciel = dôme shader
  (dégradé + disque et halo solaires), 900 étoiles la nuit.
- **Fenêtres allumées la nuit** : ~20 000 points additifs (sprite radial généré
  en canvas) posés sur les façades, ~42 % des emplacements « habités » (seedé,
  stable). Un vrai plan de fenêtres par bâtiment aurait explosé le budget
  géométrie pour rien.
- **Curseur temps** : slider 0-24 h au pas de 3 min, presets (aube / midi / fin
  d'après-midi / coucher / nuit) + bouton **Cycle** (journée complète en 75 s).
- Correctif notable en cours de route : les rubans routes/rivières étaient
  invisibles puis noirs (winding + normales) → indices retriangulés + matériaux
  `DoubleSide`.

## Exposition

- vhost nginx `ubud.gilbertval.fr` → root statique, gzip, cache long sur
  `vendor/` et `data/` ; certificat Let's Encrypt via `certbot --nginx`
  (HTTP-01, pas besoin du plugin Cloudflare puisque l'A est non proxifié).
- `DECISIONS.md` est rendu en page web (`decisions.html`, générée à la main) et
  le fichier brut est aussi servi tel quel (`/DECISIONS.md`).
