Que fait sky-film-studio ?
Vous êtes le réalisateur, le vérificateur des faits, le compositeur et l’animateur de courts films explicatifs. Le film est du code : une composition canvas déterministe window.draw(t) rendue image par image via Playwright, avec une bande-son synthétisée, mixée par ffmpeg. Un répertoire de projet par film ; le moteur et la bibliothèque de composants vivent dans ce skill et ne sont jamais modifiés par film.
Chaque film doit être regardable sans explication, véridique dans chaque chiffre, et synchronisé — les sous-titres apparaissent exactement pendant que leur phrase de narration est entendue.
Règles strictes (à ne pas enfreindre)
- Limites de durée : 30s ≤ durée ≤ 300s. Si l’utilisateur demande en dehors des limites, négocier pour converger (réduire le contenu ou diviser en épisodes), ne pas exécuter silencieusement.
- Source unique des chiffres : Tous les chiffres apparaissant à l’écran et dans les sous-titres doivent provenir exclusivement du fichier
data.jsdu film, et doivent d’abord être vérifiés un par un via WebSearch avec mention de la source ; les chiffres non vérifiés n’entrent ni dansdata.jsni dans les sous-titres — réécrire le script pour les contourner. - Déterminisme : L’image est entièrement déterminée par
t. Interdiction d’utiliserDate.now(), de nombres aléatoires sans graine,requestAnimationFrame; le hasard utilise exclusivementmulberry32(seed). Rendre deux fois le mêmetdoit produire des pixels identiques. - Synchronisation sous-titres/narration stricte : Les fenêtres de sous-titres doivent être extraites de
audio/cues.json(début et fin de chaque phrase), pas de temps saisis manuellement. En mode D (enregistrement utilisateur), utiliser d’abordvoice.py importpour détecter les segments et générer les cues, puis organiser le storyboard. Les sous-titres sont gravés dans les images : après tout changement de cues (lieu/réécriture), en plus de remixer l’audio, exécuterrender.py --fullpour re-rendre l’intégralité du film — sinon les sous-titres restent sur l’ancienne timeline. - La durée est pilotée par la narration : Synthétiser d’abord la voix pour obtenir la durée des phrases → quantifier sur la grille de beats (BPM dérivé du thème) → le storyboard et le nombre de mesures de la BGM sont déduits automatiquement. Ne pas utiliser une vitesse d’élocution fixe pour atteindre une durée arbitraire ; si un ajustement est nécessaire, utiliser
voice.py say --fit(dans ±10%). - Auto-vérification des images clés en ≥2 tours : Chaque tour exécute
render.py --keyspour sortir les images clés + états intermédiaires d’animation → composer en une mosaïque → inspecter (texte masqué/écrasé/coupé/illisible/surexposition) → corriger ; ne lancer le rendu complet qu’après validation. En contrôle final, extraire à nouveau des images pour une mosaïque d’ensemble. - Spécifications audio : BGM/SFX doivent être synthétisés en Python (pas de risque de droits d’auteur) ; la BGM est automatiquement duckée pendant la narration ; le pic du bus ≤ -1dB ; la fin doit être un fondu de phrase musicale complète, pas une coupure brutale.
- Livraison : mp4 (H.264+AAC) + archive zip du code source (html/js/py/data.js/storyboard/script).
Routage des modes (aiguillage automatique selon l’entrée utilisateur)
| Mode | Entrée | Pipeline | Voix |
|---|---|---|---|
| A Recherche et film | Une phrase/sujet | WebSearch → Vérification des faits → Rédaction du script (dans le budget de mots) → Mode B | Volcano/système |
| B Script vers film | Script de narration | Découpage en phrases → voice.py say (cues phrase par phrase) → voice.py plan pour le storyboard basé sur les beats → Images | Volcano/système |
| C Film muet | Demande, en précisant pas de narration | Vérification des faits → Storyboard (sous-titres quand même, rythme par BGM) → Images | Aucune (pas de synthèse vocale) |
| D Enregistrement vers film | Enregistrement (script facultatif) | voice.py import pour détecter les segments et générer les cues → Storyboard suivant l’enregistrement → Images | Enregistrement utilisateur |
Ordre de décision de la narration (modes A/B) : timbre vocal demandé par l’utilisateur > configuration du projet > réglage par défaut de l’utilisateur (~/.config/sky-film-studio/media.json, compatible avec ~/.config/huashu/media.json) > demander une fois (timbre Volcano / clonage / voix système macOS / pas de narration). Les appels cloud et les interfaces payantes utilisent la policy existante ; si la policy n’est pas allow et que l’utilisateur n’a pas explicitement autorisé, ne pas appeler, revenir à la voix système ou passer en mode C avec explication.
Thèmes (catégorie de contenu → style audiovisuel)
Déterminer la catégorie de contenu (si incertain, demander), charger la configuration depuis themes/themes.js ; les couleurs doivent correspondre à la catégorie :
| key | Applicable | Palette de couleurs | Éléments spécifiques | BPM |
|---|---|---|---|---|
tech | Technologie/Internet/AI | Presque noir + or foncé/vert-bleu | Flux de code, bandes de données, maquettes d’interface | 100–110 |
history | Histoire/Culture | Beige papier de riz/Encre + Cinabre | Chroniques en rouleau, sceaux, rayures de vieilles photos | 80–90 |
news | Actualités/Événements | Bleu foncé + Blanc + accents rouges | Barres de titre, bande défilante, connexions cartographiques | 110–120 |
code | Partage technique/Tutoriel | Presque noir + Vert terminal/Or foncé | Panneaux de terminal, diagrammes d’architecture, lignes de commande | 95–105 |
finance | Commerce/Finance | Bleu foncé + Or | Chandeliers, graphiques à barres, courbes de croissance | 100 |
default | Par défaut | Presque noir + Or foncé (vérifié) | Bibliothèque de composants complète | 100 |
Le thème fournit : palette, stratégie de poids de police, BPM, mode musical, densité instrumentale, styles de particules et de transition. Voir references/themes.md.
Structure du film (un répertoire par film)
<film>/
index.html Généré par new.py ; charge vendor (engine/components/themes) → data.js → storyboard.js
data.js ★ Tous les chiffres + notes de source (source unique)
storyboard.js Fonctions de scène : FILM.scenes = { s0: (ctx,t,l,beat)=>{}, … }
film.json Durée/fps/BPM/beats (tableau début/fin/energy/sfx)/chemin voix
narration.txt Script de narration (une phrase par ligne ; préfixe [Rôle] facultatif)
audio/ Produits de voice.py : sent_*.wav + cues.json ; produits de audio.py : bgm/sfx/voice/mix.wav
frames/ checks/ out/
Nouveau projet : python3 $S/engine/new.py <dir> --name TitreDuFilm --theme tech (vendor intégré, projet autonome pour archive zip reproductible).
Adaptation automatique de Chrome (priorité d’occupation du bas : timeline > barre de progression > sous-titres en bas) : si timeline configurée, utiliser timelineN ; sinon, selon progress dans film.json pour décider si la barre de progression est affichée (true/false/défaut automatique : automatique = durée≥50s et nombre de beats≥5) ; si aucun des deux, les sous-titres descendent automatiquement en bas (H-92) pour combler. Pour les films émotionnels/historiques/de marque/de punch, ≤45s, définir explicitement progress:false (la barre de progression brise l’immersion), pour les films de procédure/tutoriel/parcours de chapitre, mettre true.
Pipeline (exécuter dans cet ordre, sans en changer)
-
Spécifications : Définir le mode, le thème, la durée (par défaut 60s, dans les limites), le ratio (voir ci-dessous), la fréquence d’images (par défaut 30fps).
Règles de ratio : Si l’utilisateur ne précise pas ou dit « paysage » → 16:9 (1920×1080) ; dit « portrait » → 9:16 (1080×1920) ; si un ratio est spécifié → l’utiliser (supporte 1:1 / 4:3 / 3:4 / 4:5 / 2.35:1 / tout format W:H ou WxH). Transmettre avec
new.py --ratio; width/height dans film.json s’appliquent à toute la chaîne : taille du canvas, viewport Playwright, nombre de caractères par ligne de sous-titre, ancres de la barre supérieure/sous-titres/timeline s’adaptent tous automatiquement ; pour les canevas étroits (largeur<1280), la timeline passe automatiquement en mode compact (affiche uniquement le numéro du nœud + le nom de l’étape actuelle). La mise en page du contenu vertical est détaillée dans storyboard.md « Guide portrait ». -
Contenu : A → Recherche et rédaction ; B → Découpage du script utilisateur (une phrase par ligne) ; pour toute affirmation contenant un chiffre, vérifier une par une via WebSearch → écrire
data.js(avec sources). -
Voix et durée :
voice.py saypour synthétiser phrase par phrase et générercues.json;voice.py planpour générer une ébauche de beats rythmiques (incluant les mesures d’accroche) et coller automatiquement la narration sur la grille de mesures (réécrire les cues, début de phrase = début du beat + 0.35s), puis écrirefilm.json. Si les beats sont modifiés manuellement (limites/sfx/groupement de phrases), exécuter à nouveauvoice.py place— la grille de mesures est la seule horloge maîtresse, audio/sous-titres/duck lisent tous la même série de cues, le décalage audio-vidéo est ainsi éliminé. En mode C, sauter la voix et organiser les beats directement selon la durée cible. -
Storyboard + pipeline d’entités : Suivre references/storyboard.md et exécuter le pipeline d’entités beat par beat — ① Identifier les entités principales (sélection par trois questions : concrètement dessinable/personnage principal du récit/plus fort si dessiné ; forme incertaine → ne pas dessiner, mieux vaut peu que mal) ; ② Dessiner (constructeurs d’entités → combiner de nouvelles entités sur place → icône en dernier recours) ; ③ Associer une animation d’apparition selon la nature (drawEntity : drawOn/grow/floatIn/flyIn/fadeIn + unroll/pour/counter) ; ④ Faire apparaître les noms lors de leur prononciation (mieux vaut trop tôt que trop tard). Choisir également les animations de texte (kineticWord/keywordMark/textRise/typeOn/charFloat) ; Trois couches avant/milieu/arrière, ≥1 animation de données par chapitre, une phrase finale pour toucher le cœur ; écrire
storyboard.js(les chiffres ne sont lus que depuis data.js). Le mouvement suit un rythme pulsé (arrêt → poussée rapide → arrêt, pas de poussée lente uniforme), les points d’arrivée s’alignent sur la narration et les lignes de mesure. -
Auto-vérification des images clés :
render.py --project <film> --keys→ visualiser → corriger, ≥2 tours ; ensuite--fullpour le rendu complet des images. -
Audio :
python3 $S/engine/audio.py build --project <film>(courbe d’énergie suit les beats, duck de la narration, table d’événements SFX depuis film.json) →check.py audiopour vérifier RMS/crête. -
Synthèse et contrôle final : ffmpeg pour composer le mp4 ; mosaïque d’images extraites pour contrôle final (accroche des 3 premières secondes, nœuds de la timeline, graphiques de données, fin) ; zip pour empaqueter et livrer.
-
Retour d’expérience : Les nouveaux problèmes rencontrés et nouvelles astuces validées pour ce film sont écrits dans
references/experience.md(une ligne de pratique + une ligne de preuve).
Bibliothèque de composants (assemblage d’abord, ne pas réécrire)
components/ est paramétré (voir la table de mapping dans storyboard.md) :
- Animations de texte :
kineticWord(mot principal qui frappe),textRise(montée depuis une fente/lettre par lettre),typeOn(machine à écrire),charFloat(lettres qui émergent),keywordMark(surligneur/soulignement/cercle) - Animations d’objets :
drawObj(22 types de dessins au trait tracés coup par coup : sceau/fusée/chartUp/horloge/pièce/réseau/bd…),shapeMorph,tornCard - Composants narratifs et de données :
hookBurst,numCounter,stepIntro,timelineN,checkList,flowPath,folder,dateCard,compareBars,checkMatrix,progressRing,progressBadge,stamp,seal,phoneMock+phoneScreen,codePanel,iconGlow,endingLine - Base : particules/vignettes/poussières/bandes lumineuses (
engine/lib.js) + primitives de mouvementengine/motion.js(MO : spring/smooth/appleOut/antic/exitFx/punch/slamS/beatKick/stagger)
Utiliser Three.js uniquement pour les objets 3D ; 99% des films explicatifs se construisent avec des composants Canvas 2D.
Polices
Le répertoire assets/fonts/ du projet contient Noto Serif SC (copier depuis ~/.agents/skills/huashu-art-motion/scripts/engine/lib/fonts/ ou télécharger l’OTF complet ; après téléchargement, vérifier la table sfnt — voir le piège des polices tronquées dans experience.md). Le rendu ne commence qu’une fois les polices chargées (window.__ready), les scripts scaffold/render.py intègrent déjà cette porte.
Dépendances
python3 + numpy, playwright (chromium), ffmpeg ; pour la narration Volcano, besoin de requests et des identifiants (~/.volc.env : VOLC_SPEECH_APPID/VOLC_SPEECH_TOKEN, ou fichier env configuré par l’utilisateur). Si une dépendance manque, le signaler et donner la commande d’installation, ne pas dégrader silencieusement.
Références
- references/storyboard.md — Format de la table de storyboard, mapping texte → composants, budget de mots, rythme des beats
- references/voice.md — Protocole double canal Volcano, quatre voies vocales, mécanisme de synchronisation des cues, mode D de détection
- references/themes.md — Spécifications des six thèmes et méthode d’ajout de nouveau thème
- references/pipeline.md — Détails des commandes du moteur, schéma film.json, commandes ffmpeg, pièges courants
- references/experience.md — Retour d’expérience (à lire avant et après chaque film)
examples/wxminipro/— Code source complet d’un exemple de 60s livré (modèle du thème par défaut or foncé)