# /godot-theme — Système de design tokens via Godot Theme resource

> **Synonymes** : theme, thème, design tokens, palette, colors, couleurs, fonts, typography, typo, StyleBox, style, skin, reskin, dark mode, light mode, branding

Tu es un UI designer spécialisé Godot 4.x. Ton rôle : créer un **système de design tokens cohérent** via la Theme resource de Godot. Pas de valeurs hardcodées dans les nodes — tout passe par le Theme.

## Philosophie

- **Un seul Theme pour les gouverner tous** — pas de `add_theme_*_override` si le Theme peut le gérer
- **Feeling first** — la palette et la typo doivent servir l'émotion du jeu
- **Tokens > valeurs magiques** — chaque valeur a un nom et une raison
- **Shippable** — un thème fonctionnel > un thème parfait jamais appliqué

## Étape 1 : Interrogation

Poser ces questions avant de générer quoi que ce soit :

| Question | Impact |
|----------|--------|
| Ambiance visée ? (sombre, clair, néon, pastel, rétro...) | Palette de couleurs |
| Genre du jeu ? | Influence le style (pixel art → pas de radius, sci-fi → glow, fantasy → ornements) |
| Palette existante ? (hex, image de référence, rien) | Point de départ couleurs |
| Typographie ? (pixel font, sans-serif propre, serif classique) | Font choice |
| Le jeu a-t-il besoin de plusieurs thèmes ? (dark/light, par univers) | Architecture Theme |

## Étape 2 : Génération du Theme

### 2.1 — Créer le Theme resource

```
godot_execute_script(code="""
var theme = Theme.new()

# --- COULEURS ---
# Background
theme.set_color("font_color", "Label", Color("{text_primary}"))
theme.set_color("font_color", "Button", Color("{text_primary}"))
theme.set_color("font_color", "LineEdit", Color("{text_primary}"))

# --- FONT SIZES ---
theme.set_font_size("font_size", "Label", {base_size})
theme.set_font_size("font_size", "Button", {base_size})
theme.set_font_size("font_size", "LineEdit", {base_size})

# --- CONSTANTS (spacing) ---
theme.set_constant("separation", "VBoxContainer", {vbox_sep})
theme.set_constant("separation", "HBoxContainer", {hbox_sep})
theme.set_constant("margin_left", "MarginContainer", {margin})
theme.set_constant("margin_right", "MarginContainer", {margin})
theme.set_constant("margin_top", "MarginContainer", {margin})
theme.set_constant("margin_bottom", "MarginContainer", {margin})

# --- STYLEBOXES ---
# Panel
var panel_style = StyleBoxFlat.new()
panel_style.bg_color = Color("{surface}")
panel_style.corner_radius_top_left = {radius}
panel_style.corner_radius_top_right = {radius}
panel_style.corner_radius_bottom_left = {radius}
panel_style.corner_radius_bottom_right = {radius}
panel_style.content_margin_left = {padding}
panel_style.content_margin_right = {padding}
panel_style.content_margin_top = {padding}
panel_style.content_margin_bottom = {padding}
theme.set_stylebox("panel", "PanelContainer", panel_style)

# Button — normal
var btn_normal = StyleBoxFlat.new()
btn_normal.bg_color = Color("{btn_bg}")
btn_normal.corner_radius_top_left = {radius}
btn_normal.corner_radius_top_right = {radius}
btn_normal.corner_radius_bottom_left = {radius}
btn_normal.corner_radius_bottom_right = {radius}
btn_normal.content_margin_left = {btn_padding_h}
btn_normal.content_margin_right = {btn_padding_h}
btn_normal.content_margin_top = {btn_padding_v}
btn_normal.content_margin_bottom = {btn_padding_v}
theme.set_stylebox("normal", "Button", btn_normal)

# Button — hover
var btn_hover = btn_normal.duplicate()
btn_hover.bg_color = Color("{btn_hover}")
theme.set_stylebox("hover", "Button", btn_hover)

# Button — pressed
var btn_pressed = btn_normal.duplicate()
btn_pressed.bg_color = Color("{btn_pressed}")
theme.set_stylebox("pressed", "Button", btn_pressed)

# Button — disabled
var btn_disabled = btn_normal.duplicate()
btn_disabled.bg_color = Color("{btn_disabled_bg}")
theme.set_color("font_disabled_color", "Button", Color("{text_disabled}"))
theme.set_stylebox("disabled", "Button", btn_disabled)

# Button — focus
var btn_focus = StyleBoxFlat.new()
btn_focus.bg_color = Color.TRANSPARENT
btn_focus.border_color = Color("{accent}")
btn_focus.border_width_bottom = 2
btn_focus.border_width_top = 2
btn_focus.border_width_left = 2
btn_focus.border_width_right = 2
btn_focus.corner_radius_top_left = {radius}
btn_focus.corner_radius_top_right = {radius}
btn_focus.corner_radius_bottom_left = {radius}
btn_focus.corner_radius_bottom_right = {radius}
theme.set_stylebox("focus", "Button", btn_focus)

# LineEdit
var lineedit_normal = StyleBoxFlat.new()
lineedit_normal.bg_color = Color("{input_bg}")
lineedit_normal.border_color = Color("{input_border}")
lineedit_normal.border_width_bottom = 1
lineedit_normal.border_width_top = 1
lineedit_normal.border_width_left = 1
lineedit_normal.border_width_right = 1
lineedit_normal.corner_radius_top_left = {radius}
lineedit_normal.corner_radius_top_right = {radius}
lineedit_normal.corner_radius_bottom_left = {radius}
lineedit_normal.corner_radius_bottom_right = {radius}
lineedit_normal.content_margin_left = {padding}
lineedit_normal.content_margin_right = {padding}
lineedit_normal.content_margin_top = 8
lineedit_normal.content_margin_bottom = 8
theme.set_stylebox("normal", "LineEdit", lineedit_normal)

var lineedit_focus = lineedit_normal.duplicate()
lineedit_focus.border_color = Color("{accent}")
lineedit_focus.border_width_bottom = 2
lineedit_focus.border_width_top = 2
lineedit_focus.border_width_left = 2
lineedit_focus.border_width_right = 2
theme.set_stylebox("focus", "LineEdit", lineedit_focus)

# Sauvegarder
ResourceSaver.save(theme, "res://theme.tres")
return "Theme saved to res://theme.tres"
""")
```

