Que fait Khmer Money Explainer ?
Chaque vidéo suit deux personnes ordinaires confrontées à la même décision financière, effectue les calculs à voix haute et permet au spectateur de décider par lui-même. Les spectateurs restent pour les chiffres et font confiance à la chaîne car les chiffres sont honnêtes.
L'exemple de travail est la vidéo tontine vs banque dans templates/project/ (src/story/).
Règles qui protègent la chaîne
- Travail original uniquement. La recherche de style peut regarder d'autres chaînes, mais ne jamais copier leurs scripts, personnages, miniature, logos ou plans, et ne jamais les nommer dans une vidéo ou une description. Notre distribution, nos histoires et notre identité visuelle (y compris le guide portant un krama) nous sont propres.
- Argent honnête. Afficher les hypothèses à l'écran. Présenter les deux côtés, y compris les risques de l'option qui semble la meilleure. Donner des questions à poser, pas une recommandation personnelle. Chaque description se termine par une mention "pas un conseil financier" et précise que les personnages sont fictifs.
- Les vraies personnes restent en dehors. Les accusations de fraude contre des personnes ou des entreprises nommées ne font pas partie du format. Décrire les schémas issus de cas rapportés, liés dans la description.
- Dépenses : la voix coûte des crédits KiriTTS : le pilote de 1 100 caractères en a utilisé 433, donc une vidéo de 9 minutes représente environ 3 000 à 3 500 caractères. Vérifier
get_usageavant de doubler, informer l'utilisateur de l'estimation et obtenir d'abord l'approbation du script.
Pipeline
1. Sujet
Si l'utilisateur ne donne pas de sujet, en suggérer 3 avec une ligne chacun. Un bon sujet est une fourche que tout le monde au Cambodge reconnaît, a des chiffres qui peuvent être sourcés, et a un twist où la réponse évidente est fausse ou incomplète. Chercher ce qui est actuel avant de suggérer.
Se décider au début, et ne demander que ce qui n'est pas déjà connu : le sujet, la voix (par défaut Maly ; le compte peut avoir des voix clonées, voir list_voices), et le nom de la chaîne (CHANNEL dans story.tsx ; vide cache le badge).
2. Recherche et calculs
- Utiliser des sources primaires cambodgiennes lorsqu'elles existent : Banque Nationale du Cambodge, Institut National de la Statistique, grilles tarifaires des banques, notes fiscales des cabinets d'avocats, presse réputée. Noter les dates de publication : les taux et les règles fiscales changent.
- Réécrire
scripts/calc.pypour le sujet. Chaque chiffre à l'écran et dans la narration en provient et est écrit danssrc/story/numbers.json. Ajouter des assertions de cohérence. Exécuter plusieurs scénarios, dont un où le "gagnant" perd. - Séparer ce qui est sourcé de ce qui est supposé, et étiqueter les valeurs supposées à l'écran avec
<Note>. Si un fait ne peut pas être sourcé, soit le présenter comme une hypothèse claire, soit l'abandonner, et en informer l'utilisateur.
3. Script
Environ 7 000 à 9 000 caractères khmers pour 8 à 10 minutes ; la voix du pilote tournait à environ 15 caractères par seconde. Un battement correspond à une ou deux phrases d'environ 70 caractères, donc une vidéo de 9 minutes compte environ 100 à 120 battements. Lire references/script-formula.md pour la structure et les règles d'écriture en khmer.
L'écrire dans src/story/script.json (les scènes contiennent des battements ; format ci-dessous) et montrer à l'utilisateur le script khmer complet avec les sources et les hypothèses. Attendre l'approbation avant de doubler. L'utilisateur est l'autorité en matière de formulation et de termes khmers.
4. Configurer le projet
Copier templates/project/ dans un nouveau dossier, exécuter npm install, puis remplacer src/story/script.json, src/story/story.tsx et scripts/calc.py. Laisser src/engine/ tranquille sauf si on ajoute quelque chose de réutilisable. Utiliser un chemin court (voir les Astuces).
5. Test visuel avant de dépenser des crédits
python scripts/calc.py
python scripts/build_timeline.py --placeholder
python scripts/check_numbers.py
npx tsc --noEmit
node scripts/stills.mjs out/look/x_ 100,400,900 0.5
Regarder les images vous-même, par rapport à la checklist dans references/visual-style.md. Une fois doublé, vérifier chaque ligne deux fois, près de son début et près de sa fin : les images prises uniquement à la fin cachent les cartes qui restent vides pendant que la voix monte en puissance jusqu'à un nombre. Écrire les scènes une par une et vérifier chacune, car les problèmes de mise en page sont bien moins chers à corriger maintenant.
6. Voix
python scripts/tts_todo.py
Ceci liste uniquement les battements qui sont nouveaux ou modifiés. Pour chacun, appeler KiriTTS text_to_speech avec le champ tts du battement (ou text) et une voix cohérente, sans définir les paramètres de livraison. Télécharger l'URL vers voice/<id>.mp3 (les liens expirent dans environ un jour) et l'enregistrer avec python scripts/tts_todo.py --done <id> <speech_id>. Un clip par battement signifie qu'un mot erroné coûte une phrase à corriger.
Les repères mot par mot sont optionnels : enregistrer la sortie de get_word_timestamps sous voice/<id>.words.json, puis utiliser at('b03', 'word'). Les fractions comme at('b03', .5) sont généralement suffisantes. Écouter les nombres, les noms et les mots étrangers ; si KiriTTS en lit mal un, ajouter une orthographe tts pour ce battement.
7. Timeline, son, rendu
python scripts/build_timeline.py
python scripts/make_audio.py
npx remotion render src/index.ts Main out/video.mp4 --codec h264 --crf 18 --muted
ffmpeg -y -i out/video.mp4 -i out/mix.wav -map 0:v:0 -map 1:a:0 -c:v copy -c:a aac -b:a 192k -shortest out/final.mp4
python scripts/qa.py out/final.mp4 out/qa
npx remotion still src/index.ts Thumbnail out/thumb.png
Les vidéos longues prennent du temps, alors lancer le rendu en arrière-plan. Rendre un court pilote des premières scènes pour la revue de l'utilisateur avant la vidéo complète lorsque le rendu visuel ou la voix est nouveau.
8. QA
Lire out/qa/report.md, et regarder chaque planche contact. Enquêter sur les images noires ou figées et sur la sonie loin de -15 LUFS. Vérifier que chaque chiffre à l'écran correspond à numbers.json et qu'aucun texte khmer n'est coupé ou chevauché.
9. Livrer
Envoyer le mp4 et la vignette avec SendUserFile. Écrire également out/description.md en khmer, contenant : un accroche, un résumé travaillé avec les hypothèses, les risques, les questions à se poser, les mentions de personnages fictifs et de non-conseil financier, une invitation à commenter, des chapitres avec des horodatages réels provenant de timeline.json, des liens vers les sources, et des hashtags. Ne jamais télécharger ou publier sans que l'utilisateur le demande.
Format de script.json
{ "gap": 0.3, "scene_gap": 0.7, "tail": 1.5,
"scenes": [{ "id": "Hook", "chapter": 0, "music": "light", "beats": [
{ "id": "h1", "text": "Phrase en khmer", "tts": "orthographe parlée optionnelle", "sfx": [{"at": 0.75, "type": "coin"}] }
]}]}
- L'
idd'une scène doit correspondre à un composant dansSCENESdestory.tsx. - Le
chapterindexeCHAPTERS; 0 est l'accroche et cache la barre. music:light,tenseouresolve.- Types de
sfx: pop whoosh coin cash ding thud tick paper sad tada alarm.atest une fraction du battement. Les utiliser pour les révélations, pas sur chaque ligne.
Écrire des scènes
Lire src/story/story.tsx : c'est la référence pour la façon dont une scène est écrite. En bref, const {f, at} = useScene() donne l'image et les temps de battement, et chaque élément entre via <Show at={...} out={...} x y>. Rien n'est chronométré en secondes, donc un nouveau doublage ne casse jamais une scène.
Éléments disponibles :
engine/Figure: visages, poses, marche et accessoires à la main. Définir chaque personnage une fois en haut de l'histoire.engine/Props: Title, Label, Chip, Tag, Bubble, ThoughtCloud, Jar, Coin, Bill, MoneyBag, Calendar, Bank, House, Stall, Notebook, Phone, Rock, Umbrella, StormCloud, CheckMark, VsBadge, Arrow, FlyingMoney, Note, Moto, NameChip.engine/Charts: Card, Counter, Bars, LineChart, MonthGrid, etmoney().engine/Stage:mood,tint,zoom,focus.
Si un sujet nécessite un nouvel accessoire, le dessiner dans le même style encré dans le fichier de l'histoire, et le déplacer vers engine/Props.tsx s'il est réutilisable.
Astuces (chacune s'est produite)
- Limite de chemin Windows. Remotion échoue lorsque le chemin du projet est si long que les fichiers dans
node_modulesdépassent 260 caractères :Failed to launch the browser process/spawn ... chrome-headless-shellsur les images, et erreursgetExecutableDirsur les rendus complets. Pointer vers un navigateur différent ne corrige pas la seconde erreur. Garder le projet sur un chemin court commeD:/videos/<nom>(moins d'environ 100 caractères), et exécuternpm installlà-bas. - Espace temporaire. Chaque bundle est copié dans le dossier temporaire et n'est pas supprimé. Si C: est plein, définir
RENDER_TMPpourstills.mjs, etTEMP/TMPpour la CLI, sur un disque plus grand. <Show>par défaut à x=0, y=0, ce qui place un titre centré à moitié hors écran. Toujours passerx={960}pour les éléments centrés.- Les chiffres de Koulen se lisent mal ("12" ressemble à "I2").
Titledéfinit déjà les chiffres et les symboles dans la police du corps ; ne pas le contourner. - Étiquettes sur les visages. La tête d'un personnage debout atteint environ y=470, et les mains levées vont plus haut. Placer les étiquettes à y≈300-350 au-dessus d'un personnage.
- Remotion n'écrit pas d'audio utilisable avec
--muted, donc toujours multiplexermix.wavensuite comme indiqué. - Les heredocs Bash avec beaucoup de TSX peuvent échouer à l'analyse dans certains shells sur Windows. Écrire les fichiers source avec l'outil de fichier.