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,354 @@
{
"schemaVersion": 1,
"id": "page.thermo-test",
"lang": "fr",
"hero": {
"kicker": "EXPLAINER INTERACTIF",
"title": "Cycle frigorifique",
"subtitle": "Compression, condensation, détente, évaporation",
"meta": "Note de cours · valeurs illustratives"
},
"overview": {
"lead": "Le cycle frigorifique déplace de la chaleur du froid vers le chaud grâce à un travail $W$.",
"cards": [
{
"badge": "PROBLEM",
"title": "Objectif",
"body": "Extraire $Q_e$ à basse température.",
"intent": "warning"
},
{
"badge": "APPROACH",
"title": "Cycle",
"body": "Quatre organes en boucle fermée.",
"intent": "flow"
},
{
"badge": "RESULT",
"title": "COP",
"body": "$\\mathrm{COP}=Q_e/W$",
"intent": "output"
}
]
},
"sections": [
{
"id": "s1",
"title": "Le problème",
"blocks": [
{
"type": "prose",
"md": "On veut **refroidir** un volume en rejetant la chaleur à lextérieur."
},
{
"type": "callout",
"kind": "definition",
"title": "Travail",
"md": "Le compresseur fournit $W=h_2-h_1$."
}
]
},
{
"id": "s2",
"title": "Échanges",
"blocks": [
{
"type": "formula",
"tex": "\\mathrm{COP}=\\frac{Q_e}{W}",
"caption": "Coefficient de performance"
},
{
"type": "sim",
"sim": {
"simId": "ts-diagram"
},
"caption": "Le même cycle sur le diagramme Ts : les aires sont les chaleurs échangées."
}
]
},
{
"id": "s3",
"title": "Isotherme",
"blocks": [
{
"type": "chart",
"payload": {
"chartType": "line",
"series": [
{
"id": "p",
"label": "P(V)",
"values": [
4,
2.5,
1.8,
1.4,
1.2
],
"intent": "flow"
}
]
},
"caption": "Pression vs volume (illustratif)"
},
{
"type": "demo",
"caption": "Le cycle à compression de vapeur — 4 organes en boucle fermée.",
"demo": {
"schemaVersion": 1,
"id": "demo.vapor-cycle",
"lang": "fr",
"disclaimer": "Schéma pédagogique — valeurs illustratives.",
"scene": {
"id": "scene.cycle",
"panels": [
{
"id": "panel.cycle",
"type": "svg-scene",
"payload": {
"nodes": [
{
"id": "comp",
"label": "1 · Compresseur\n$W = h_2 - h_1$",
"intent": "compute"
},
{
"id": "cond",
"label": "2 · Condenseur\n$Q_c = h_2 - h_3$",
"intent": "output"
},
{
"id": "exp",
"label": "3 · Détente\n$h_3 = h_4$",
"intent": "flow"
},
{
"id": "evap",
"label": "4 · Évaporateur\n$Q_e = h_1 - h_4$",
"intent": "cache"
},
{
"id": "work",
"label": "Travail fourni $W$",
"intent": "highlight"
}
],
"edges": [
{
"id": "e12",
"from": "comp",
"to": "cond",
"style": "solid",
"intent": "flow"
},
{
"id": "e23",
"from": "cond",
"to": "exp",
"style": "solid",
"intent": "flow"
},
{
"id": "e34",
"from": "exp",
"to": "evap",
"style": "solid",
"intent": "flow"
},
{
"id": "e41",
"from": "evap",
"to": "comp",
"style": "solid",
"intent": "flow"
},
{
"id": "ew",
"from": "work",
"to": "comp",
"style": "dashed",
"intent": "highlight"
}
]
}
}
]
},
"acts": [
{
"id": "a1",
"title": "Cycle",
"pattern": "flowTrace",
"steps": [
{
"id": "a1.s1",
"speak": "Le compresseur fournit le travail $W$ au fluide.",
"pattern": "spotlightTour",
"pointTo": [
"comp"
],
"reveal": [
{
"ids": [
"comp",
"work",
"ew"
],
"scope": "act"
}
]
},
{
"id": "a1.s2",
"speak": "Au condenseur, la chaleur $Q_c$ est rejetée vers l'extérieur.",
"pattern": "spotlightTour",
"pointTo": [
"cond"
],
"reveal": [
{
"ids": [
"cond",
"e12"
],
"scope": "act"
}
]
},
{
"id": "a1.s3",
"speak": "La détente est isenthalpique : $h_3 = h_4$.",
"pattern": "spotlightTour",
"pointTo": [
"exp"
],
"reveal": [
{
"ids": [
"exp",
"e23"
],
"scope": "act"
}
]
},
{
"id": "a1.s4",
"speak": "À l'évaporateur, le fluide absorbe $Q_e$ : c'est le froid utile.",
"pattern": "spotlightTour",
"pointTo": [
"evap"
],
"reveal": [
{
"ids": [
"evap",
"e34"
],
"scope": "act"
}
]
},
{
"id": "a1.s5",
"speak": "Le cycle se boucle : le fluide retourne au compresseur.",
"pattern": "overview",
"reveal": [
{
"ids": [
"comp",
"cond",
"exp",
"evap",
"work",
"e12",
"e23",
"e34",
"e41",
"ew"
],
"scope": "act"
}
]
}
]
}
]
}
},
{
"type": "sim",
"sim": {
"simId": "carnot-cycle",
"preset": {
"t_cold": 260,
"t_hot": 300,
"q_cold": 100
},
"disclaimer": "Valeurs illustratives — les COP réels sont inférieurs au COP de Carnot."
},
"caption": "Manipulez les températures des sources : le COP maximal suit le 2ᵉ principe."
},
{
"type": "sim",
"sim": {
"simId": "carnot-cycle-anim"
},
"caption": "Le cycle de Carnot battement par battement — piston et diagramme PV en direct."
},
{
"type": "stats",
"items": [
{
"value": "3.2",
"label": "COP typique",
"intent": "output"
},
{
"value": "1.25×",
"label": "Gain relatif",
"intent": "highlight"
},
{
"value": "<2%",
"label": "Pertes",
"intent": "warning"
}
]
}
]
},
{
"id": "s4",
"title": "Synthèse",
"blocks": [
{
"type": "table",
"columns": [
"Organe",
"Échange"
],
"rows": [
[
"Compresseur",
"$W$"
],
[
"Condenseur",
"$Q_c$"
],
[
"Évaporateur",
"$Q_e$"
]
]
},
{
"type": "prose",
"md": "Le COP mesure lefficacité du cycle."
}
]
}
],
"footer": "Valeurs pédagogiques — pas des mesures expérimentales."
}