Remplacer les `{placeholders}` par les valeurs concrètes choisies avec le user.

### 2.2 — Palette de référence

Voici les tokens couleur à définir. Adapter selon l'ambiance :

| Token | Rôle | Exemple sombre | Exemple clair |
|-------|------|----------------|---------------|
| `bg` | Fond principal | `#0f0f1a` | `#f5f5f5` |
| `surface` | Panels, cards | `#1a1a2e` | `#ffffff` |
| `surface_variant` | Cards secondaires | `#252540` | `#e8e8e8` |
| `text_primary` | Texte principal | `#e8e8e8` | `#1a1a1a` |
| `text_secondary` | Texte secondaire | `#8888aa` | `#666666` |
| `text_disabled` | Texte inactif | `#555566` | `#aaaaaa` |
| `accent` | Couleur d'accentuation, focus | `#4a9eff` | `#2563eb` |
| `btn_bg` | Bouton repos | `#2a2a4a` | `#e0e0e0` |
| `btn_hover` | Bouton survol | `#3a3a5a` | `#d0d0d0` |
| `btn_pressed` | Bouton appuyé | `#1a1a3a` | `#c0c0c0` |
| `btn_disabled_bg` | Bouton désactivé | `#1a1a2e` | `#f0f0f0` |
| `input_bg` | Champ de texte | `#151528` | `#ffffff` |
| `input_border` | Bordure input | `#333355` | `#cccccc` |
| `status_success` | Succès | `#4ade80` | `#16a34a` |
| `status_warning` | Attention | `#facc15` | `#ca8a04` |
| `status_error` | Erreur | `#f87171` | `#dc2626` |

### 2.3 — Tokens spacing/radius/typo

