Sous-titres + incrustations pour bobine
Prend une bobine 9:16 déjà montée (généralement 2160x3840 à 30 ips, par exemple la sortie de talking-head-edit) et y ajoute des sous-titres et des incrustations. Le tout est piloté par un seul fichier edit.json (pages de sous-titres et incrustations, en trames) que les deux moteurs de rendu lisent, de sorte que les versions HyperFrames et Remotion correspondent trame par trame.
SK=~/.claude/skills/reel-captions-overlays
PY=$($SK/scripts/find_python.sh) # faster-whisper large-v3 + opencv ($REELKIT_PYTHON, le .venv du dépôt, ou python3)
AUDIO_PY=~/.cache/reel-audio/venv/bin/python # étape musicale (créé par scripts/setup_audio.sh)
ANA_PY=~/.cache/reel-audio/analysis-venv/bin/python # analyse du style de référence (créé par scripts/setup_audio.sh --analysis)
Outil par défaut : HyperFrames (Apache-2.0, épinglé [email protected]). Remotion (4.0.539) est conservé comme build de parité. Remotion est gratuit pour les particuliers et les entreprises de jusqu'à 3 personnes ; une entreprise plus grande a besoin d'une licence payante pour une utilisation commerciale (remotion.pro/license). HyperFrames n'a pas une telle condition de licence.
Flux de travail
- Configuration (premier passage).
$SK/scripts/new_reel.sh <reel.mp4> <workdir>Cela transcrit avec des horodatages de mots (large-v3), détecte les boîtes de visage toutes les 0,5 s (faces_src.json) et les coupures de plan (cuts.txt), copieoverlays.example.jsonvers<workdir>/overlays.json, puis s'arrête. - Remplir
overlays.json. Lisez d'abordwords_raw.json.corrections: corrigez les noms de marque par séquence de tokens, par exemple["Ackme"]→"Acme",["re","-motion,"]→"Remotion,",["Acme","Voice."]→"Acme Voice.". Coller les paires de marques en un seul token les maintient sur une seule page de sous-titres. Conservez les lignes en langue étrangère exactement comme elles sont prononcées (par exemple "Même voix, autre langue.").sansWindows:[début,fin]secondes de séquences B-roll, d'écrans de capture et de plages promptDemo. Les sous-titres y passent au sans empattement lourd (même couloir à 75 %).overlays: voir la spécification de style ci-dessous et le Plan graphique. Les heures sont en secondes, tirées des horodatages des mots.sponsored: truepour une bobine payante ou de marque. Cela active la règle de battement de démonstration (Bobines sponsorisées ci-dessous) et l'avertissement de vérification.
- Construire les deux projets.
$SK/scripts/new_reel.sh <reel.mp4> <workdir> <workdir>/overlays.json - Regarder avant le rendu.
cd <workdir>/hyperframes && npx [email protected] snapshot --at 2.5,20,30 --no-end(ounpx remotion still Reel x.png --frame=N --scale=0.5dansremotion/). - Rendu. Ceux-ci ont besoin de Chrome, alors exécutez-les en dehors du sandbox Bash (
dangerouslyDisableSandbox). À l'intérieur, Chrome crève sur les recherches de port Mach.<workdir>/hyperframes/render.sh <out>_captions_hyperframes.mp4effectue le rendu d'une mise en page 1080x1920 suréchantillonnée en 2160x3840 à CRF 16 avec faststart.<workdir>/remotion/render.sh <out>_captions_remotion.mp4fait de même avec--scale=2, CRF 16, AAC 192k et faststart, puis exécutescripts/repair_remotion.py(voir les Pièges).
- Vérifier.
$PY -I $SK/scripts/verify.py <reel.mp4> <out.mp4> <workdir>/edit.json <workdir>/faces_src.json <workdir>/qc <label>(sort 1 et imprime ÉCHEC si les trames, les trames corrompues, la lisibilité, les bords de carte ou l'offre CTA échouent ; environ 9 minutes sur une bobine 4K de 60 s)- Elle vérifie que le nombre de trames et la durée correspondent à la source.
- Elle analyse chaque trame pour détecter la corruption (une trame vidéo erronée ou des tuiles noires).
corrupt_framesdoit être 0. - Elle vérifie ponctuellement 5 pages de sous-titres : la bande doit être vide 1 trame avant qu'une page ne commence et remplie 2 trames après.
- Elle mesure le changement de pixels de la boîte de visage sous chaque incrustation. Cela devrait être environ 0, à l'exception de l'écran de capture plein écran et des cartes promptDemo, qui couvrent délibérément le visage (ils sont exclus des vérifications de visage, de trame corrompue et de lisibilité).
- Elle liste les
demo_beats(incrustations promptDemo, ou toute incrustation avec"demo": true). Lorsqueedit.jsonasponsored: trueet qu'il y en a moins de 2, elle imprime un AVERTISSEMENT et l'ajoute auxwarnings(pas un échec dur ; corrigez la bobine ou dites pourquoi dans le rapport). - Séparateur AVANT/APRÈS (v7, avertissement). Pour chaque paire de lignes avant -> après de promptDemo, elle rapporte
before_after: les mots que les deux clips partagent, l'écart dans le montage et le silence mesuré dans le rendu, et si le montage a la bande de commutation et l'effet sonore de commutation (build_editba). Une paire qui répète des mots sans tout cela (écart >= 400 ms, bande, SFX) imprime un AVERTISSEMENT : une ligne répétée sans séparateur se lit comme un défaut de montage (voir promptDemo). - Offre CTA (v7, vérification dure). Un
ctaavec uneofferdoit être entièrement visible >= 2,5 s, à >= 40 px (13+ px sur un téléphone 360px), et effectivement dessiné (changement de pixel dans sa bande).<label>_offer_mobile.jpgle montre à la taille du téléphone ; regardez-le. Une bobine sponsorisée dont le CTA n'a pas d'offerreçoit un AVERTISSEMENT. - Lisibilité à la taille du téléphone : elle réduit 8 pages de sous-titres à 360px de large et mesure l'épaisseur des hampes, la hauteur du texte et
le halo de contour (luminosité du glyphe moins l'anneau qui l'entoure). Minimums : hampe >= 4,0 px, hauteur >= 28 px, halo >= 130.
legibility_okdoit être vrai.<label>_mobile.jpgmontre les recadrages ; regardez-le. - Elle écrit une feuille de contact avec un arrêt sur image au milieu de chaque incrustation, et une feuille de recadrage synchronisée. Ouvrez les deux avant de faire votre rapport.
- Musique + Effets sonores (étape par défaut ; sauter avec
--no-musicouMUSIC=0). Remplissez<workdir>/music_plan.json(copié demusic_plan.example.jsonlors du premier passage ; il utilise le préréglage de style par défautsteady-funk-bed; voir Musique et conception sonore ci-dessous), puis$SK/scripts/music_stage.sh <out_hyperframes.mp4> <workdir> <out>_music.mp4Cela mixe le lit sonore et les effets sonores sous la voix, le multiplexe sur l'image avec une copie du flux vidéo (pas de ré-encodage) et l'audio ajusté à la durée de la vidéo, crée la copie téléphone<out>_music_mobile.mp4(MOBILE_OUT=pour la mettre ailleurs) et exécutemusic_verify.py, y compris la vérification de style par rapport au préréglage du plan. Elle doit imprimer RÉUSSI. Elle refuse de écraser une sortie existante (FORCE=1pour autoriser). Elle échoue également toute phrase dont la parole est inférieure à 6 dB au-dessus de la musique en dessous (voice_over_musicdans le rapport,--min-voice-over-music) : ce qui importe, c'est de savoir si chaque ligne peut être bien entendue. Le lit est un groove régulier non-ducking à environ 13 dB sous la voix, donc une phrase calme peut s'y enfoncer même lorsque la moyenne de la section passe. Corrigez un échec en amont, avec l'égalisation de la parole de talking-head-edit ou un gain par segment, pas en baissant tout le lit. Une bobine d'interview typique qui réussit mesurait 11,2 dB min et 14,1 dB médian. Ouvrez<workdir>/qc/music_sections.png. La première exécution crée~/.cache/reel-audio/venv(scripts/setup_audio.sh). - Copie téléphone (pour l'envoi, lorsque l'étape musicale a été sautée) :
ffmpeg -i <out.mp4> -vf scale=720:1280:flags=lanczos -c:v libx264 -preset slow -crf 22 -maxrate 2800k -bufsize 5600k -pix_fmt yuv420p -c:a copy -movflags +faststart <out>_mobile.mp4(environ 14-19 Mo pour 60 s, en dessous de la limite de 25 Mo). Copiez l'audio masterisé, ne le ré-encodez jamais : un second encodage AAC à 128k a fait passer le vrai pic d'une bobine de -1,3 à -0,7 dBTP.
Spécification de style (d'après la bobine de référence)
Toutes les tailles ci-dessous sont dans l'espace de conception 1080x1920 (rendu à 2x). Le CSS partagé est templates/style.css.
- Sous-titres (v2 : les sous-titres v1 étaient de fines lignes blanches, difficiles à lire sur un téléphone. Plus lourds, plus grands, soulignés est la valeur par défaut.)
- Un mot par page, occasionnellement deux : un mot-outil court rejoint son voisin, et les paires de marques sont collées.
- Le texte est en casse et avec la ponctuation telles qu'elles sont prononcées ("contenu.", "Ensuite"). Ne le mettez jamais en majuscules. Pas de surbrillance par mot : avec 1-2 mots par page, cela ajoute seulement du bruit.
- Police : DM Serif Display (inclus, épinglé
@fontsource/[email protected], OFL) en 136px, blanc. Ne revenez jamais à une fine police avec empattement telle que Instrument Serif regular pour les sous-titres. Instrument Serif reste pour les titres de cartes sur papier ou rouge. - Contour : une copie du mot avec un trait (
::beforeavecdata-t,-webkit-text-stroke: 6px, donc 3px à l'extérieur du glyphe) dans un noir presque pur à 86 %, peint derrière le remplissage afin qu'il n'amincisse jamais les lettres. Ombre : 0 0 3px, 0 5px 12px et 0 14px 34px, toutes sombres. - Ajustement :
build_edit.pydéfinitfspar page à partir detemplates/fonts/caption_metrics.jsonafin qu'une page ne dépasse jamais 820px (par exemple "automatiquement." à 127px). Régénérez les métriques avecscripts/caption_metrics.pysi la police change. - Placement : une voie centrée à 75% de la hauteur (y=1440), en dessous des mains de l'orateur et du micro et au-dessus de l'interface utilisateur des 20 % inférieurs. Elle descend au menton + 6% (plafonné à 76%) uniquement sur les gros plans. Sur une configuration de bureau typique, les mains se situent à 55-72 %, donc une voie "sous le menton" (60 %) repose sur les mains.
- Animation : un pop de 4 trames (échelle 0,86→1, y 14→0, fondu) qui commence une trame plus tôt, de sorte que le mot soit visible sur sa première trame.
- Les pages commencent exactement à la trame de début du mot et se maintiennent jusqu'à la page suivante, ou jusqu'à la fin du mot + 0,2 s en cas de pause.
- Sous-titres B-roll et écran de capture : Inter 900 en 120px avec tracking -0,03em, même contour et même voie à 75%.
- Carte titre (
titleCard, pour la phrase d'accroche)- Un bloc rouge brique
#B23A2E, 810px de large (75 %), avec son sommet à y=190. - Ligne du haut : Anton EN MAJUSCULES en 118px. En dessous, un sous-titre Instrument Serif blanc en 62px.
- Son bas se situe à environ 23 % de la hauteur du cadre. C'est délibérément plus haut que la référence (bord supérieur 22-28 %), car le visage commence à environ 26 %.
- Un bloc rouge brique
- CTA (
cta)- Un "Comment" italique serif blanc (82px) au-dessus d'un bloc rouge avec le mot-clé Anton (196px, par exemple "GUIDE"). Même bande supérieure que la carte titre.
- Le bloc apparaît en 3 trames après le kicker.
- Ligne d'offre (
offer, bobines sponsorisées, v7) : l'offre de la marque sous le menton sur une carte en papier, par exemple "Utilisez mon lien pour un ESSAI GRATUIT de 14 jours." Utilisez le libellé de la marque.\ndéfinit le saut de ligne, et les mots EN MAJUSCULES ("GRATUIT") obtiennent un bloc blanc sur rouge. "Comment / WORD" reste l'élément principal ; l'offre est la ligne secondaire.build_edit.pydériveofferF(deofferAt, par défaut le début du CTA + 10 trames),offerY(menton + 3 % de--facessur la fenêtre CTA, maintenu à 55-60 % de la hauteur, au-dessus de l'encre du sous-titre à environ 1385px) etofferFs(Inter ajusté à 720px, max 46px ; il avertit en dessous de 40px). La carte fait 780px de large (x 150-930, dégagée de l'interface utilisateur du côté droit) et inclinée de -1,5°. - L'offre doit être entièrement à l'écran >= 2,5 s. Si la bobine se termine trop tôt après que l'orateur a dit le CTA, maintenez la
dernière trame :
$SK/scripts/hold_end.sh <reel.mp4> <frames> <reel_hold.mp4>copie en flux la coupe, ajoute N copies encodées de sa dernière trame avec un silence numérique, et vérifie que la parole se décode de manière identique à l'échantillon. Choisissez N de sorte que la bobine se termine juste avant un battement musical (battement k = k * 60 / bpm aveccue_at0), définissez laenddu CTA et laendde la section du plan musical à la nouvelle durée, et exécutez build_edit avec la nouvelle--frames. Le lit joue sous le maintien et coupe avec la dernière trame (exemple : 32 trames, se terminant à 68,2 s, juste avant le battement 125 d'un lit à 110 BPM à 68,207 s ; offre complètement affichée 3,2 s).
- Écran de capture (
takeover, pour une mention d'outil ou de produit, maintenu 1,5-3 s)- Un fond rouge foncé plein écran
#8E1F17avec une subtile grille 8x14 rouge plus clair. - Une pilule de recherche arrondie blanche (loupe à gauche ; micro et objectif à droite) dont la requête en italique gras s'écrit sur 14 trames.
- En dessous, une carte arrondie blanche avec le nom de l'outil (serif 128px), une description d'une ligne, une forme d'onde rouge et 2-3 chips.
- Ne simulez jamais une véritable interface utilisateur de produit. Utilisez la carte neutre avec du texte uniquement. La voix continue en dessous.
- Un fond rouge foncé plein écran
- Carte flottante (
floatCard, pour une statistique, un conseil ou une étiquette ;kickeretwidthoptionnels)- Une carte en papier
#FBF7F1, 470px de large, avec son sommet à y=200, sur le côté gauche ou droit. Tournée de ±3-4° avec une ombre profonde. - Le contenu est soit un kicker optionnel + un grand nombre Anton + une étiquette serif + une ligne en petites capitales, soit une variante drapeau :
flag: "es"(kicker + drapeau CSS + mot) ouflag: "us-es"(kicker "Même voix, autre langue" + drapeau US → drapeau ES + mot). - Les drapeaux emoji sont dessinés en CSS, afin qu'ils ne dépendent jamais d'une police emoji.
- Une carte en papier
- Liste d'étapes (
steps) : une carte en papier en haut (y 150) avec un kicker rouge et des lignes numérotées (DM Serif 54px). Chaque élément a son propre tempsatet apparaît lorsque l'orateur le dit ; le numéro actuel est rouge, les lignes précédentes sont atténuées. À utiliser lorsque l'orateur dit "trois étapes", "d'abord... puis". - Division avant/après (
split) : deux volets inclinés côte à côte en haut, foncé "Ancienne méthode" (barré) et rouge "Nouvelle méthode". Le nouveau pan
...
[tronqué pour la traduction]