# GAB-040 · XPGainAnimation — « Animation de gain XP »

**Archétype / renderer_key :** `text_cta` (cartographie) · **module :** EdTechPlayKit
**Critère validé :** changer le JSON change l'animation sans modifier le HTML. ✅ check.py 12/12.

## Pack (structure officielle par-GAB)
```
GAB-040/
  renderer.html            ← moteur animation XP (ne pas modifier par instance)
  instance.example.json    ← SOURCE DE VÉRITÉ (contenu réel, à plat)
  schema.contract.json     ← contrat de validation
  README-contract.md       ← ce fichier
```

## Champs requis (instance, à plat)
`gab_id` · `xp_gain_id` · `xp_gained` · `level_label` · `xp_after` · `xp_max`

Optionnels : `context_note`, `xp_icon`, `xp_before`, `replay_cta_label`, `footer_note`.

## Ce qui vient du JSON vs HTML
- **JSON** : points gagnés, libellé du niveau, valeurs avant/après, seuil de niveau, icône, libellé du CTA replay, note pédagogique, note de bas de page.
- **HTML** : badge animé (keyframe xp-pop), barre de progression, bouton replay, layout, fallback BLOCKED.

## Archétype
GAB-040 est un gabarit **read-only / display-only** de la famille PlayKit : il reçoit un XP déjà calculé et l'anime. Il n'écrit, ne calcule et ne valide aucun score.

Règle d'or : *PlayKit affiche · GamificationAdapter calcule et écrit.*

## Garde-fous (child_safety)
- **Anti-calcul** : `xp_gained` est fourni par GamificationAdapter en entrée — le renderer ne fait aucune arithmetic.
- **BLOCKED** si `xp_gained` absent/non-numérique, `level_label` absent, `xp_after` absent, `xp_max` absent.
- **Replay** : le bouton « Rejouer le gain XP » ne re-déclenche que l'animation visuelle, pas une écriture en base.
- **prefers-reduced-motion** : animations tronquées à 0.01ms si l'utilisateur préfère.

## QA à vérifier
1. Modifier `xp_gained` → badge affiche la nouvelle valeur sans toucher au HTML.
2. Modifier `xp_after` / `xp_max` → barre se positionne correctement.
3. `xp_gained` absent → BLOCKED propre dans la zone d'affichage.
4. Bouton replay → badge pop + barre animée depuis `xp_before` vers `xp_after`.
5. Responsive 375/768/1024.

## Dépendances externes (external_refs / dependencies)
- **GamificationAdapter** (module EdTechPlayKit) : fournit `xp_gained`, `xp_before`, `xp_after`, `xp_max`, `level_label` avant d'appeler ce renderer.
- Gabarits voisins : `GAB-039` (streak inline, lecture seule) · `GAB-038` (replay) · `GAB-036` (warning).
- Gabarits exclus : calcul/attribution XP → GamificationAdapter ; badge débloqué → KIT BadgeUnlock ; streak → GAB-039.

## Source
`INDEX-300-playkit-GAB-036-040-PLAYABLE.html` (stage `data-tpl="40"`, handler `xpFire()`).
