# GAB-382 · MediaLearningImageViewer — « Visionneuse image »

**Archétype / renderer_key :** `media_viewer` (cartographie) · **module :** EdTechMediaLearning
**Note :** renderer_key `media_viewer` — pas de moteur kit de référence ; renderer conçu à partir de l'écran source lui-même (INDEX-300-medialearning-GAB-381-385-PLAYABLE.html, stage data-tpl="382").
**Critère validé :** changer le JSON change le rendu sans modifier le HTML. check.py 12/12.

## Pack (structure officielle par-GAB)
```
GAB-382/
  renderer.html            ← moteur visionneuse image (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` · `image_viewer_id` · `alt_text` · `source_rights` · `useful_zones[]{zone_id,label,annotation,position}`

Optionnels : `image_src`, `image_placeholder_emoji`, `caption`, `zoom_enabled`, `fallback`.

## Ce qui vient du JSON vs HTML
- **JSON** : emoji ou URL de l'image, texte alternatif, légende, droits/source, chaque zone annotée (label + annotation + position CSS), activation du zoom.
- **HTML** : scène image, zones cliquables, boutons Zoom/Texte alternatif, panel feedback, slots.

## Garde-fous (accessibility / child_safety)
- **alt_text obligatoire** : aucune image affichée sans description lisible par lecteur d'écran.
- **source_rights obligatoire** : jamais afficher une image sans mention de droits (prévention violation droits d'auteur en contexte scolaire).
- **useful_zones non vide** : au moins 1 zone annotée — garantit la dimension pédagogique active.
- **BLOCKED** si `alt_text` absent, `source_rights` absent, ou `useful_zones` vide.
- **_TODO** : `image_src` porte `_TODO:url_image_reelle` — l'URL réelle doit être fournie avant déploiement pédagogique.

## QA à vérifier
1. Modifier `alt_text` / `annotation` d'une zone → rendu change sans toucher au HTML (critère d'or).
2. `useful_zones:[]` → BLOCKED propre.
3. `alt_text` absent → BLOCKED propre.
4. `source_rights` absent → BLOCKED propre.
5. Clic zone → panel affiche l'annotation correspondante.
6. Bouton Zoom → toggle scale(1.25) / scale(1) sur la scène.
7. Bouton Texte alternatif → panel affiche alt_text.
8. `zoom_enabled:false` → bouton zoom masqué.
9. Instance externe injectée via `ENGINE.init(ext)` → rendu change sans modifier le HTML.
10. Responsive 375/768/1024 — aucun débordement.

## _TODO / Contenus manquants
- `image_src` : URL de l'image réelle non présente dans le HTML source (placeholder emoji 🏛️ dans la démo). Valeur : `_TODO:url_image_reelle`.

## Source
`INDEX-300-medialearning-GAB-381-385-PLAYABLE.html` (stage `data-tpl="382"`, handlers `d382Zoom`, `d382Annot`, `d382Alt`).
