feat: page interactive, démos Play/Step et simulateur Carnot

Ajoute le pipeline PageSpec (validation, rendu, publication /p/{slug}),
les démos TipTap /demo, et le simulateur Carnot (modes frigo/PAC/moteur,
énergie kJ vs puissance W, unités K/°C/°F) avec correctifs d’équations KaTeX.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Antigravity
2026-07-24 17:51:43 +00:00
parent f385d43d5d
commit 69c99e4f4f
67 changed files with 12005 additions and 33 deletions

View File

@@ -0,0 +1,469 @@
{
"schemaVersion": 1,
"id": "demo.attnres",
"lang": "fr",
"disclaimer": "Poids d'enseignement — schéma illustratif, pas les mesures de la Figure 8 du papier.",
"scene": {
"id": "scene.problem",
"panels": [
{
"id": "panel.trunk",
"type": "svg-scene",
"payload": {
"nodes": [
{
"id": "residualTrunk",
"label": "Tronc résiduel h",
"intent": "flow"
},
{
"id": "L1",
"label": "L1 · Attention",
"intent": "compute"
},
{
"id": "L2",
"label": "L2 · MLP",
"intent": "cache"
},
{
"id": "L3",
"label": "L3 · Attention",
"intent": "compute"
},
{
"id": "L4",
"label": "L4 · MLP",
"intent": "cache"
},
{
"id": "L5",
"label": "L5 · Attention",
"intent": "compute"
},
{
"id": "L6",
"label": "L6 · MLP",
"intent": "cache"
},
{
"id": "L7",
"label": "L7 · Attention",
"intent": "compute"
},
{
"id": "L8",
"label": "L8 · MLP",
"intent": "cache"
}
],
"edges": [
{
"id": "e.L1.h",
"from": "L1",
"to": "residualTrunk",
"style": "solid",
"weight": 1,
"intent": "flow"
},
{
"id": "e.L2.h",
"from": "L2",
"to": "residualTrunk",
"style": "solid",
"weight": 1,
"intent": "flow"
},
{
"id": "e.L3.h",
"from": "L3",
"to": "residualTrunk",
"style": "solid",
"weight": 1,
"intent": "flow"
},
{
"id": "e.L4.h",
"from": "L4",
"to": "residualTrunk",
"style": "solid",
"weight": 1,
"intent": "flow"
},
{
"id": "e.L5.h",
"from": "L5",
"to": "residualTrunk",
"style": "solid",
"weight": 1,
"intent": "flow"
},
{
"id": "e.L6.h",
"from": "L6",
"to": "residualTrunk",
"style": "solid",
"weight": 1,
"intent": "flow"
},
{
"id": "e.L7.h",
"from": "L7",
"to": "residualTrunk",
"style": "solid",
"weight": 1,
"intent": "flow"
},
{
"id": "e.L8.h",
"from": "L8",
"to": "residualTrunk",
"style": "solid",
"weight": 1,
"intent": "flow"
}
]
}
},
{
"id": "panel.magShare",
"type": "chart",
"payload": {
"chartType": "line",
"series": [
{
"id": "series.magnitude",
"label": "‖h‖",
"values": [
2,
3,
4,
5,
6,
7,
8,
9
],
"intent": "compute"
},
{
"id": "series.embedShare",
"label": "part embedding",
"values": [
0.5,
0.33,
0.25,
0.2,
0.17,
0.14,
0.12,
0.11
],
"intent": "output"
}
]
}
}
]
},
"acts": [
{
"id": "a1",
"title": "Le problème — dilution en profondeur",
"pattern": "accumulate",
"steps": [
{
"id": "a1.s1",
"speak": "Chaque couche entre dans le tronc résiduel avec un **coefficient fixe ×1** — aucune sélection.",
"pattern": "spotlightTour",
"pointTo": [
"residualTrunk",
"L1",
"e.L1.h"
],
"reveal": [
{
"ids": [
"residualTrunk",
"L1",
"e.L1.h"
],
"scope": "act"
}
]
},
{
"id": "a1.s2",
"speak": "La **magnitude** croît avec la profondeur ; la part de l'embedding **dilue** $\\approx 1/(l+1)$.",
"pattern": "chartBuild",
"pointTo": [
"series.magnitude",
"series.embedShare"
],
"reveal": [
{
"ids": [
"series.magnitude"
],
"scope": "act"
},
{
"ids": [
"series.embedShare"
],
"scope": "act"
}
]
}
]
},
{
"id": "a2",
"title": "Full Attention Residuals",
"pattern": "heatmapFill",
"transition": "fade",
"scene": {
"id": "scene.heatmap",
"panels": [
{
"id": "panel.attnMatrix",
"type": "heatmap-matrix",
"payload": {
"rows": 8,
"cols": 8,
"triangular": "lower",
"rowLabels": [
"L1",
"L2",
"L3",
"L4",
"L5",
"L6",
"L7",
"L8"
],
"colLabels": [
"h₁",
"f₁",
"f₂",
"f₃",
"f₄",
"f₅",
"f₆",
"f₇"
],
"values": [
[
1.0,
0,
0,
0,
0,
0,
0,
0
],
[
0.3,
0.7,
0,
0,
0,
0,
0,
0
],
[
0.2,
0.65,
0.15,
0,
0,
0,
0,
0
],
[
0.25,
0.15,
0.45,
0.15,
0,
0,
0,
0
],
[
0.1,
0.1,
0.15,
0.6,
0.05,
0,
0,
0
],
[
0.1,
0.08,
0.12,
0.2,
0.45,
0.05,
0,
0
],
[
0.18,
0.07,
0.1,
0.12,
0.18,
0.3,
0.05,
0
],
[
0.12,
0.06,
0.08,
0.1,
0.14,
0.2,
0.25,
0.05
]
]
}
}
]
},
"steps": [
{
"id": "a2.s1",
"speak": "Matrice **lower-triangular** : chaque ligne = une couche ; chaque ligne **somme à 1**.",
"pattern": "overview"
},
{
"id": "a2.s2",
"speak": "On remplit progressivement : la couche 1 ne voit que **$h_1$**.",
"pattern": "heatmapFill",
"pointTo": [
"r1.c1"
],
"reveal": [
{
"ids": [
"r1.c1"
],
"scope": "act"
}
]
},
{
"id": "a2.s3",
"speak": "**Dominance diagonale** — chaque couche favorise son prédécesseur immédiat.",
"pointTo": [
"r3.c3",
"r4.c4"
],
"reveal": [
{
"ids": [
"r2.c1",
"r2.c2",
"r3.c1",
"r3.c2",
"r3.c3"
],
"scope": "act"
}
],
"annotate": [
{
"kind": "badge",
"targetIds": [
"r2.c2"
],
"scope": "act",
"intent": "highlight"
}
]
},
{
"id": "a2.s4",
"speak": "L'**embedding** garde un poids non trivial en profondeur.",
"annotate": [
{
"kind": "circle",
"targetIds": [
"r8.c1"
],
"scope": "transient",
"intent": "highlight"
},
{
"kind": "badge",
"targetIds": [
"r8.c1"
],
"scope": "act",
"intent": "highlight"
}
]
},
{
"id": "a2.s5",
"speak": "Certaines couches profondes **récupèrent** des sources très antérieures — skip connections apprises.",
"annotate": [
{
"kind": "badge",
"targetIds": [
"r7.c1"
],
"scope": "act",
"intent": "highlight"
},
{
"kind": "callout",
"targetIds": [
"r8.c3"
],
"scope": "transient",
"text": "récupération précoce",
"intent": "warning"
}
]
},
{
"id": "a2.s6",
"speak": "Pre-Attn et Pre-MLP se **spécialisent** différemment (patterns mesurés, ici illustratifs).",
"pattern": "overview",
"annotate": [
{
"kind": "badge",
"targetIds": [
"r5.c4"
],
"scope": "scene",
"intent": "highlight"
}
]
},
{
"id": "a2.s7",
"speak": "Matrice assemblée — triangulaire inférieure ; **chaque ligne somme à 1**.",
"pattern": "overview",
"reveal": [
{
"ids": [
"*"
],
"scope": "act"
}
]
}
]
}
]
}