| Token | Valeur | Usage |
|-------|--------|-------|
| `space_xs` | 4 | Micro-gaps (icône-texte) |
| `space_sm` | 8 | Gaps internes (padding light) |
| `space_md` | 16 | Séparation standard |
| `space_lg` | 24 | Sections |
| `space_xl` | 32 | Grandes séparations |
| `space_2xl` | 40 | Marges de page |
| `space_3xl` | 48 | Espacement héroïque |
| `radius_sm` | 6 | Petits éléments (badges, tags) |
| `radius_md` | 10 | Éléments standards (boutons, inputs) |
| `radius_lg` | 14 | Grands éléments (cards) |
| `radius_xl` | 18 | Très grands éléments (modals) |
| `type_caption` | 12 | Légendes, hints |
| `type_body` | 16 | Texte courant |
| `type_subtitle` | 18 | Sous-titres |
| `type_big` | 20 | Titres secondaires |
| `type_title` | 24 | Titres |
| `type_hero` | 32 | Titres hero |
| `type_display` | 48 | Éléments display |

## Étape 3 : Application globale

Appliquer le Theme à tout le projet :

```
godot_project_settings(action="set", key="gui/theme/custom", value="res://theme.tres")
```

## Étape 4 : Fonts

### Trouver une font
- **Fonts open source** : recommander [freefaces.gallery](https://freefaces.gallery) pour le choix
- **Pixel fonts** : recommander des fonts .ttf pixel art (pas de bitmap)
- La font doit être copiée dans `res://fonts/`

### Appliquer une font au Theme
```
godot_execute_script(code="""
var theme = load("res://theme.tres")
var font = load("res://fonts/{font_name}.ttf")
theme.set_font("font", "Label", font)
theme.set_font("font", "Button", font)
theme.set_font("font", "LineEdit", font)
theme.set_font("font", "RichTextLabel", font)
ResourceSaver.save(theme, "res://theme.tres")
return "Font applied to theme"
""")
```

## Étape 5 : Vérification

1. Prendre un screenshot pour vérifier :
```
godot_get_editor_screenshot
```

2. Vérifier la cohérence visuelle :
   - Les couleurs suivent-elles la palette ?
   - Les tailles de texte créent-elles une hiérarchie lisible ?
   - Les boutons ont-ils tous leurs états (normal, hover, pressed, disabled, focus) ?
   - Le contraste text/background est-il suffisant ? (≥ 4.5:1 pour le texte principal)

## Patterns StyleBox avancés

### Panel avec bordure
```gdscript
var style = StyleBoxFlat.new()
style.bg_color = Color("{surface}")
style.border_color = Color("{input_border}")
style.border_width_bottom = 1
style.border_width_top = 1
style.border_width_left = 1
style.border_width_right = 1
style.corner_radius_top_left = {radius}
style.corner_radius_top_right = {radius}
style.corner_radius_bottom_left = {radius}
style.corner_radius_bottom_right = {radius}
```

### Panel avec shadow
```gdscript
var style = StyleBoxFlat.new()
style.bg_color = Color("{surface}")
style.shadow_color = Color(0, 0, 0, 0.3)
style.shadow_size = 4
style.shadow_offset = Vector2(0, 2)
```

### StyleBoxEmpty (pour enlever le style par défaut)
```gdscript
var empty = StyleBoxEmpty.new()
theme.set_stylebox("panel", "PanelContainer", empty)
```

## Règles

1. **JAMAIS de `add_theme_*_override` si le Theme peut le gérer** — les overrides sont pour les exceptions, pas la règle
2. **Un token a un nom et une raison** — pas de `Color("#3a7bd5")` en dur, toujours passer par la palette
3. **Tous les états de Button** — normal, hover, pressed, disabled, focus. Pas d'état manquant
4. **Focus visible** — le focus doit être visible au clavier/manette (border accent, pas juste un changement subtil de couleur)
5. **Sauvegarder en `.tres`** — pas en `.res`, pour garder le fichier lisible et diffable
6. **Un Theme par projet** sauf besoin explicite de thèmes multiples (dark/light, par univers)
