Bilingual Story Video(双语打字机故事视频)
Entrez un thème, recevez une vidéo éducative verticale. Chaque scène = fond blanc initial + carte d'illustration (transition noir & blanc → couleur de gauche à droite) + sous-titres bilingues dévoilés mot par mot + narration en chinois synchronisée avec la bande dévoilée.
Environnement local (important, à lire d'abord)
Cette machine n'a pas de node system. La chaîne d'outils disponible :
- node/npm :
~/.local/node-bin/node(node copié depuis ChatGPT.app et resigné ad-hoc, peut charger des modules natifs). npm/npx utilise les scripts intégrés de ChatGPT. Exécutez d'abord dans chaque shell :⚠️ N'utilisez pas directementexport PATH="$HOME/.local/node-bin:/Applications/ChatGPT.app/Contents/Resources/cua_node/bin:$PATH"/Applications/ChatGPT.app/.../bin/nodepour lancer Remotion — il active la vérification de bibliothèque, ce qui provoque une erreur "different Team IDs" lors du chargement des modules natifs rspack. Si~/.local/node-bin/noden'existe pas, recréez-le :mkdir -p ~/.local/node-bin cp /Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node ~/.local/node-bin/node codesign --remove-signature ~/.local/node-bin/node && codesign -s - ~/.local/node-bin/node - ffmpeg :
~/.local/bin/ffmpeg(tts_generate.py le trouvera automatiquement). - edge-tts : python3 système installé (
pip3 install --user edge-tts). - SVG → PNG (pour les images de substitution ou illustrations SVG) :
qlmanage -t -s 1440 -o . file.svg. Attention : qlmanage force une sortie carrée pour SVG, la toile SVG doit être carrée (ex : 1440×1440), sinon elle sera étirée.
Workflow
1. Écrire l'histoire
Lisez d'abord references/story-writing.md (structure en trois actes, règles pour le texte et les prompts). Écrivez 3 à 6 scènes selon le thème. Chaque scène :
title: Grand titre, 6–10 mots, accrocheur (ex : "Il veut faire vingt câlins par jour").zh: Texte de narration en chinois, 18–30 mots, une phrase qui décrit l'image. Ce texte sert à la fois de sous-titre et de texte TTS. Remplacez les guillemets par des virgules (le TTS lit mal les guillemets).en: Traduction anglaise correspondante, naturelle.imagePrompt: Prompt pour l'illustration. Style uniforme (ex : "soft watercolor children's book illustration"), seulement des images couleur — la version noir & blanc est générée automatiquement par un filtre CSS de niveaux de gris, une image pour deux usages. La composition doit prévoir des espaces vides ; l'image sera recadrée en carte horizontale d'environ 1.4:1 (objectFit: cover, les bords haut et bas seront coupés).
Informations de série : meta.category (ex : "Parent-enfant"), meta.series (ex : "La croissance ne prévient pas").
2. Créer le projet
python3 scripts/new_project.py --output /chemin/absolu/vers/le/dossier/du/projet
cd dossier_du_projet && npm install --no-audit --no-fund
3. Remplir story.json
Modifiez public/story/story.json (structure dans l'exemple du modèle). Remplissez uniquement meta + id/title/zh/en/image/imagePrompt pour chaque scène ; les champs audio et timestamp sont générés par les scripts.
4. Générer les illustrations
Une image couleur par scène → public/assets/scene-<id>.png.
python3 scripts/gen_images.py /chemin/absolu/vers/le/dossier/du/projet
- Si
OPENAI_API_KEYest définie, appelle automatiquement gpt-image-1 pour générer. - Sans clé, le script écrit
ASSET_PROMPTS.md, en laissant l'utilisateur générer les images dans ChatGPT puis les placer danspublic/assets/; ou bien utilise un SVG carré dessiné + qlmanage pour le convertir en PNG comme substitut.
5. Générer la narration + les données temporelles
python3 scripts/tts_generate.py /chemin/absolu/vers/le/dossier/du/projet
Pour chaque scène : synthétise un MP3 dans public/audio/, enregistre la durée audio précise et conserve les données WordBoundary (mot par mot) dans story.json. Lors du rendu, la durée totale de la narration sert de piste unifiée : le texte apparaît linéairement mot par mot depuis la phase noir & blanc, puis la couleur recouvre, les deux se terminant exactement à la dernière image de la narration. Voix par défaut zh-CN-YunxiNeural (masculine, adaptée aux histoires parent-enfant), voix féminine possible avec zh-CN-XiaoxiaoNeural, à modifier dans meta.voice. Débit meta.rate (ex : -10%).
Les champs zh/en de story.json doivent exister avant d'exécuter ce script ; si vous changez le texte, relancez avec --force.
6. Prévisualiser une image fixe (obligatoire avant le rendu)
npx remotion still StoryVideo out/check.png --frame=<image au milieu de chaque scène> --overwrite
Vérifiez au moins 4 images clés par scène : première image, image de fin du noir & blanc, milieu de la couleur, dernière image. Durée de la scène = 1 + ceil(durée audio en secondes × fps), décalage cumulé scène par scène. Vérifiez : première image seulement fond beige ; texte déjà présent pendant la phase noir & blanc ; titre ne déborde pas ; illustration bien cadrée ; sous-titres chinois au maximum deux lignes ; anglais ne sort pas de la zone de sécurité ; dernière image avec couleur et texte à 100 %.
7. Rendu + validation
npm run render # sortie out/story.mp4, H.264 + AAC
npx remotion ffmpeg -i out/story.mp4 2>&1 | grep -E "Duration|Stream"
Confirmez : durée = somme des durées des scènes, une piste vidéo et une piste audio, résolution 1080×1350.
Spécifications visuelles (déjà implémentées dans le modèle, généralement pas besoin de modifier)
- 1080×1350 (4:5 vertical), 30fps ; fond beige
#F7F1E3, couleur thème dansmeta.theme. - Chronologie par scène : image 0 complètement vide ; à partir de l'image 1, image noir & blanc, narration et texte commencent en même temps ; le noir & blanc se termine à l'image 30 ; la couleur commence à l'image 31 pour recouvrir ; dernière image : couleur, chinois, anglais et narration se terminent exactement en même temps, sans temps d'arrêt ni fondu de sortie.
- Machine à écrire : normalisée par la durée totale de la narration, utilise le découpage de chaîne pour dévoiler mot par mot ; le texte complet invisible réserve l'espace de mise en page final, donc les sauts de ligne ne bougent pas.
- Titre avec animation de soulignement jaune qui grandit ; carte d'image avec numéro de scène rond vert foncé en haut à gauche ; barre jaune verticale à gauche des sous-titres.
Pièges courants
- Erreur rspack "different Team IDs" lors du rendu : utilisation du node original de ChatGPT, voir la section Environnement ci-dessus.
- WordBoundary vide : edge-tts 7.x nécessite de passer
boundary="WordBoundary"(le script le gère déjà, ne modifiez pas). - Image 404 entraînant un échec du rendu : tous les
scene.imagedoivent exister danspublic/avant le rendu. - Horodatage des signes de ponctuation chinois : les signes de ponctuation ne sont pas dans WordBoundary, le script les fait apparaître à la fin du mot précédent, c'est normal.
- Réutilisation du navigateur : le modèle détecte automatiquement le chemin de Google Chrome ou Chromium courant sur macOS/Linux via
remotion.config.ts, priorisant la réutilisation du navigateur système pour éviter de télécharger ~100 Mo de Headless Chrome par projet. Si aucun n'est détecté, Remotion utilise le processus de navigateur par défaut.