Files
Momento/memento-note/components/simulators/ts-diagram-view.tsx
Antigravity 69c99e4f4f 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>
2026-07-24 17:51:43 +00:00

115 lines
5.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useDarkMode } from '@/components/interactive-demo/demo-speak'
/**
* Ts diagram of the Carnot cycle — canonical 2nd-law diagram.
* Driven by AnimPlayerShell via `step` (0..4). SVG, transform/opacity only.
* Cycle = rectangle: horizontal isotherms (Th, Tc), vertical adiabatics.
*/
const X0 = 110 // y-axis x
const Y0 = 280 // x-axis y
const S1 = 190 // entropy left
const S2 = 520 // entropy right
const YH = 80 // T_h line y
const YC = 220 // T_c line y
const EASE = 'transform 700ms cubic-bezier(0.22, 1, 0.36, 1), opacity 500ms ease'
// marker position per beat (end of each phase)
const MARKER = [
{ x: S2, y: YH }, // b1 end: right-top
{ x: S2, y: YC }, // b2 end: right-bottom
{ x: S1, y: YC }, // b3 end: left-bottom
{ x: S1, y: YH }, // b4 end: left-top
{ x: S1, y: YH }, // b5: stay
]
export function TsDiagramView({ step, lang }: { step: number; lang: string }) {
const fr = lang.startsWith('fr')
const dark = useDarkMode()
const s = Math.min(step, 4)
const ink = dark ? '#EDE7DB' : '#242422'
const muted = dark ? '#A39C8D' : '#686762'
const plum = dark ? '#D07AA6' : '#9F3F70'
const blue = dark ? '#7FA8CC' : '#3F6F9F'
const paper = dark ? '#17140F' : '#F4F0E8'
const m = MARKER[s]
const qhW = S2 - S1
return (
<svg
viewBox="0 0 680 320"
className="w-full"
role="img"
aria-label={fr ? 'Diagramme Ts du cycle de Carnot' : 'Ts diagram of the Carnot cycle'}
style={{ background: paper, display: 'block' }}
>
{/* axes */}
<line x1={X0} y1={Y0} x2={650} y2={Y0} stroke={ink} strokeWidth={1.5} />
<line x1={X0} y1={Y0} x2={X0} y2={30} stroke={ink} strokeWidth={1.5} />
<text x={648} y={Y0 + 18} fontSize={12} fill={muted} textAnchor="end" fontStyle="italic">s</text>
<text x={X0 - 8} y={40} fontSize={12} fill={muted} textAnchor="end" fontStyle="italic">T</text>
{/* isotherm T_h */}
<line x1={X0} y1={YH} x2={650} y2={YH} stroke={plum} strokeWidth={1} strokeDasharray="5 4" opacity={0.45} />
<text x={X0 - 8} y={YH + 4} fontSize={11} fill={plum} textAnchor="end" fontWeight={600}>T_h</text>
{/* isotherm T_c */}
<line x1={X0} y1={YC} x2={650} y2={YC} stroke={blue} strokeWidth={1} strokeDasharray="5 4" opacity={0.45} />
<text x={X0 - 8} y={YC + 4} fontSize={11} fill={blue} textAnchor="end" fontWeight={600}>T_c</text>
{/* Q_h area (beat ≥ 0, shown from beat 0) */}
<rect
x={S1} y={YH} width={qhW} height={Y0 - YH}
fill={plum} opacity={s >= 0 ? 0.10 : 0}
style={{ transition: 'opacity 600ms ease' }}
/>
{s === 0 ? (
<text x={(S1 + S2) / 2} y={(YH + Y0) / 2} textAnchor="middle" fontSize={15} fontWeight={800} fill={plum}>Q_h</text>
) : null}
{/* Q_c area (from beat 2) */}
<rect
x={S1} y={YC} width={qhW} height={Y0 - YC}
fill={blue} opacity={s >= 2 ? 0.16 : 0}
style={{ transition: 'opacity 600ms ease' }}
/>
{s >= 2 && s < 4 ? (
<text x={(S1 + S2) / 2} y={(YC + Y0) / 2} textAnchor="middle" fontSize={15} fontWeight={800} fill={blue}>Q_c</text>
) : null}
{/* W = cycle area (beat 4) */}
<rect
x={S1} y={YH} width={qhW} height={YC - YH}
fill={plum} opacity={s === 4 ? 0.18 : 0}
style={{ transition: 'opacity 600ms ease' }}
/>
{s === 4 ? (
<text x={(S1 + S2) / 2} y={(YH + YC) / 2} textAnchor="middle" fontSize={17} fontWeight={800} fill={plum}>W</text>
) : null}
{/* cycle edges, drawn progressively */}
{/* top: b1 (isothermal expansion) */}
<line x1={S1} y1={YH} x2={S2} y2={YH} stroke={ink} strokeWidth={2.5} opacity={s >= 0 ? 1 : 0.15} />
<polygon points={`${S2 - 14},${YH - 5} ${S2 - 4},${YH} ${S2 - 14},${YH + 5}`} fill={ink} opacity={s >= 0 ? 1 : 0.15} />
{/* right: b2 (adiabatic expansion) */}
<line x1={S2} y1={YH} x2={S2} y2={YC} stroke={ink} strokeWidth={2.5} opacity={s >= 1 ? 1 : 0.15} style={{ transition: 'opacity 500ms ease' }} />
<polygon points={`${S2 - 5},${YC - 14} ${S2},${YC - 4} ${S2 + 5},${YC - 14}`} fill={ink} opacity={s >= 1 ? 1 : 0.15} style={{ transition: 'opacity 500ms ease' }} />
{/* bottom: b3 (isothermal compression) */}
<line x1={S2} y1={YC} x2={S1} y2={YC} stroke={ink} strokeWidth={2.5} opacity={s >= 2 ? 1 : 0.15} style={{ transition: 'opacity 500ms ease' }} />
<polygon points={`${S1 + 14},${YC - 5} ${S1 + 4},${YC} ${S1 + 14},${YC + 5}`} fill={ink} opacity={s >= 2 ? 1 : 0.15} style={{ transition: 'opacity 500ms ease' }} />
{/* left: b4 (adiabatic compression) */}
<line x1={S1} y1={YC} x2={S1} y2={YH} stroke={ink} strokeWidth={2.5} opacity={s >= 3 ? 1 : 0.15} style={{ transition: 'opacity 500ms ease' }} />
<polygon points={`${S1 - 5},${YH + 14} ${S1},${YH + 4} ${S1 + 5},${YH + 14}`} fill={ink} opacity={s >= 3 ? 1 : 0.15} style={{ transition: 'opacity 500ms ease' }} />
{/* entropy ticks */}
<text x={S1} y={Y0 + 16} fontSize={10} fill={muted} textAnchor="middle">s</text>
<text x={S2} y={Y0 + 16} fontSize={10} fill={muted} textAnchor="middle">s</text>
{/* state marker */}
<circle cx={m.x} cy={m.y} r={6} fill={plum} stroke={paper} strokeWidth={2} style={{ transition: EASE }} />
</svg>
)
}