Contrat de rédaction de diaporama
Un diaporama HyperFrames est une composition HyperFrames normale — scènes, clips, timelines GSAP — avec un ingrédient supplémentaire : une île JSON qui déclare quelles scènes sont des diapositives et comment elles sont connectées. Le SlideshowController du lecteur lit l'île et transforme la timeline GSAP continue en un deck discret et navigable.
Lisez /hyperframes-core en premier pour le contrat de base de la composition (clips, pistes, attributs data-*, règles de déterminisme). Ce skill couvre uniquement ce qui est nouveau : le schéma de l'île, les règles de rédaction des diapositives, les fragments, le branchement, la validation et le composant d'encapsulation.
Résultat — un deck navigable, pas un MP4 linéaire
Le résultat d'un diaporama est le deck en cours d'exécution : servez-le avec hyperframes present <project-dir> (ou le mode présentation de Studio) — le SlideshowController du lecteur lit l'île et pilote la navigation, les fragments, le branchement et le mode présentateur. Voir Présentation et transfert ci-dessous.
N'utilisez pas hyperframes render pour un diaporama dans un seul MP4. Un deck est rédigé sous forme de plusieurs compositions de scène de premier niveau (un data-composition-id par diapositive) sans composition racine maîtresse les encapsulant, donc render résout uniquement la première composition et émet un MP4 silencieusement tronqué (par exemple 6s pour un deck de 40 secondes). Une exportation linéaire de la ligne principale (diapositives principales uniquement, séquences de branchement exclues) est reportée — jusqu'à ce qu'elle soit disponible, les sorties prises en charge sont le deck present en direct et les images fixes par diapositive snapshot. Si un utilisateur a besoin d'un MP4 linéaire aujourd'hui, signalez cette limitation plutôt que de pointer render vers le deck.
Confirmation d'intention
Si l'utilisateur demande explicitement un diaporama, une présentation de diapositives ou un diaporama HyperFrames, procédez avec ce skill.
Si le skill est déclenché par une demande connexe telle que « présentation », « pitch deck », « deck », « deck interactif » ou « convertir cette page », faites une pause avant de rédiger, présentez le choix avant de demander une confirmation. Expliquez brièvement qu'un diaporama HyperFrames signifie un deck exécutable avec des diapositives discrètes, une navigation intégrée et un mode présentateur, des notes de l'orateur modifiables, une gestion des médias partagés et une validation avant le transfert. Pour les conversions de pages sources, mentionnez également que l'objectif est de préserver la conception visuelle, les interactions, les animations et le comportement des médias de la page d'origine tout en traduisant le mouvement de la page en transitions de diapositive à diapositive.
Puis posez une courte question de confirmation :
Voulez-vous cela comme un diaporama HyperFrames ?
Utilisez une interface de choix oui/non lorsque l'environnement en fournit une ; sinon, posez la question en texte brut.
N'implémentez pas le diaporama tant que l'utilisateur n'a pas répondu oui. S'il répond non, cessez d'utiliser ce skill et passez au flux de travail non-diaporama approprié.
Les deux éléments
1. Scènes — déclarées de la manière normale
Chaque diapositive est soutenue par une scène. Déclarez les scènes avec data-composition-id, data-start, data-duration et data-label :
<div
data-composition-id="problem"
data-start="0"
data-duration="8"
data-label="Le problème"
data-width="1920"
data-height="1080"
>
<!-- les clips vont ici -->
</div>
Les diapositives de branchement (accessibles uniquement via une zone sensible, exclues de la ligne principale) sont déclarées exactement de la même manière — elles apparaissent uniquement dans une entrée slideSequences de l'île, pas dans le tableau principal slides.
2. L'île JSON — un bloc de script par composition
Ajoutez exactement un bloc <script type="application/hyperframes-slideshow+json"> au HTML de la composition. Il contient toutes les métadonnées du diaporama :
<script type="application/hyperframes-slideshow+json">
{
"slides": [...],
"slideSequences": [...]
}
</script>
L'île est la source unique de vérité pour l'ordre des diapositives, les notes, les points d'arrêt des fragments, les zones sensibles et les séquences de branchement. Gardez-la près du début du <body>, avant les divs de scène, pour qu'elle soit facile à trouver.
Ne cachez pas le manifeste du diaporama derrière un bloc <script type="application/json"> alternatif avec du code d'exécution qui crée l'île. La commande present lit statiquement le HTML de la composition et s'attend à ce que la véritable île application/hyperframes-slideshow+json soit déjà présente.
Schéma
SlideshowManifest (l'objet île de premier niveau)
{
"slides": [
/* SlideRef[] — la ligne principale, dans l'ordre */
],
"slideSequences": [
/* SlideSequence[] — séquences de branchement hors ligne */
]
}
SlideRef
{
"sceneId": "problem",
"notes": "Commencez par la douleur, pas par l'entreprise.",
"fragments": [3.5, 5.2, 7.0],
"hotspots": [
/* SlideHotspot[] */
],
"ttsScript": null,
"ttsAudioUrl": null,
"ttsDurationMs": null
}
| Champ | Requis | Notes |
|---|---|---|
sceneId | oui | Doit correspondre exactement au data-composition-id d'une scène (ou fournir startTime/endTime explicites). La règle de lint résout les scènes par data-composition-id. |
notes | non | Texte réservé au présentateur. Jamais montré au public. |
fragments | non | Tableau de temps (en secondes) dans la plage [start, end] de la diapositive — voir Fragments ci-dessous. |
hotspots | non | Superpositions interactives déclenchant un branchement — voir Branchement ci-dessous. |
startTime | non | Optionnel. Remplace les limites de temps de la scène correspondante ; par défaut, le début/fin de la scène. |
endTime | non | Optionnel. Remplace les limites de temps de la scène correspondante ; par défaut, le début/fin de la scène. |
ttsScript, ttsAudioUrl, ttsDurationMs | non | Réservé. Les champs du schéma existent mais la lecture TTS n'est pas encore connectée. Omettez sauf si vous pré-remplissez pour une construction future. |
SlideHotspot
{
"id": "h1",
"label": "Comment avons-nous calculé cela ?",
"target": "market-deep-dive",
"region": { "x": 60, "y": 10, "w": 35, "h": 20 }
}
| Champ | Requis | Notes |
|---|---|---|
id | oui | Unique dans la diapositive. |
label | oui | Texte d'info-bulle / bouton affiché au public. |
target | oui | Doit correspondre à un SlideSequence.id dans slideSequences. |
region | non | Boîte englobante en pourcentage de la diapositive : {x, y, w, h} dans 0–100. Omettez pour rendre la zone sensible comme un bouton étiqueté pleine diapositive. |
SlideSequence
{
"id": "market-deep-dive",
"label": "Méthodologie de dimensionnement du marché",
"slides": [{ "sceneId": "mkt-1" }, { "sceneId": "mkt-2" }]
}
slides à l'intérieur d'une séquence utilise la même forme SlideRef que la ligne principale. Les fragments et les zones sensibles imbriquées sont autorisés.
Règles de rédaction des diapositives
Ce sont des contraintes strictes, pas des suggestions. Une diapositive qui les viole sera purement et simplement remplacée lorsqu'un relecteur la verra.
- Le titre est une affirmation sous forme de phrase complète, pas une étiquette. Écrivez « Les PME passent 14 heures/semaine sur la planification manuelle » pas « Problème de planification ». La phrase doit pouvoir se suffire à elle-même si le visuel est ignoré.
- Une idée + un visuel par diapositive. Si vous êtes tenté d'ajouter un deuxième groupe de puces ou un deuxième graphique, divisez la diapositive.
- Commencez par la conclusion. Le point le plus fort vient en premier — sur la diapositive et dans l'ordre du deck. Les investisseurs lisent de gauche à droite, de haut en bas, et ils s'arrêtent.
- Dimensionnement du marché ascendant uniquement. N'écrivez jamais « 50 milliards $ de TAM » sans montrer les calculs. Construisez à partir de l'économie unitaire : comptes × ACV, ou transactions × taux de prélèvement.
- Police minimum équivalente à 30pt. En 1920×1080, un titre fait 72–96px ; le corps du texte fait 48px. Ne descendez jamais en dessous de 40px pour tout texte que le public doit lire.
Portage des pages sources
Lors de la conversion d'une page existante en diaporama, la fidélité à la source fait partie du contrat. Ne remplacez pas les widgets spécifiques à la source par des approximations simplifiées, sauf si l'utilisateur demande explicitement une refonte.
- Préservez la conception visuelle, le langage d'animation, le comportement interactif, le comportement des médias et les fonctionnalités de présentation de la page d'origine aussi fidèlement que possible. Lorsque le système de diaporama prend en charge le mode présentateur, incluez des notes de l'orateur en utilisant le comportement de notes modifiables partagées plutôt qu'une implémentation spécifique au deck.
- Portez les visuels mécaniques du DOM/CSS/JS source aussi exactement que possible : lecteurs personnalisés, visualiseurs canvas, timelines, têtes de lecture, tiges, cercles expansifs, états de survol et autres détails interactifs doivent survivre à la conversion.
- Traitez les éléments
<video>/<audio>natifs comme la source de vérité pour toute chroma média personnalisée, visualiseur canvas, forme d'onde, grille de rythme ou tête de lecture. Connectez les événements média de la source (play,pause,timeupdate,seeking,seeked,ended,ratechange,volumechange) et dérivez l'état visuel demedia.currentTime; n'exécutez pas une minuterie séparée qui pourrait dériver par rapport à la lecture réelle. - Chaque
<video>ou<audio>copié avecsrcdoit avoir des attributs de timing HyperFrames avant le lint :data-startetdata-duration, plusdata-has-audio="true"lorsque l'audio natif audible doit être conservé. Utilisez la plage de temps de la scène pour les médias spécifiques à la diapositive ; pour les vidéos de preuve contrôlées par l'utilisateur qui peuvent être lues à partir de plusieurs diapositives ciblées, utilisez une plage à l'échelle du deck. Ne laissez paspreload="none"sur les médias ; utilisezmetadataouauto. - Résolvez les jetons de police source avant la validation. Si vous conservez des polices source personnalisées, ajoutez des règles
@font-facepour les fichiers de police locaux/capturés. Si vous utilisez des polices de secours système, remplacez les déclarations tokenisées telles quefont-family: var(--f-body)par des piles concrètes sécurisées pour le rendu telles quesystem-ui, sans-serifouui-monospace, monospace; ne laissez pasvar(...)comme valeur de famille de police. - Auditez la source pour les mouvements de page atypiques, en particulier les comportements pilotés par le défilement, la molette, le toucher, l'état de hachage, le redimensionnement ou une boucle requestAnimationFrame. Traitez les fenêtres fixes avec des couches "monde" traduites/mises à l'échelle, le parallaxe, les panneaux épinglés, les défileurs horizontaux, les timelines défilées, le snapping de sections et les caméras zoom-élément comme des comportements source. Le défilement est souvent le déclencheur de transition de la source, alors préservez la transition en extrayant ses points d'arrêt de progression, son easing et ses états de caméra/focus, puis réhébergez ce mouvement sur la navigation du diaporama via des positions de timeline, des fragments ou un crochet de lecteur/harnais réutilisable. Les wrappers autonomes qui sautent aux points d'arrêt des diapositives ont toujours besoin d'un crochet de transition de navigation-caméra explicite ; le calcul des transformations de caméra par diapositive ne suffit pas. Ne simulez pas une transition littérale de défilement de page vers le bas à l'intérieur de la diapositive ; le spectateur doit ressentir un voyage/dézoom de caméra d'un point focal à un autre, pas voir une page web en cours de défilement. Gardez chaque mouvement de caméra de diapositive à diapositive continu : évitez les arrêts de route intermédiaires qui inversent la direction x/y ou le zoom, sauf si la source le fait visiblement à la même limite. Une transition qui zigzague avant d'atterrir est pire qu'un simple déplacement focal direct.
- Préservez la sémantique de recadrage des médias de la source. Traitez les captures d'écran, les tweets/publications sociales, les captures d'interface utilisateur de produit, les graphiques, les documents, le code, les classements et toute image avec du texte lisible comme des preuves de contenu, pas comme des médias décoratifs : utilisez le rapport hauteur/largeur source (
height: auto) ouobject-fit: containdans un cadre stable. Utilisezobject-fit: coveruniquement lorsque la source l'a fait, ou pour des miniatures intentionnellement décoratives/fond/cinématographiques. Après avoir intégré ces captures dans une diapositive, inspectez les quatre bords pour détecter du texte tronqué, des logos, des contrôles ou des légendes ; un recadrage visible sur un contenu significatif est un bug, sauf si la source elle-même l'a recadré. - Si un comportement est générique pour les diaporamas, placez-le dans le lecteur/contrôleur ou dans un extrait de skill réutilisable. Ne le résolvez pas avec des scripts de deck ponctuels.
- Les cadres de scène empilés ne doivent jamais bloquer l'interaction sur la diapositive active. Les cadres cachés ont besoin à la fois d'un masquage visuel et d'un blocage des événements :
.scene-frame {
opacity: 0;
visibility: hidden;
pointer-events: none;
}
.scene-frame.is-active {
opacity: 1;
visibility: visible;
pointer-events: auto;
}
Si la visibilité est pilotée de manière impérative, définissez les trois propriétés (opacity, visibility et pointerEvents) dans le contrôleur de visibilité. opacity: 0 seul laisse encore une couche invisible qui peut avaler les clics.
Fragments : points d'arrêt de révélation dans une diapositive
Un fragment est un temps absolu de la timeline de composition (en secondes) dans la plage [start, end] d'une diapositive où le contrôleur doit maintenir un état de révélation.
Comment cela fonctionne :
- Le lecteur entre dans une diapositive fragmentée — cherche directement à
fragments[0]et s'arrête là. - L'utilisateur appuie sur Suivant (ou →) — le contrôleur cherche à
fragments[1]et s'arrête. - Après le dernier fragment, Suivant passe à la diapositive suivante.
- Une diapositive sans fragments entre à une image de repos à l'intérieur de la diapositive, généralement son point médian, pas exactement à
slide.end.
Les temps de fragment doivent se situer dans [start, end]