Formats

28 — Stories : le format stories (stories web) et story.recit.dev

Statut : proposé · Phase : P11 · Mis à jour : 02/11/2026.

Ce plan détaille la phase P11 de 06 · Feuille de route : le format stories (cartes verticales plein écran qu'on fait défiler d'un tap), son jumeau JSON, son lecteur, ses exports (images, film) et le site story.recit.dev. Il part de 08 · Formats §6, qu'il précise sans revenir sur les décisions acceptées ; chaque désaccord avec un plan accepté est posé en question ouverte (§12). Il s'appuie sur le code au 02/11/2026.

Il dépend de 11 · Images (lots IM1 et IM2 logés en P11 : ```pixel et textcard), de 14 · IA et scénario (attributs de scène du scénario, Broc), de 15 · Export PDF (pas de PDF pour stories, mais la même chaîne de capture), de 09 · Langues et JSON, de 10 · Formulaires (sondages), de 03 · Packaging §6 et §8, de 07 · Domaines et de 21 · Tests. Il réutilise la chaîne de capture livrée par le plan 23 (report, P6) et le bloc d'image du film livré par 24 · Webtoon (P7). Les ponts depuis report et calendar attendent les plans 23 et 27.

Le nom. Le format stories porte le même mot que le modèle Story du cœur. AGENTS.md le garde tel quel « on purpose » : le renommer est une décision de produit, pas un nettoyage. Ce plan ne la prend pas ; il écrit stories partout et liste en §12 (question 1) ce qu'un renommage toucherait et pourquoi il vaudrait mieux le décider avant ST0.

1. Pourquoi

  • La forme courte la plus lue sur mobile. Des cartes 9:16 plein écran, une idée par carte, un tap pour avancer : c'est la forme des stories des réseaux et des Web Stories. Récit la sert depuis la même source Markdown que le reste.
  • Écrire une fois, publier partout. Une story s'intègre dans une page de doc ou une landing (StoryEmbed), s'exporte en une image 1080×1920 par carte pour les réseaux, et devient un film vertical par le pont stories ⇄ motion.
  • La fin de la chaîne verticale. Avec motion (P4) et toon (P7), stories ferme le trio des formats verticaux : une seule source donne la story, le webtoon et le film (14 D6).
  • Le format des cartes de texte et des images en JS. Le plan 11 a tranché que textcard et ```pixel sont des blocs de motion et de stories, pas un format : P11 est leur premier vrai client.

2. Ce qui existe déjà et ce qu'on réutilise

Relevé dans le dépôt le 02/11/2026.

ÉlémentÉtatCe que P11 en fait
packages/formats/storiesstub privé (@recit/stories 0.0.0, scope:format), src/index.ts videpaquet publiable sur le modèle de packages/formats/deck
@recit/core/schema (source.ts)StoriesSourceSchema = genericSource("stories"), scènes lâches ; stories dans STORY_FORMATS ; packages/core/schema/v1/stories.json publiéschéma strict et typé, ajout compatible en v1 (B1)
@recit/core/config (validate.ts)StoriesConfigSchema existe déjà, vide de réglages : il ne fait que refuser les anciennes clés de site (dir, routePrefix…) avec un renvoi vers publish:reçoit les réglages du format ; les refus restent
MotionSceneSourceSchematype (bloc), dur, hold, props, attrs, body, voiceoverles champs d'une carte en sont un sur-ensemble : le pont motion → stories devient fermé et presque gratuit (§5.4)
@recit/motion/sourcestoryToFilm et la table d'inférence fermée (infer.ts : un titre seul → title, un paragraphe → statement, une liste → list…) ; site-stories/vite.ts l'essaie déjà sur toute story deckmême table pour le pont stories → motion
@recit/motion-blocksMotionFrame, filmTimeline, useFilmClock (clock.ts), huit blocs, le cadre commun blocks/frame.tsxune carte type=stat est un bloc joué dans la carte, à l'horloge de la carte
@recit/deckrendu HTML d'une scène (slides/SceneContent.tsx, HtmlSlide.tsx), navigation clavier (navigation-utils.ts) ; aucun geste tactile (pas de swipe)rendu des cartes Markdown à réutiliser ; gestes à écrire (événements pointeur, sans dépendance)
Règles de densité (core/src/rules/anti-overload.ts)mots visibles, puces, par scène, avec RulesConfigSchemaseuils propres aux cartes
@recit/site-storiesplugin.tsx choisit MotionViewer ou StoryViewer (deck) selon le formatune branche stories vers StoryPlayer, chargée paresseusement
@recit/site-kitformats.ts décrit stories ; SITES ne connaît pas storyentrée story (port 3009)
La CLIrecit dev a un aperçu propre au motion ; recit export (deck) sans --to ; recit render rend un récit motionaperçu stories ; --to images avec la chaîne de P6 ; render accepte une story stories
Plan 11TextCardBlock, PixelBlock (schémas prévus dans @recit/core/schema), TextCard statique et PixelImage dans @recit/components, blocs animés dans @recit/motion-blocksune carte = une textcard (IM2.3), image d'une carte = ```pixel (IM1)
Plan 24bloc panel du film (image dans un plan)fond image d'une carte dans le film

On ne crée pas : de bibliothèque de carrousel, de geste ou de lecteur vidéo ; de second moteur de texte (11 D4) ; de stockage pour les sondages ; de schéma de type hors de @recit/core.

3. Vocabulaire

  • Une scène de stories est une carte : « carte » est le mot du lecteur, de l'URL (?card=N) et de l'interface, comme « slide » pour le deck. Le modèle garde Scene.
  • Une story est le modèle compilé (Story), quel que soit le format. Dans la doc, un document format: stories se dit « une story (format stories) » tant que la question 1 n'est pas tranchée.
  • Le rendu motion d'une story est un film. Un « deck » ne désigne que les slides.
  • textcard est un bloc, pas une carte : une carte peut contenir une textcard (et c'est le cas principal, 11 D6).

À ajouter au glossaire d'AGENTS.md par l'intégrateur (ST6) : « carte ».

4. Le modèle

4.1 Markdown

MarkdownMarkdown
--- title: Lorem Launch format: stories lang: en aspectRatio: 9:16 autoplay: true dur: 5 --- --- id=hook background=./bg/01.webp alt="An abstract lorem gradient." # Lorem ipsum. --- id=proof dur=7 overlay=bottom ## :value{data=sales field=revenue agg=sum format=currency} dolor sit amet this quarter --- id=stat type=stat number=30 unit=s kicker="Lorem" --- id=quote :::textcard{variant=quote background=theme} Lorem ipsum dolor sit amet. — Lorem Ipsum ::: --- id=cta background=#0b0b0f # Try it now ::cta[Get started]{href=https://recit.dev}
ÉlémentRôle
backgroundimage, vidéo courte (.mp4, .webm, muette, en boucle), couleur, ou theme / gradient (mêmes valeurs que la textcard, 11 D4). Un seul nom, jamais bg
altdescription d'un fond image ou vidéo, localisable ; manquante : erreur en mode strict (08 §6), avertissement sinon
overlaydégradé de lisibilité : none, top, bottom, full
dursecondes à l'écran en lecture automatique ; par défaut le dur de la story, ou la durée du bloc motion
type, hold, attributs de bloccarte jouée par un bloc de @recit/motion-blocks (stat, list…), mêmes attributs qu'en motion (B4)
corpsMarkdown habituel (titres, paragraphes, listes, :value), blocs transverses dans le corps (```pixel, :::textcard, règle B2)
::cta[label]{href}bouton d'action en bas de la carte (balayage vers le haut) ; une seule par carte, en dernier
:::notesnotes d'auteur, jamais affichées ; voix off dans le film
beat, cast, set, prompt…attributs réservés du scénario (14 D4), gardés dans attrs jusqu'à P16

Deux écarts avec 08 §6, posés en question 2 : 08 écrit duration: 5s et aspect: 9:16. Le cœur appelle déjà ces réglages dur (scène motion, secondes, nombre) et aspectRatio (frontmatter du deck et du film). Ce plan propose les mots existants : un mot par chose, et le pont avec motion copie les champs sans les traduire.

Règles :

  • texte trop long pour une carte : erreur (règles de densité, seuils propres au format, 08 §6) ;
  • ::cta ailleurs qu'en fin de carte, ou deux ::cta : erreur avec ligne ;
  • type= inconnu de @recit/motion : erreur avec la liste des blocs ; type= quand @recit/motion-blocks n'est pas installé : erreur « installez … » (B1) ;
  • fond introuvable : erreur avec ligne ; poids au-delà du budget : avertissement ;
  • aspectRatio autre que 9:16 : erreur en P11 (question 6).

4.2 Le jumeau JSON

Dans packages/core/src/schema/source.ts, en zod/mini, types dérivés :

TypeScriptTypeScript
/** A background: a color, a theme keyword, or an image or video with its description */ export const StoriesBackgroundSchema = z.union([ z.string(), // "#0b0b0f", "theme", "gradient", "./bg/01.webp" z.strictObject({ src: z.string(), alt: z.optional(LocalizedSchema) }), ]); export const StoriesCtaSchema = z.strictObject({ label: LocalizedSchema, href: z.string().check(z.minLength(1)), }); export const StoriesSceneSourceSchema = z.strictObject({ id: sceneFields.id, attrs: sceneFields.attrs, body: sceneFields.body, notes: sceneFields.notes, /** A motion block played in the card (same names as MotionSceneSource) */ type: z.optional(z.string().check(z.minLength(1))), props: z.optional(z.record(z.string(), z.unknown())), dur: z.optional(z.number().check(z.positive())), hold: z.optional(z.number().check(z.gte(0))), background: z.optional(StoriesBackgroundSchema), overlay: z.optional(z.enum(["none", "top", "bottom", "full"])), cta: z.optional(StoriesCtaSchema), }); export const StoriesSettingsSourceSchema = z.looseObject({ aspectRatio: z.optional(z.literal("9:16")), autoplay: z.optional(z.boolean()), dur: z.optional(z.number().check(z.positive())), loop: z.optional(z.boolean()), theme: z.optional(z.union([ThemeModeSchema, z.string(), ThemeConfigSchema])), rules: z.optional(RulesConfigSchema), /** Round thumbnail of the story in a rail */ cover: z.optional(StoriesBackgroundSchema), images: z.optional(StoriesImagesOptionsSchema), // ST3 }); export const StoriesSourceSchema = z.strictObject({ ...storyFields, format: z.literal("stories"), settings: z.optional(StoriesSettingsSourceSchema), scenes: z.array(StoriesSceneSourceSchema), });
  • background reprend la forme de l'image du deck (DeckImageSchema : string | { src, alt }), et la conversion suit celle de deckScene : background=… alt=… dans le Markdown, objet en JSON. Ce plan propose de renommer ce type en ImageSourceSchema et de le partager (question 7) plutôt que d'en écrire un second.
  • 09 §2.3 écrit background, duration, cta { label, href }, overlay : seul duration change (question 2). cta est un champ typé, comme 09 le prévoit ; le ::cta du Markdown y est converti. La règle B2 (blocs transverses dans le corps) vaut pour textcard et pixel, pas pour cta, qui est propre au format.
  • type, props, dur, hold ont exactement le sens de MotionSceneSourceSchema : les deux schémas partagent ces champs par un objet commun (sceneBlockFields), jamais par copie.
  • StoriesImagesOptionsSchema va dans packages/core/src/config/validate.ts avec les autres options d'export ; StoriesConfigSchema reçoit les réglages (forme imbriquée de recit.config) et garde les refus des anciennes clés de site. Pas d'options PDF : stories n'a pas de PDF (15 §1, tranché).

4.3 Conversion et aller-retour

  • storiesScene dans convert.ts : attributs typés vers leurs champs, ::cta final vers cta, :::notes vers notes, le reste du corps dans body. Un bloc ```yaml seul dans le corps d'une carte type=… donne props, comme en motion.
  • Écriture canonique : id type background alt overlay dur hold, puis attrs, puis le corps, puis ::cta en dernier.
  • Propriété testée : compile(md) == compile(toJson(md)) et toMd(toJson(md)) == md sur les fixtures et les exemples ; source-conversion.spec.ts couvre examples/stories-* sans code en plus.

4.4 Langues

  • Une story par langue (launch.fr.md, même structure, mêmes id) ou un JSON qui porte toutes ses langues ; la parité vérifie en plus cta.href, type, dur identiques, et signale un cta.label ou un alt non traduit.
  • Les fonds sont partagés (variante 01.fr.webp possible, 09 §1). Une textcard ou un ```pixel se refait avec la langue (11).
  • dir suit la langue : en RTL, les zones de tap et le sens du balayage s'inversent ; les barres de progression se remplissent de droite à gauche.

4.5 Scénario, personnages, images

  • Le plan 14 (D4) écrit ses exemples en stories : cast: dans le frontmatter, cast=, set=, pose=, prompt= sur les cartes. En P11 ces attributs restent dans attrs ; @recit/scenario les lit en P16. Une carte avec prompt= et sans fond reçoit une image de remplacement neutre (avertissement, erreur en --strict), point d'accroche de 14 D7.
  • Les images ne sont jamais générées par Récit. ```pixel (IM1) et sprite (IM4, plus tard) dessinent en JS, sans IA.
  • Broc. Le scénario 2 de sites/plans/pages/annexes/broc/ a une version stories. Elle vit dans examples/scenario-lebrocoli (règle B7), en P16, après la licence de l'image de référence (© vguerand, tous droits réservés). Rien de Broc dans examples/stories-*.

5. Le rendu

5.1 Le lecteur

Composants de @recit/stories (08 §6), anonymes, un X.module.css chacun, une story et un play chacun :

ComposantRôle
StoryPlayerracine : carte courante, horloge, clavier, gestes, ?card=N (ou ?card=<id>), plein écran sur mobile, cadre 9:16 centré sur bureau
StoryCardune carte : fond, voile, contenu (HTML de la scène, ou bloc motion), StoryCTA
ProgressBarsune barre par carte, remplie par l'horloge ; role="progressbar" sur la carte courante
TapZonesprécédent (premier tiers), suivant (le reste), appui long = pause ; ce sont des boutons nommés, pas des zones muettes
StoryCTAlien d'action, balayage vers le haut ou clic
StoryCovervignette ronde d'une story
StoryRailrangée de vignettes de plusieurs stories ; passer d'une story à l'autre par balayage horizontal
MuteToggleseulement si un fond vidéo a du son (muet par défaut)
ShareButtonnavigator.share quand il existe, sinon copie du lien
PauseButtonpause visible, toujours (critère WCAG 2.2.2 : un contenu qui avance seul plus de 5 s doit pouvoir s'arrêter)
  • Contenu d'une carte. Une carte Markdown se rend par le rendu HTML de scène du deck (SceneContent) ; si l'importer tire le runtime du deck dans le bundle, la partie commune descend dans @recit/components (ST1.2 tranche, mesure à l'appui). Une carte type=… se rend par MotionFrame, à l'horloge de la carte : le bloc joue son entrée puis tient.
  • Horloge. useFilmClock de @recit/motion-blocks sert aussi aux barres de progression : une seule notion du temps pour la carte et son bloc. Pause quand l'onglet est caché (visibilitychange) ou pendant un appui long.
  • Gestes. Événements pointeur natifs (tap, appui long, balayages), sans dépendance. Clavier : flèches, espace (pause), Échap (fermer dans un rail), Entrée sur le CTA.
  • Mouvement réduit. Sous prefers-reduced-motion, la lecture automatique est coupée par défaut, les blocs motion montrent leur état final, une vidéo de fond montre sa première image.
  • Préchargement de la carte suivante (image, vidéo, police), rien au-delà.
  • Mobile. 100dvh, marges de sécurité (env(safe-area-inset-*)), aucune barre du navigateur sur le texte ; le contenu se met à l'échelle par les unités de conteneur.
  • Style. Loi du plan 19 : modules CSS compilés par Lightning CSS, ./styles.css publié, valeurs dynamiques (couleur de fond, progression) en variables CSS par useCssVariable, light-dark() pour l'interface ; une carte garde les couleurs de sa story.
  • Embed. <StoryEmbed slug="launch" format="stories" /> dans une page, StoryRail en MDX ; plein écran sous /present/<slug>.

5.2 Les images (ST3)

  • recit export launch.md --to images : un PNG 1080×1920 par carte et par langue (--all-locales), listés dans exports.json (variante kind: "images" de ExportManifestSchema).
  • La CLI sert le build du lecteur et capture chaque carte par @recit/paged/runner : page ?card=N&settled=1, fenêtre 360×640 à l'échelle 3. Les blocs motion sont à leur état final, les vidéos à leur première image. La textcard statique de @recit/components sert ici (IM2.3).
  • Options typées (StoriesImagesOptionsSchema) : format (png, jpeg, webp, encodé dans Chromium), scale, cards (une sélection d'id), maxBytes.

5.3 Pas de PDF

Tranché le 24/10 (15 Q5) : recit export --to pdf sur une story stories répond par une erreur explicite qui renvoie vers --to images et recit render.

5.4 Le film (pont stories ⇄ motion, ST2)

Correspondance fermée, dans les deux sens (08 §0) :

CartePlan du film
type=… et propsmême bloc, mêmes props
corps Markdowntable d'inférence de @recit/motion (titre seul → title, paragraphe → statement, liste → list…) ; hors table : erreur avec ligne, jamais une devinette
:::textcardbloc textcard (IM2.2)
background imagecouche de fond du plan : bloc panel du plan 24 ou fond du cadre commun (blocks/frame.tsx), à trancher en ST2.1
background couleurfond du plan
background vidéoerreur en P11 (question 8)
dur, holddur, hold
notesvoiceover
ctaperdu dans le film (un lien ne se clique pas dans un MP4) : avertissement

Dans l'autre sens, un récit format: motion devient une story en changeant format: : chaque plan devient une carte type=… avec son dur, et voiceover devient notes. Le sur-ensemble du §4.2 rend ce sens sans perte.

  • storiesToFilm vit dans @recit/stories/motion (sous-chemin : le lecteur n'importe pas @recit/motion pour une story sans bloc). recit render launch.md reconnaît le format ; pas d'option --as motion (même proposition que la question 10 du plan 24).
  • Les autres ponts de P11 (08 §0) : report → stories (chaque :::kpi ou ::chart → une carte ; 11 IM3 précise :::kpi → textcard variant=stat) et calendar → stories (les prochains événements → une story « à venir »). Ils dépendent de @recit/data (P6) et de @recit/calendar (P10) et forment le lot ST2b.
  • stories → toon (14 D6 : une carte = une case) est « plus tard », hors P11.

6. CLI et MCP

CommandeEffetLot
recit init --format storiesstory Lorem de quatre cartesST1
recit dev launch.mdaperçu du lecteur, rechargement à chaud (src/stories/client.tsx)ST1
recit build launch.mdlecteur statiqueST1
recit validate [--strict] launch.mdschéma, densité, alt, cta, blocs, paritéST0
recit convert launch.md --to json|mdjumeau, forme canoniqueST0
recit export launch.md --to imagesPNG par carteST3
recit render launch.mdfilm 9:16ST2

MCP (@recit/mcp), sans appel de modèle : describe_format accepte stories ; validate_story (générique, proposé par le plan 24) ; ressource recit://guide/stories (une idée par carte, jamais de chiffre inventé : la règle d'or du guide motion vaut ici), reprise par recit skills export. Les outils build_film et apply_ops restent propres au film.

7. Le site story.recit.dev

  • sites/story : Markdown et config (createSiteConfig({ site: "story" }), styles.css, vercel.json), composants dans @recit/site-kit, exemples en devDependencies (ST-20).
  • Accueil : une story jouable (tap, balayage), rail de vignettes ; galerie : lancement, cartes de texte (examples/stories-textcards, plan 11), « rapport en cartes » et « à venir » quand les ponts ST2b existent ; exports : PNG et MP4 par exports.json. Aucune doc propre : docs.recit.dev › Formats › Stories.
  • Port local 3009, e2e 4309, projet Vercel recit-story, alias 301 stories.recit.dev (07). Le projet Vercel et le DNS restent à l'utilisateur.
  • Référencement. Métadonnées Open Graph, hreflang, et JSON-LD par le sous-export @recit/core/jsonld prévu en P10 (03 §8). Le format Web Stories de Google repose sur AMP (amp-story) : une sortie AMP serait une seconde vue de la story. Ce plan ne la promet pas (question 4) ; l'état du programme est à vérifier au moment de ST4.

8. Les exemples

DossierContenuLanguesLot
examples/stories-launchsix cartes Lorem : titre, chiffre :value sur des données Lorem, bloc stat, liste, citation, CTAen, frST4
examples/stories-textcardsles cinq variantes de textcard (plan 11)en, frIM2.5 (P11)
examples/stories-characterkit de personnage Lorem, planche synthétique (plan 11)en, frIM4, plus tard
  • Lorem Ipsum, aucun nom réel, aucun asset tiers. Fonds en SVG et dégradés écrits par un script de l'exemple ; pas de vidéo commitée dans les exemples. La vidéo de fond est testée par une fixture courte générée par script dans Chromium (canvas et MediaRecorder), dans les tests seulement.
  • launch.md et son jumeau launch.json (commité ou non, l'aller-retour est testé dans les deux cas).
  • Les sources ne passent jamais par oxfmt ; ligne au NOTICE.md dans le même changement.

9. Tests

NiveauCe qui est vérifiéOù
Schéma et jumeaustoriesScene et son inverse, ::cta, props en YAML, fond objet ou chaîne ; aller-retour ; erreurs avec ligne ; parité ; sur-ensemble de motion (un récit motion change de format sans perte)packages/core/src/__tests__/, source-conversion.spec.ts
Modèle et pontsdensité, storiesToFilm (table d'inférence, fonds, durées, cta perdu avec avertissement), motion → storiespackages/formats/stories/src/__tests__/
Composantsune story par composant avec play : avancer au tap et au clavier, pause (bouton, appui long), CTA atteignable au clavier, barres de progression lues comme telles, RTL ; axe en erreurX.stories.tsx, pnpm test:stories
Horlogelecture automatique avec une horloge factice (pas d'attente réelle), pause sur onglet caché, mouvement réduittests unitaires
CLIdev, build, convert, validate, export --to images (nombre, taille 1080×1920), renderpackages/cli/src/__tests__/
e2e, sitestory.recit.dev en clair et sombre, mobile et bureau ; tap, clavier, balayage (événements pointeur de Playwright) ; changement de langue ; ?card=Ne2e/site-story.spec.ts, captures -linux
e2e, exportsPNG des cartes (taille, nombre, deux langues), MP4 du pont (durée)e2e/stories-export.spec.ts
Storybooksurface stories de la galeriee2e/storybook-stories.spec.ts

Les noms suivent la convention des specs (*.spec.ts, une spec par surface de Storybook) ; le plan 11 (§ tests) écrit encore e2e/stories.e2e.ts. Seuils de couverture : une ligne packages/formats/stories/** dans le vitest.config.ts racine.

10. Lots

Identifiants ST0 à ST6 : ST1 à ST4 reprennent 08 §6, ST0, ST2b, ST5 et ST6 sont nouveaux. IM1 et IM2 (plan 11) sont logés dans cette phase et se coordonnent avec ST1 à ST3.

Code
(question 1) ─► ST0 ─► ST1 ─┬─► ST2 ──┬─► ST4 ─► ST6 ├─► ST3 ──┤ └─► ST5 ──┘ IM1, IM2 (plan 11) ─► ST2, ST3 P6, P10 ─► ST2b

ST0 — Le jumeau (M)

Dépend de : la question 1 (un renommage se fait ici ou jamais avant la 1.0), et les questions 2 et 7. Fichiers : packages/core/src/schema/source.ts, convert.ts, parity.ts, packages/core/src/config/validate.ts (StoriesConfigSchema), packages/core/schema/v1/stories.json.

  • ST0.1 — StoriesSceneSourceSchema, StoriesSettingsSourceSchema, StoriesSourceSchema strict ; sceneBlockFields partagé avec motion ; ImageSourceSchema si la question 7 le retient.
  • ST0.2 — storiesScene et l'écriture canonique ; erreurs avec ligne.
  • ST0.3 — Parité ; fixtures Lorem ; test « un récit motion change de format sans perte ».
  • ST0.4 — pnpm -F @recit/core schema:json ; version plan prerelease pour @recit/core.

Sortie : aller-retour octet pour octet sur toutes les fixtures ; examples/motion-hello, passé en format: stories, valide sans retouche hors :::notes.

TerminalBash
pnpm exec vitest run packages/core/src/__tests__/source-conversion.spec.ts pnpm test:related packages/core/src/schema/convert.ts && pnpm check

ST1 — Le paquet et le lecteur (L)

Dépend de : ST0. Fichiers : packages/formats/stories/** (paquet publiable, ./styles.css), packages/cli/src/stories/, packages/cli/src/index.ts, packages/integrations/site-stories/src/plugin.tsx et vite.ts, et packages/components si ST1.2 y déplace le rendu commun.

  • ST1.1 — compileStories(story) : cartes typées, densité, budget.
  • ST1.2 — Rendu d'une carte Markdown : réutilisation de SceneContent, mesure du bundle, décision écrite dans ce plan.
  • ST1.3 — Composants du §5.1, gestes, horloge, mouvement réduit ; stories avec play.
  • ST1.4 — recit init --format stories, recit dev, recit build.
  • ST1.5 — Branche stories de site-stories, StoryEmbed format="stories", routes par langue.
  • ST1.6 — Version plan preminor pour @recit/stories, prerelease pour @recit/cli et @recit/site-stories.

Sortie : une fixture se lit au tap, au clavier et au balayage dans recit dev et dans examples/site-embed ; compteurs de style et de stories à 0 ; aucune nouvelle tolérance dans scripts/check-package-boundaries.js.

TerminalBash
pnpm exec nx run stories:build && pnpm -F @recit/stories typecheck pnpm test:stories packages/formats/stories && pnpm check

ST2 — Blocs motion et pont stories ⇄ motion (M/L)

Dépend de : ST1, le bloc panel du plan 24 (W4), IM2.2 pour textcard. Fichiers : packages/formats/stories/src/motion/, packages/formats/motion-blocks/src/blocks/frame.tsx (fond), packages/formats/motion/src/schema/, packages/cli/src/motion/source.ts.

  • ST2.1 — Fond d'image d'un plan : panel ou cadre commun, décision écrite ici.
  • ST2.2 — Cartes type=… jouées dans le lecteur.
  • ST2.3 — storiesToFilm, recit render launch.md ; sens motion → stories.
  • ST2.4 — Avec IM2.3 : une textcard comme carte.

Sortie : recit render examples/stories-launch/launch.md produit un MP4 9:16 ; le même fichier passé en format: motion se joue sur motion.recit.dev. Version plan prerelease pour @recit/motion et @recit/motion-blocks.

ST2b — Ponts report → stories et calendar → stories (M)

Dépend de : @recit/report et @recit/data (P6, plan 23), @recit/calendar (P10, plan 27). Correspondances de 08 §0 et 11 IM3, en erreur explicite hors table. Peut glisser après P11 sans bloquer sa sortie (question 9).

ST3 — Les images (S/M)

Dépend de : ST1 et @recit/paged/runner (P6). Fichiers : StoriesImagesOptionsSchema, packages/cli/src/commands/export-*.ts, ExportManifestSchema.

  • ST3.1 — Capture par carte (?card=N&settled=1, échelle 3), encodage dans Chromium.
  • ST3.2 — exports.json, --all-locales, --to pdf refusé avec son message.

Sortie : recit export examples/stories-launch/launch.md --to images --all-locales produit douze PNG 1080×1920 listés dans exports.json.

ST4 — Exemple, site, doc (M)

Dépend de : ST2, ST3. Fichiers : examples/stories-launch/**, sites/story/**, packages/tools/site-kit/src/sites.ts, e2e/ports.ts, scripts/e2e-projects.js, e2e/site-story.spec.ts, e2e/stories-export.spec.ts, e2e/storybook-stories.spec.ts, page docs Formats › Stories, NOTICE.md.

  • ST4.1 — examples/stories-launch (en, fr).
  • ST4.2 — sites/story, entrée story de SITES, métadonnées de partage.
  • ST4.3 — Doc : syntaxe, JSON Schema, ponts.
  • ST4.4 — e2e et captures : pnpm test:e2e:update:linux e2e/site-story.spec.ts.

ST5 — MCP et guide (S)

describe_format pour stories, recit://guide/stories, validate_story s'il n'existe pas déjà (plan 24, W6.1). Sortie : un agent qui lit le guide écrit une story Lorem qui passe recit validate --strict.

ST6 — Clôture (S)

pnpm verify, pnpm test:e2e:linux e2e/site-story.spec.ts e2e/stories-export.spec.ts e2e/storybook-stories.spec.ts, seuils de couverture, version plans relus, mot « carte » proposé au glossaire d'AGENTS.md, note datée dans journal.md.

Critères de sortie de P11

Ceux de 06 P11 :

  • examples/stories-launch se lit au tap, au clavier et au balayage ;
  • l'export d'images et le pont vers motion (MP4 vertical) fonctionnent ;
  • la version 0.7.0-alpha est publiée (après le go de l'utilisateur).

Proposés par ce plan : story.recit.dev en ligne (stories.recit.dev redirige), comme les autres phases de format ; jumeau de chaque exemple en aller-retour ; lecteur conforme à WCAG 2.2.2 (pause).

11. Risques

RisqueParade
Confusion entre Story (modèle) et stories (format)glossaire, « une story (format stories) » dans la doc ; question 1 avant ST0
Lecture automatique inaccessiblebouton de pause toujours visible, mouvement réduit, horloge testée
Le lecteur tire le runtime du deck ou de motion dans le bundleST1.2 mesure ; sous-chemin ./motion ; blocs motion chargés à la demande
Gestes qui se battent avec le défilement de la page hôte (embed)gestes actifs seulement en plein écran ou sur la carte ; e2e sur examples/site-embed
P6 ou P10 en retard : ponts report et calendar absentsST2b séparé, hors des critères de P11
Vidéos de fond lourdesbudget de poids, préchargement d'une seule carte, première image sous mouvement réduit
Web Stories de Google dépendantes d'AMPpas de promesse AMP (question 4) ; métadonnées standard
type= ouvre la carte à tous les blocs, y compris ui-scene trop chargédensité appliquée aussi aux props textuelles ; liste blanche de blocs si besoin

12. Questions ouvertes

  1. Le nom du format. stories partage son mot avec le modèle Story. Le renommer est une décision de produit (AGENTS.md) que ce plan ne prend pas. AGENTS.md dit qu'elle figure dans 06, où ne se trouve que la question 11 (sens de story.recit.dev). Un renommage toucherait : STORY_FORMATS et StoriesSourceSchema (@recit/core), l'URL recit.dev/schema/v1/stories.json (figée à la 1.0), la clé stories: de recit.config (aujourd'hui réservée au format, avec les refus de l'ancienne section de site), @recit/stories et packages/formats/stories, formats.ts de site-kit, l'alias stories.recit.dev, l'icône fmt-stories. Garder stories, ou renommer — et dans ce cas, avant ST0 ?
  2. dur et aspectRatio. 08 §6 et 09 §2.3 écrivent duration: 5s et aspect: 9:16 ; le cœur a déjà dur (secondes) et aspectRatio. Prendre les mots existants (recommandé) ?
  3. Sens de story.recit.dev (06, question 11, toujours ouverte) : stories web (ce plan), ou user stories de backlog ?
  4. AMP et Web Stories. Faut-il une sortie AMP (amp-story) pour l'indexation par Google, ou les métadonnées standard suffisent-elles (recommandé pour P11, spike après) ?
  5. Sondages. 08 §6 prévoit :::poll en v2, avec un stockage. Proposition : un sondage est un :::form du plan 10 (contrat d'API, aucun service hébergé par Récit), pas un bloc nouveau. D'accord ?
  6. Seul 9:16 ? D'autres rapports (4:5) en P11, ou plus tard ?
  7. Un seul type d'image. Renommer DeckImageSchema en ImageSourceSchema et le partager entre l'image du deck, le fond d'une carte et la couverture ?
  8. Fond vidéo dans le film. Erreur en P11 (proposé), ou incrustation de la vidéo dans le plan Remotion ?
  9. Ponts report et calendar. Dans les critères de P11 (08 §0 les y range), ou après, selon l'avancement de P6 et P10 ?
  10. Lecture automatique par défaut. autoplay: true par défaut (comme les réseaux), ou false (plus accessible) ?