Reel — Montage Story (plein cadre avec mouvement)
L'intervenant reste en plein écran. L'histoire est racontée par des coupures vers ses propres clips,
des stickers/cartes/widgets qui apparaissent sur les mots prononcés, une mascotte qui réagit, et
des moments de profondeur où des mots géants ou un arrière-plan de marque se trouvent derrière l'intervenant
(masque de personne). Exemple concret : examples/story/story_stoodi_inviteraw.py.
Arguments : $ARGUMENTS
Valeurs par défaut (modifier uniquement si l'utilisateur le demande)
Lire d'abord reel.config.json (sinon reel.config.example.json).
| Élément | Valeur par défaut |
|---|---|
| Sous-titres | Aucun. Les graphiques de mots-clés sont acceptables ; jamais de transcription continue |
| Audio | Mix original de la prise, inchangé — finish.py le remuxe. Pas d'effets sonores, pas de musique d'ambiance |
| Prise | Supposer déjà montée, étalonnée, musique ajoutée → ne pas couper ni étalonner. Brute/non montée → demander d'abord |
| B-roll | broll_dir depuis la configuration ; descriptions dans work/_catalog/<dossier>/NOTES.md |
| Marque | brand + palette depuis la configuration. Pas de fichiers mascotte → pas de scènes de mascotte |
| Appel à l'action | Mot-clé de commentaire géant à l'écran ; carte « Suivre » = texte @<handle du créateur> uniquement, jamais de visage recadré |
| Langue | language depuis la configuration (Whisper + quelle classe de texte utiliser) |
Entrées
Le nom de la prise et le sujet proviennent des arguments. Demander une fois, en un seul message, uniquement ce qui manque : la prise est-elle déjà montée/étalonnée/avec musique ; mot-clé de commentaire ; noms ou jargon que Whisper pourrait mal entendre ; clips qu'ils veulent inclure ou exclure.
Pipeline
PY = .venv/Scripts/python.exe -X utf8 (Windows) ou .venv/bin/python -X utf8 (macOS/Linux). Étapes longues en arrière‑plan.
| # | Étape | Commande / action | Vérification |
|---|---|---|---|
| 1 | Regarder | ffprobe la prise ; contact sheet ffmpeg -i raw/<prise> -vf fps=1/5,scale=216:384,tile=9x2 -frames:v 1 work/<prise>/sheet.jpg et regarder | espace au-dessus de la tête, texte dans le cadre inversé ?, déjà étalonné ? |
| 2 | Transcrire | $PY tools/transcribe.py <prise> --prompt "<noms, jargon>" | relire les noms ; écarts de mots > 3 s → retranscrire cette fenêtre |
| 3 | Visage | $PY tools/face_track.py <prise> | affiche FACE = (x, y) et le haut de la tête |
| 4 | B-roll | $PY tools/story_assets.py <prise> catalog ; lire NOTES.md ; regarder les bandes des clips non décrits encore et ajouter leurs lignes dans NOTES.md | Indicateurs HDR / inversé / VFR |
| 5 | Feuille de rythme | écrire work/<prise>/beats.md : temps | mots | mode | quoi. Règles ci-dessous, techniques dans references/techniques.md | chaque temps fort ancré à un mot |
| 6 | Masque | si moment de profondeur : $PY tools/story_assets.py <prise> matte (~8 min CPU pour 80 s, arrière‑plan, pas de ffmpeg en parallèle) | work/<prise>/matte/fg.webm |
| 7 | Module de prise | copier examples/story/story_stoodi_inviteraw.py → tools/story_<slug>.py (slug : nom de la prise, non‑alphanumériques → _) ; définir NAME, FACE, BROLL, TILES, MIRRORED, scènes, SCENES (DUR optionnel — détecté). Noms de mascottes = les fichiers dans assets/mascot (minuscules, espaces → -) | |
| 8 | Actifs | $PY tools/story_assets.py <prise> all (mascotte, logo, rognages B-roll, tuiles) | |
| 9 | Construction | $PY tools/story_build.py <prise> ; dans work/<prise>/sc : npx hyperframes lint public → 0 erreurs (avertissements nested_structure attendus) ; npx hyperframes snapshot public -o ../snaps --no-end --describe false --at <chaque temps fort> ; lire les contact sheets, corriger, reconstruire | |
| 10 | Rendu rapide | $PY tools/finish.py <prise> --seconds 12 ; lire work/<prise>/sc/quick_sheet.jpg | les superpositions entrent et sortent ; couleurs pas ternes |
| 11 | Rendu complet | $PY tools/finish.py <prise> (~12 min pour 80 s, arrière‑plan) → final/<prise>/, vérifier, qa/sheet.jpg | lire la sheet image par image |
| 12 | Rapport | chemin, durée, temps forts, clips utilisés, tout élément retourné/re‑mappé tonalement, vérifier le résultat. Si quelque chose de nouveau a été appris, l'ajouter à cette compétence |
Règles des temps forts
- Quelque chose change toutes les 2 à 4 s ; jamais plus d'environ 5 s d'intervenant nu.
- Mélanger les modes : intervenant + stickers · coupure B-roll (~25–30 % du temps) · moment de profondeur (4–6 par reel) · graphique plein écran avec l'intervenant en bulle facecam (1–2 max).
- Repère = heure de début du mot prononcé dans
transcript.json. Chaque élément part avant le temps fort suivant. - Les mots de profondeur vont au-dessus de la tête (haut de la tête depuis l'étape 3) : un mot géant à la fois, le mot précédent s'envole. Les lignes empilées finissent cachées derrière la tête.
- Zones de sécurité : pas de texte au-dessus de y 150 (en‑tête Instagram) ni en dessous de y 1560 (légende) ; garder x < 960 entre y 1100–1650 (boutons j'aime/commentaire).
- Les chiffres présentés comme des faits doivent provenir de la prise. Les étiquettes illustratives sont acceptables.
- Texte farsi/arabe : classe
.fa(RTL limité à l'élément — jamaisdir="rtl"sur<html>, cela rend en noir),letter-spacing: 0, chiffres viafa(), un grand zéro en latin0(le zéro persan est un point). Texte latin :.en; mots d'affichage géants :.blk.
Contrat du moteur — bugs déjà payés
- Scène =
def scene(c: Comp):c.clip(calque, id, debut, fin, html, piste),c.broll(nom, a, b, mstart),c.matte(n, a, b),c.j(js...). Calques :under(derrière la bulle),tiles,behind(entre la prise et le masque),fw,broll,over,fx. - Les divs de clip reçoivent un id
k-<id>; animer#<id>-iou des ids internes — jamais un.cliplui‑même. - Tout élément qui glisse depuis l'extérieur de l'écran a besoin de
autoAlpha:0dans son état de départ, sinon il apparaît trop tôt. - La première interpolation d'un élément définit son état initial (
fromTorend immédiatement) ; interpolations suivantes :.toouimmediateRender:false. - Jamais de décalages
from:"random"niMath.random— mélanger l'ordre du DOM en Python avecrandom.Random(seed). - Même propriété, même élément : une interpolation doit se terminer avant que la suivante ne commence (lint
overlapping_gsap_tweens). #camscale/x/y/clipPath/borderRadius pilotent les zooms, la bulle et la mosaïque. Le masque vit à l'intérieur de#cam, donc les moments de profondeur restent alignés à n'importe quelle échelle de caméra.- B‑roll de la caméra avant avec texte lisible dans le cadre → ajouter à
MIRRORED. Ne jamais inverser la prise principale. - Les sources HLG/HDR sont re‑mappées tonalement par
story_assets.py. Sifinish.pys'arrête sur « HDR auto‑promotion », une source a échappé à ce chemin. hyperframes snapshotn'est pas une preuve du rendu — c'est à cela que sert l'étape 10.