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,76 @@
/** Interactive Demo schema v1 — caps & allowlists (brainstorm 2026-07-22). */
export const INTERACTIVE_DEMO_SCHEMA_VERSION = 1 as const
export const INTERACTIVE_DEMO_CAPS = {
maxScenes: 5,
maxActs: 8,
maxStepsPerAct: 12,
maxAnnotationsPerStep: 5,
maxPanelsPerScene: 2,
maxJsonBytes: 64 * 1024,
} as const
export const PATTERN_IDS = [
'progressiveReveal',
'spotlightTour',
'accumulate',
'compareBeforeAfter',
'chartBuild',
'heatmapFill',
'overview',
'flowTrace',
] as const
export const INTENT_IDS = [
'highlight',
'flow',
'cache',
'compute',
'output',
'warning',
] as const
export const SCOPE_IDS = ['transient', 'act', 'scene'] as const
export const ANNOTATION_KINDS = ['circle', 'arrow', 'badge', 'callout'] as const
export const PANEL_TYPES = ['svg-scene', 'chart', 'heatmap-matrix'] as const
export const TRANSITIONS = ['fade', 'cut'] as const
export const CHART_TYPES = ['line', 'bar', 'area'] as const
/**
* Human / locale strings — may contain hex/rgb in prose; changeable by translateDemo.
* Must stay in sync between color-scan skip, translate strip, and docs.
*/
export const HUMAN_STRING_KEYS = [
'lang',
'speak',
'title',
'text',
'disclaimer',
'label',
'rowLabels',
'colLabels',
] as const
export type HumanStringKey = (typeof HUMAN_STRING_KEYS)[number]
const HUMAN_STRING_KEY_SET = new Set<string>(HUMAN_STRING_KEYS)
export function isHumanStringKey(key: string): boolean {
return HUMAN_STRING_KEY_SET.has(key)
}
/** Hex / rgb color literals forbidden in non-human JSON fields (P11). */
export const FORBIDDEN_COLOR_RE =
/#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\b|\brgba?\s*\(/i
/**
* Future generation-prompt rule (not a validator cap):
* speak ≈ 12 sentences, ~25 words max — tempo is decided at writing time.
*/
export const SPEAK_WRITING_RULE =
'speak ≈ 12 phrases, ~25 mots max — le tempo de la démo se décide à lécriture, pas au rendu.'