Communitygithub.com

smwbev/framewright

Vidéos courtes entièrement à partir de code : un seul fichier HTML, chaque image une fonction pure de (numéro d'image, seed, largeur). Claude/Codex/Gemini/Cursor.

Qu'est-ce que framewright ?

Framewright est une compétence d'agent IA qui permet de créer des vidéos courtes de qualité professionnelle en écrivant uniquement du code. Le principe est simple : un seul fichier HTML contient un canvas, une liste de scènes appelées « plaques » (plates), et une fonction de rendu qui génère chaque image à la demande à partir du numéro d'image, d'une graine (seed) et de la largeur de sortie. Aucune image, vidéo, police ou bibliothèque externe n'est nécessaire : tout est calculé à la volée. Les images sont rendues via un navigateur headless (Chrome) et assemblées par ffmpeg, avec une synthèse sonore finale qui s'aligne sur la durée des scènes. Ce workflow est conçu pour fonctionner avec Claude Code, Codex, Gemini et Cursor, et repose sur des contraintes strictes de déterministe et d'encapsulation : chaque image ne dépend que de ses paramètres, pas de l'horloge ou de Math.random. L'outil guide l'utilisateur depuis le brief et le storyboard jusqu'au rendu final et aux variations, avec des vérifications visuelles à chaque étape. Il est idéal pour les développeurs et motion designers qui veulent un contrôle total sur le rendu, reproductible et versionnable.

Compatible avec✓Claude Code✓Codex CLI✓Cursor✓Gemini CLI
npx skills add smwbev/framewright

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Que fait framewright ?

Vous allez réaliser une courte vidéo comme un graveur réalise une estampe : un seul fichier HTML avec un canvas, une liste de scènes appelées plaques (plates), et une fonction d'image (frame) qui dessine n'importe quelle image à la demande à partir de (numéro d'image, seed, largeur). Pas de séquences vidéo, pas de fichiers image, rien depuis un CDN. Les images sont rendues dans Chrome headless et assemblées par ffmpeg. Le son est synthétisé en dernier, sur les longueurs de scène verrouillées.

Parlez à l'utilisateur dans sa langue. Respectez les règles ci-dessous même lorsque l'utilisateur est pressé : chaque raccourci ici coûte plus qu'il ne rapporte.

SKILL_DIR ci-dessous désigne le dossier qui contient ce fichier (dans Claude Code c'est ${CLAUDE_SKILL_DIR} ; ailleurs c'est .agents/skills/framewright). Après l'étape 3, les scripts résident aussi dans le dossier scripts/ du projet.

Non-négociables

  1. Une image dépend uniquement du numéro d'image, de la seed et de la largeur de sortie. Pas de Math.random, pas de temps réel, pas d'animation CSS, pas de requestAnimationFrame comme source temporelle. scripts/check.mjs le prouve avant chaque rendu complet.
  2. Pas d'image, vidéo, police ou fichier de bibliothèque, pas de base64, pas de CDN. Des polygones tracés depuis une photo par un script sont des données et sont acceptables. Les polices système suffisent.
  3. Vous vérifiez en regardant les images rendues, jamais en lisant du code et en imaginant. Toute correction est confirmée avec une image.
  4. Une scène à la fois. Écrivez une plaque, tirez trois images, regardez, corrigez, puis la plaque suivante.
  5. Les longueurs des scènes sont des multiples du temps (beat) du premier jet. Le son vient en dernier.
  6. Rendu complet seulement après qu'une planche contact (contact sheet) de toute la vidéo semble correcte.
  7. Ne commettez jamais frames/, shots/, *.mp4, *.wav ou les photos de l'utilisateur.
  8. Demandez avant d'installer des paquets système. Ne publiez jamais l'image d'une personne réelle sans que l'utilisateur confirme avoir le droit de l'utiliser.

Aperçu du workflow

ÉtapeCe qui se passePoint de contrôle avec l'utilisateur
0vérification de l'environnementseulement si quelque chose doit être installé
1briefquestionnaire, un bloc
2conceptstrois options, choisir une
3storyboard + échafaudageun « go »
4scènes, une par uneplanche contact toutes les 2–3 scènes
5ressources (photos, logos)aperçu du portrait tracé
6planche complète, rendu, constructionaperçu MP4
7sonMP4 reconstruit
8livraison et variationsfinal

Temps typique : brief et concepts 10 minutes, échafaudage 10, chaque scène 10–20, rendu 2–4 minutes par minute de vidéo 1080p, son 15.

Étape 0. Environnement

bash SKILL_DIR/scripts/doctor.sh            # rapport ; ajoutez --json pour un résumé lisible par machine
bash SKILL_DIR/scripts/doctor.sh --install  # installe ce qui manque, demande avant chaque étape

Requis : Node 20+, npm, ffmpeg avec libx264, Puppeteer avec Chrome dans le projet. Optionnel : Python 3 avec numpy, scipy, Pillow, seulement lorsqu'une photo sera tracée. Si le docteur signale des outils manquants, dites à l'utilisateur ce qui sera installé et où, obtenez un oui, puis exécutez --install (ajoutez --yes lorsque l'utilisateur a déjà accepté). Ne commencez pas l'étape 3 avec un docteur défaillant.

Étape 1. Le brief

Exécutez le questionnaire depuis references/questionnaire.md. Utilisez l'outil de questions structurées de l'agent quand il existe (Claude Code : AskUserQuestion, jusqu'à quatre questions par appel, devux à quatre options chacune, mettez l'option recommandée en premier et marquez-la). Sans un tel outil, affichez les questions sous forme de liste numérotée avec des options lettrées et une valeur par défaut par question, et acceptez des réponses concises comme 1b 2a 3c. Demandez toujours, dans cet ordre :

  1. Message : que doit comprendre ou ressentir le spectateur, en une phrase. Noms, dates, liens, phrases exactes qui doivent apparaître à l'écran.
  2. Où cela est diffusé et le format : 16:9, 9:16, 1:1, 4:5.
  3. Durée : 10–15, 20–25, 30–40, 45–60 secondes.
  4. Ton : ludique, impassible, chaleureux, épique, technique, sombre.
  5. Style : laissez proposer (par défaut) ou une famille depuis references/styles.md.
  6. Ressources : photos, logos, captures d'écran. Les fichiers doivent être placés dans le dossier du projet ; une image collée dans le chat ne peut pas être sauvegardée par vous. Demandez les droits pour les personnes réelles.
  7. Son : synthétisé, aucun, ou espace pour la piste de l'utilisateur (demandez son BPM).
  8. Livrables et qualité : brouillon ou final, coupes supplémentaires (vertical, GIF, image d'aperçu, variations de seed), une couverture comme première image du MP4 (les flux la montrent comme aperçu).

Si l'utilisateur dit « tu décides », prenez les valeurs par défaut, dites lesquelles vous avez prises, et passez à la suite.

Étape 2. Concepts

Proposez exactement trois concepts avant tout code. Construisez-les sous trois angles : littéral (montrez le sujet), métaphore (un système visuel qui représente la situation : une mire TV pour l'attente, un plan pour un projet, un terminal pour un processus), et parodie de genre (bulletin d'information, mode attente d'arcade, carte de sécurité, bulletin météo, télétexte). Pour chaque concept donnez : un nom, un pitch d'une phrase, le système visuel et la palette, trois à cinq scènes clés dans l'ordre, la fin, une esquisse sonore, pourquoi cela correspond, et son principal risque. Présentez un tableau compact, recommandez-en un, et demandez à l'utilisateur de choisir. La méthode et des exemples travaillés se trouvent dans references/questionnaire.md. Un concept dont le pitch est un voyage sans coupure (un trait qui ne se lève jamais, un vol d'un détail vers un paysage) est construit comme un monde continu (references/world.md) ; dites-le dans sa ligne, car cela change la façon dont les scènes sont construites et modifiées. Un concept qui est une vue dessinée, peinte et animée (un dessin au crayon qui devient une peinture à l'huile vivante, styles 13–16) est construit comme un film peinture (references/painting.md) ; dites-le aussi dans sa ligne : ses plaques sont des chapitres de temps sur une seule peinture, et la scène est le travail.

Étape 3. Storyboard et échafaudage

Remplissez storyboard.md (modèle dans assets/storyboard.md) : une ligne par plaque, longueurs en mesures, la grille de temps (30 fps, 120 BPM : temps 15 images, mesure 60), la seconde de l'événement principal, le total. Le total doit correspondre à la durée convenue ; lorsqu'une scène est ajoutée plus tard, une autre scène cède une mesure. Affichez le tableau et demandez un seul go.

Ensuite, échafaudez :

bash SKILL_DIR/scripts/init.sh              # index.html, scripts/, audio.mjs, storyboard.md, package.json
bash SKILL_DIR/scripts/init.sh . --world    # idem, mais index.html est le squelette d'un monde unique (pas de coupures)
bash SKILL_DIR/scripts/init.sh . --painting # le squelette peinture ; audio.mjs et nature.mjs créent un son de nature
npm install                                 # puppeteer (Chrome vient du cache ou est téléchargé une fois)
node scripts/look.mjs shot 0,30,60 1200 7

Ouvrez les PNG avec votre outil de visualisation d'images et regardez-les. La plaque de démonstration du squelette doit être rendue avant que vous n'y touchiez. Remplacez ensuite la plaque de démonstration par votre première scène. Dans un film peinture, l'image 0 est du papier blanc : tirez 30,82,200 (le dessin, la couleur qui arrive, la peinture vivante) à la place, et remplacez le bloc de scène de la démo tandis que le kit de peinture reste tel quel.

Étape 4. Scènes

Lisez references/guide.md une fois avant la première scène. L'essentiel :

  • plate('nom', {len: 2*BAR}, (S, R) => { ... }). S.t est la progression 0..1, S.i l'image locale, S.f l'image globale, S.g le contexte 2D en coordonnées logiques (petit côté 1080). R est un générateur stable pour toute la plaque ; S.b ré-initialise la seed toutes les trois images et donne une ligne de vie ; S.nz change à chaque image pour le bruit. Les seeds dérivent du nom de la plaque.
  • Toute la géométrie en unités logiques, centrée via CX, CY. Gardez le contenu important à l'intérieur des 92 % centraux de l'image ; en 9:16, évitez aussi les 15 % du haut et les 20 % du bas, où se trouvent les boutons et les sous-titres de la plateforme.
  • Le temps à l'intérieur d'une plaque en temps : Math.floor(S.i/BEAT), span(S.i, a, b), ease.out(...). Ne codez jamais en dur des numéros d'image globaux à l'intérieur d'une scène. Quelque chose qui continue à travers les coupures prend le temps d'une autre plaque par son nom, at('plaque', temps) ; un moment que le son doit atteindre va dans CUES et est lu avec cue('nom').
  • Les aides vivent au-dessus du bloc de plaques, jamais entre les plaques.
  • Les transitions sont dessinées par le moteur aux bords des plaques (indicateurs cutIn/cutOut) ; les scènes ne les connaissent pas.
  • Un film monde (--world) n'a pas de coupures. Les plaques sont des constructeurs, build(W, {pen, b, R}), qui ajoutent à une seule chronologie : b(x) est le temps x de la plaque, le stylo continue la ligne là où la plaque précédente l'a laissée, camKey déplace une caméra, title ajoute du texte. Lisez references/world.md avant le premier constructeur.
  • Un film peinture (--painting) dessine une seule peinture fixe en trois médiums. Ses plaques appellent toutes drawPainting(S) ; la vue vit dans l'objet SCENE et ses couches entre /* ===== scene ===== */ et /* ===== end scene ===== */, et le kit de peinture au-dessus reste tel quel. Lisez references/painting.md avant la première couche. Examinez d'abord le dessin seul, puis la révélation, puis la vie (references/painting.md, section 13).

Par scène : écrivez-la, tirez la première image, une au milieu, une cinq images avant la fin, regardez, corrigez, regardez à nouveau. Après toutes les deux ou trois scènes :

node scripts/look.mjs sheet 24 480 7 shots/sheet.png
FROM=240 TO=480 node scripts/look.mjs sheet 12 480 7 shots/sheet-b.png   # une section, plus dense

Liste de vérification pour la planche, chaque élément avec vos yeux : chaque case se lit comme une image fixe en 1,5 seconde ; aucun texte n'est coupé ; les lignes et panneaux voisins ne se touchent pas ; deux cases adjacentes d'une même plaque ne se ressemblent jamais ; les coupures atterrissent là où prévu et ne mangent pas la première image d'une scène ; rien d'important ne se trouve dans les 8 % extérieurs ; la couleur n'est pas boueuse ; les lignes fines ne s'effritent pas ; l'événement principal se situe sur sa seconde prévue ; la dernière image ressemble à une fin ; jamais deux titres ne partagent l'écran au même endroit. Une scène qui échoue au test « 1,5 seconde » est reconçue, pas décorée. Une scène vide reçoit un objet plus grand ou une caméra plus proche, jamais plus de détail ; un gros plan chargé voit son décor atténué autour du sujet. Dans un film monde, tirez aussi la dernière image de chaque plaque à côté de la première image de la suivante : rien ne doit sauter.

Envoyez la planche à l'utilisateur à ces moments avec deux phrases de statut. Ne racontez pas le code.

Étape 5. Ressources

Les photos deviennent des polygones affichés, jamais des pixels :

bash scripts/portrait.sh photo.jpg --levels 0,14,0,28,0,42,0,56,0,70,0,84 --height 900
node scripts/look.mjs shot <image dans la scène portrait> 1200 7

Regardez shots/portrait_preview.png et l'image rendue. Ajustez les niveaux, le flou, le recadrage et le seuil de fond selon references/photo.md. Tant que le fichier n'est pas encore dans le dossier, construisez la scène sur le substitut synthétique fourni dans le squelette et dites-le.

Étape 6. Planche complète, rendu, construction

node scripts/look.mjs sheet 24 480 7 shots/sheet.png      # regardez, corrigez, répétez
node scripts/check.mjs                                    # déterministe et auto-contenu, doit dire OK
node scripts/render.mjs frames 7 1920 5                   # dir, seed, largeur (omise : 1920 paysage, 1080 portrait), onglets
bash scripts/build.sh out.mp4                             # frames (+ track.wav) -> mp4

La vérification rend cinq images de chaque plaque dans sept ordres (première image d'un nouvel onglet, avant, arrière, mélangé, juste après l'image précédente, après une autre largeur, après un balayage du film comme le ferait un onglet de rendu) et exige des pixels identiques. Elle scanne aussi le source à la recherche de Math.random, Date et performance.now, échoue lorsque la page demande un fichier, et affiche la grille de temps et le temps de rendu prévu. Corrigez chaque ÉCHEC avant de rendre ; make.sh exécute la vérification et s'arrête en cas d'échec. Une image qui change avec l'ordre de rendu indique un état qui survit à une image : un canvas mis en pool sans effacement, un global qu'une plaque modifie, une clé de cache sans toutes ses entrées.

Vérifiez à partir du fichier, pas des images : le nombre d'images ffprobe est égal au total de look.mjs info, la durée est égale aux images divisées par 30, et une mosaïque faite à partir du MP4 correspond à la planche :

ffmpeg -i out.mp4 -vf "select='not(mod(n\,50))',scale=480:-1,tile=6x4" -frames:v 1 shots/out_sheet.png

Envoyez le premier MP4 à l'utilisateur dès qu'il existe, même avec des espaces réservés, et dites ce qui est un espace réservé.

Étape 7. Son

scripts/export-curves.mjs écrit curves.json depuis la page : débuts de plaques, les repères (cues), et pour chaque image d'un film monde la vitesse et la position à l'écran de la tête de ligne, dans un film peinture les parts révélées, la vie, la rafale (gust) et le zoom. audio.mjs prend sa chronologie de là, donc il ne dérive jamais de l'image (une page sans RISO.curves() a besoin des débuts de look.mjs info recopiés dans T à la main). Écrivez un bloc d'événements par plaque en utilisant la carte de repères dans references/audio.md ; les frappes sur quelque chose que l'image marque prennent leur temps depuis les repères de la page, cue('nom') (CUES, ou W.cues dans un film monde), pas depuis des numéros de temps copiés d'une plaque ; dans un film monde, donnez à la ligne ou au personnage une voix qui suit les courbes (follow(), references/audio.md, section 7). Une peinture ou un paysage reçoit une ambiance nature au lieu de rythmes : vent, eau, bruissement et oiseaux depuis nature.mjs, synchronisés aux repères et à la rafale (gust) de la page par le audio.mjs que --painting copie depuis assets/audio-nature.mjs (references/audio.md, section 8, Ambiance nature). Ensuite :

node scripts/export-curves.mjs curves.json
node audio.mjs track.wav
ffmpeg -i track.wav -filter_complex "showwavespic=s=1800x300:split_channels=1" -frames:v 1 shots/wave.png
bash scripts/build.sh out.mp4

Vous ne pouvez pas écouter, donc lisez la forme d'onde : pas de silence accidentel dans les scènes actives, pas de scène collée au plafond. Chaque fois qu'une longueur de scène change, régénérez la piste.

Étape 8. Livraison

Livrez out.mp4 (1920×1080, H.264, AAC, ~0,7 Mo par seconde sur les styles complexes) et dites comment reconstruire : bash scripts/make.sh [photo.jpg] [seed] [largeur]. Proposez, n'imposez pas : une autre seed (une impression différente des mêmes plaques), une coupe verticale (AR=9:16 node scripts/render.mjs frames-v 7 1080 5, puis vérifiez une planche avec AR=9:16 ; les sous-titres inférieurs se situent à 70 % de la hauteur là, TITLE_Y, hors des boutons de la plateforme ; un …

Skills associés