# Simulateurs interactifs (plugins) Bibliothèque de simulateurs pédagogiques pour les **pages interactives** (`/p/{slug}`). L'IA ne code jamais une simulation : elle **choisit** un simulateur de cette liste et le **configure** (`preset` = valeurs de la note), ou utilise `generic-formula` si aucun ne correspond au sujet. ## Liste des simulateurs disponibles | `simId` | Famille | Sujet | Interaction | |---|---|---|---| | `carnot-cycle` | `sim` | Machine frigorifique / PAC / moteur de Carnot (2ᵉ principe) | Curseurs T_c, T_h, Q_c → COP, η, W min, Q_h en direct | | `carnot-cycle-anim` | `anim` | Cycle de Carnot animé (piston + diagramme P–V live, 5 étapes) | Play / Pause / Step / Reset / vitesse + narration | | `generic-formula` | `sim` | (générique) toute relation chiffrée y = f(paramètres) | Curseurs définis par l'IA, expressions sûres (aucun `eval`) | Deux familles de plugins : `sim` (manipulation de paramètres, calcul en direct) et `anim` (scène animée codée en dur, pilotée par le player Play/Step — narration par battements). Les deux sont choisis par l'IA via le même bloc `{ "type": "sim" }`. ## Comment l'IA les utilise 1. Le prompt de génération de section injecte `catalogForPrompt(lang)` (registry.ts) — id + résumé + mots-clés + bornes de chaque simulateur. 2. Si le contenu de la note correspond (`keywords`), l'IA émet `{ "type": "sim", "sim": { "simId": "carnot-cycle", "preset": { "t_hot": 300 } } }`. 3. `validateInteractivePage` vérifie : `simId` connu, preset dans les bornes, `compute(preset)` fini — sinon rejet (renvoyé au LLM ou fallback). ## Ajouter un plugin (5 étapes) Pour un **`sim`** (curseurs) : 1. **`lib/simulators/.ts`** — implémenter `SimulatorPlugin` (`family: 'sim'`) : `id`, `title`/`summary` fr+en (le summary sert au matching IA), `keywords`, `params` (curseurs : bornes, pas, défaut, unité, intent), `outputs` (symbole KaTeX, unité), et `compute(env)` **pur et déterministe**. 2. **`lib/simulators/index.ts`** — ajouter au `REGISTRY`. 3. **`components/simulators/-view.tsx`** — composant sur mesure (props : `preset`, `title`, `disclaimer`, `lang`). Réutiliser `SimSlider` / `SimOutputCard` / `SimHeading` / `SimKaTeX` de `sim-controls.tsx`. 4. **`components/simulators/index.ts`** — enregistrer dans `SIMULATOR_VIEWS`. 5. Vérifier : `compute` fini aux valeurs par défaut, `npx tsc --noEmit`, tester sur `/dev/interactive-page`. Pour une **`anim`** (scène animée Play/Step) : 1. **`lib/simulators/.ts`** — implémenter `AnimPlugin` (`family: 'anim'`) : `id`, `title`/`summary` fr+en, `keywords`, `disclaimer?`, `beats` (narration fr+en par étape — KaTeX inline `$…$` dans `speak`). 2. **`lib/simulators/index.ts`** — ajouter au `REGISTRY`. 3. **`components/simulators/-anim-view.tsx`** — scène SVG/React pilotée par `step` (props : `step`, `lang`). Transitions CSS sur `transform`/`opacity` uniquement. Le chrome (Play/Pause/Step/Reset/vitesse + panneau de narration + clavier Espace/←/→/R) est fourni par `AnimPlayerShell` — ne pas le réécrire. 4. **`components/simulators/index.ts`** — enregistrer dans `ANIM_VIEWS`. 5. Vérifier : chaque `step` rend un état cohérent (y compris état final sans JS), `npx tsc --noEmit`, tester sur `/dev/interactive-page`. Règles : pas de couleurs en dur (intents / tokens `--pp-*`), labels fr+en dans le plugin, tout calcul côté `compute` ou scène codée (jamais de logique LLM), SSR = état lisible sans JS.