Communitygithub.com

resolve-cut

Montez, rendez et vérifiez des vidéos de type « talking-head » (cours, interviews) de bout en bout dans DaVinci Resolve Studio : transcriptions mot par mot, dossier complet de chaque prise, dernière prise complète de chaque paragraphe, liste de coupes image par image, assemblage par script, rendu avec préréglages, QC (loudness, trames, mots répétés) et livraison.

Qu'est-ce que resolve-cut ?

Ce skill permet d'assembler, de rendre et de contrôler des vidéos dans DaVinci Resolve Studio via des scripts sauvegardés paramétrés. Il ne réécrit pas l'assemblage à chaque session : il appelle les scripts, lit leurs retours et vérifie le résultat avec des nombres et des trames. Le jugement reste humain : la personne décide ce qui reste, vous exécutez et mesurez. Le flux de travail commence par la transcription mot par mot de chaque clip, puis la création d'un dossier compact listant toutes les prises avec leurs répétitions, suivi d'une liste de coupes choisies. L'assemblage dans Resolve se fait en étapes séparées (import, montage, zoom et isolation vocale). Le rendu est lancé avec un préréglage, et une vérification (QC) vérifie la loudness, les trames et les mots répétés dans le mix final. En cas de défauts, une nouvelle version est générée (au maximum 3 rounds). Le skill prend en charge DaVinci Resolve Studio (pas la version gratuite), nécessite ffmpeg, Python avec numpy et PIL, et éventuellement une clé API ElevenLabs. Les scripts sont divisés en deux catégories : ceux qui s'exécutent dans Resolve via `run.py` et ceux qui s'exécutent en Python pur avec ffmpeg. Le skill inclut également des astuces et des pièges vérifiés (mesurés sur macOS avec Resolve Studio 21.1.1 et 21.1.2) pour éviter des erreurs courantes comme les timeouts MCP, la gestion des rendus ou les problèmes de piste audio.

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Developh/resolve-cut/tree/HEAD/skills/resolve-cut

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 resolve-cut ?

Vous assemblez, rendez et vérifiez des vidéos dans DaVinci Resolve Studio via des scripts sauvegardés avec paramètres. Vous ne réécrivez pas l'assemblage à chaque session : vous appelez les scripts, lisez ce qu'ils renvoient et vérifiez le résultat avec des nombres et des trames. Le jugement reste humain : la personne décide ce qui reste, vous exécutez et mesurez.

$SKILL ci-dessous est le dossier de ce skill (où se trouve ce fichier). Les scripts dans scripts/resolve/ s'exécutent dans Resolve via run.py ; les scripts dans scripts/media/ sont du Python pur avec ffmpeg. Chaque script a --help.

Avant de commencer

  1. Réponse de Resolve : python3 "$SKILL/scripts/resolve/run.py" - '{}' <<< 'result = resolve.GetVersionString()'. Le code de sortie 2 signifie que Resolve est fermé, que c'est l'édition gratuite, ou que Préférences > Système > Général > Scripting externe utilisant n'est pas réglé sur Local.
  2. ffmpeg -version, python3 -c "import numpy, PIL" et ELEVENLABS_API_KEY (environnement ou ./.env).
  3. Si le projet conserve un fichier de notes (VIDEO_NOTES.md ou similaire), lisez-le : ce que la personne a approuvé et rejeté auparavant. Ne demandez pas deux fois la même correction.
  4. Dossier de travail : tout ce que vous écrivez (transcriptions, dossier, trames, rendus) va dans un dossier de travail, jamais dans le dossier des rushes.

Le flux

1. Transcrire. Transcriptions mot pour mot, un JSON par clip : python3 "$SKILL/scripts/media/transcribe.py" <dossier des clips> --out work/transcripts [--language por]. La transcription est la base de tout : choisir les prises, couper sur les limites de trame et vérifier le mix final.

2. Dossier. Tout le matériel dans un fichier texte compact, lu une fois : python3 "$SKILL/scripts/media/dossier.py" <dossier des clips> --transcripts work/transcripts --out work/dossier.md [--sheets]. Il liste chaque phrase avec son temps et signale «repeats C0076 20.2» quand une phrase commence comme une précédente : une autre tentative de la même réplique. Avec un script, gardez la dernière prise complète de chaque paragraphe ; supprimez les hésitations, les faux départs et les tentatives répétées. Ouvrez un clip uniquement pour décider quelque chose : python3 "$SKILL/scripts/media/inspect_range.py" <clip> <t0> <t1> --words work/transcripts/<clip>.json (trames, forme d'onde et mots dans une seule image).

3. Liste de coupes. Écrivez work/plan.json avec les prises choisies dans l'ordre ({"Lesson 01 v1": [["01a", "C0081", 1.9, 12.6], ["01b", "C0083", 5.4, 23.8], ...]} : prise, clip, de, à en secondes du clip), puis : python3 "$SKILL/scripts/media/cut_list.py" work/plan.json work/transcripts <dossier des clips> work/cuts.json. Les coupes atterrissent sur la limite de trame la plus silencieuse à côté des mots, les pauses de plus d'1 s sont raccourcies, et les segments alternent le zoom 1 / 1.2 pour que les coupes entre les prises ne sautent pas. Pour un faux départ sans écart ("co- contar"), forcez la trame avec {"in_frame": N} ou {"out_frame": N}. Notes pour le monteur : add_markers.py.

4. Assembler dans Resolve. Une opération lourde par appel, et lisez chaque result avant le suivant :

R="$SKILL/scripts/resolve/run.py"
python3 "$R" "$SKILL/scripts/resolve/project.py" '{"name": "Lesson 01", "width": 1920, "height": 1080, "fps": "25"}'
python3 "$R" "$SKILL/scripts/resolve/assemble.py" '{"phase": "import", "bin": "Raw", "media": "/abs/clips", "files": ["C0081.MP4"]}'
python3 "$R" "$SKILL/scripts/resolve/assemble.py" '{"phase": "timeline", "bin": "Raw", "cuts": "/abs/work/cuts.json", "timeline": "Lesson 01 v1", "zoom": {"center": [0.45, 0.37]}, "voice_isolation": 50}'

zoom.center est l'endroit où se trouve le visage (fraction de la trame), donc le zoom avant le maintient en place. Vérifiez que frames == expected et que failures est vide.

5. Regarder avant le rendu. frames.py exporte les trames directement depuis la timeline en moins d'une seconde ({"timeline": "Lesson 01 v1", "frames": [100, 500], "folder": "/abs/work/frames", "max": 960}). Regardez une trame normale et une trame zoomée.

6. Rendre. python3 "$R" "$SKILL/scripts/resolve/render.py" '{"phase": "start", "timeline": "Lesson 01 v1", "folder": "/abs/out", "name": "lesson-01", "preset": "reel", "width": 1920, "height": 1080, "mark": [0, <frames - 1>]}', puis interrogez {"phase": "status", "job": "<id>"} toutes les 10 s jusqu'à ce que JobStatus soit Complete. Attendez la fin du rendu avant de répondre : une exécution sans tête qui termine son tour au "rendu démarré" ne laisse personne pour le vérifier.

7. Vérifier. python3 "$SKILL/scripts/media/qc.py" out/lesson-01.mp4 --expected <frames> --transcribe (ajoutez --ref contre la dernière version approuvée, --frames pour une feuille, --simulate pour Instagram). Lisez la transcription du mix final à chaque coupe : les mots répétés ("decide, decide"), les mots coupés et les mots au mauvais endroit sont les défauts que crée une liste de coupes. Confirmez une coupe suspecte sur la forme d'onde (inspect_range.py) avant de la déplacer, corrigez la liste de coupes, assemblez une nouvelle version (v2) et rendez à nouveau. Au maximum 3 rounds, chaque défaut nommé avec son temps exact. Ne dites jamais que c'est fini parce que ça "a l'air correct" : citez les chiffres.

8. Livrer. loudness.py quand le mix n'est pas dans la cible (gain linéaire et un limiteur, jamais loudnorm), puis deliver.py export.mp4 clean.mp4 [--no-editlist] [--copy <folder>] : pas de piste de timecode, pas de métadonnées, moov en premier, copie comparée octet par octet.

9. Réviser, après l'approbation de la personne. Écrivez dans le fichier de notes ce qu'ils ont approuvé et rejeté, dans leurs mots, une ligne chacun ; chaque nouveau piège avec sa date ; et chaque routine que vous avez faite à la main plus d'une fois devient un script avec paramètres à côté de ceux-ci.

Exécution de scripts dans Resolve

  • run.py se connecte à Resolve ouvert et exécute un script avec resolve, project, P (le JSON) et __file__ définis, puis imprime result en JSON. Cela coûte beaucoup moins de tokens que d'écrire le même script via un MCP.
  • Avec un serveur MCP à la place (officiel run_script_unsafe) : P = {...}; __file__ = "<abs path of the script>"; exec(open(__file__, encoding="utf-8").read()). Le bac à sable lit les fichiers en ASCII sans encoding, et les noms persistent entre les appels : les scripts préfixent leurs variables.
  • Sauvegardez avant et après l'écriture (GetProjectManager().SaveProject()) ; il n'y a pas d'annulation. Faites chaque nouvelle version sur une copie de la timeline (DuplicateTimeline, qui copie aussi les comps Fusion).
  • Consultez l'API au lieu de deviner : search_scripting_api, get_scripting_docs et get_whats_new du MCP officiel (une fois par session), ou le README de Blackmagic dans le dossier Developer/Scripting de Resolve (Aide > Documentation > Développeur).
  • Nouvelle opération qui se répétera ? Écrivez-la une fois comme un script avec un dictionnaire P et un result, à côté de ceux-ci.

Cibles de livraison

DestinationImageSon
Reels, Stories, Shorts, TikTok1440x2560 à la fréquence d'images de tournage, H.264 High à environ 20 Mbps réel, tags Rec.709 (1-1-1), faststart-14 LUFS, crête réelle sous -1.5 dBTP
Leçons et courstel qu'enregistré (1920x1080 ou 3840x2160)-16 LUFS, crête réelle jusqu'à -1 dBTP
YouTubele master 4K (les uploads 1080p perdent en qualité), MP4 sans listes d'éditionle mix du master
LinkedIn1920x1080 et 1080x1920 à 16 Mbps, avec SRTle mix du master

Pièges vérifiés

Mesuré sur macOS avec Resolve Studio 21.1.1 et 21.1.2, octobre et novembre 2026.

Machine

  • Un seul ffmpeg à la fois, avec nice -n 15 et -threads 2 : 96 processus ffmpeg parallèles ont gelé le Mac et forcé un redémarrage.
  • En zsh, $var ne se divise pas en mots (ffmpeg $args casse) : construisez les listes d'arguments en Python.
  • Écrivez les sorties dans le dossier de travail : un assistant qui sauvegardait des images à côté du clip a écrit dans le disque des rushes.

Configuration de Resolve et API

  • Resolve 21.1 a déplacé le scripting Python vers Studio : run.py et les deux serveurs MCP nécessitent DaVinci Resolve Studio.
  • Le scripting externe doit être réglé sur Local (Préférences > Système > Général) sinon scriptapp("Resolve") retourne None.
  • StartRendering est le dernier appel d'un script : tout le reste retourne None jusqu'à la fin du rendu.
  • La fréquence d'images du projet se verrouille lorsque la première timeline est créée : définissez-la avant (project.py).
  • Résolution : SetSetting une clé à la fois, useCustomSettings d'abord.
  • Le délai d'attente MCP (10 s par défaut, 60 s au maximum) renvoie une erreur mais le script continue de s'exécuter dans Resolve : vérifiez l'état avant de le relancer.
  • Il n'y a pas de rogner, déplacer ou glisser : supprimez l'élément et ajoutez-le à nouveau avec startFrame, endFrame (exclusif) et recordFrame.
  • startFrame compte à partir de la première trame du fichier, même avec un timecode de caméra.
  • GetSourceStartFrame lit parfois une trame trop tôt (866 lit 865) alors que le placement est correct : lisez le point d'entrée avec GetLeftOffset.
  • AddMarker conserve un marqueur par trame.
  • ReplaceClip efface les métadonnées du clip.
  • SetTrackEnable retourne True et ne change rien sur certaines timelines : désactivez les clips avec SetClipEnabled et confirmez sur une trame exportée.
  • SetClipEnabled sur une timeline qui n'est pas la courante retourne False : SetCurrentTimeline d'abord, puis confirmez avec GetClipEnabled.
  • DeleteClips(items, True) ripple toutes les pistes : supprimez d'abord, sans ripple, tout ce qui croise la coupe (pistes, sous-titres).
  • L'isolation vocale fonctionne par script : TimelineItem.SetVoiceIsolationState({"isEnabled": True, "amount": 100}) a réduit la réverbération de la pièce de 3 à 4 dB ; Timeline.SetVoiceIsolationState(track, {...}) règle un contrôle pour toute une piste.
  • L'API ne peut pas définir les paramètres ResolveFX (Affinage du visage, Suppression des imperfections) : une personne les règle, ou vous pilotez l'interface via l'accessibilité.
  • Avec l'écran verrouillé ou Resolve minimisé, la fenêtre disparaît de l'accessibilité mais l'API continue de fonctionner : vérifiez avec des trames exportées.
  • Super Scale est une propriété du media pool : SetClipProperty("Super Scale", 2) ; un fichier de remplacement nécessite de la redéfinir.
  • Les LUT pour Graph.SetLUT vont dans le dossier système des LUT de Resolve, dans un sous-dossier, passées par chemin relatif après RefreshLUTList().
  • Changer de page pendant que Resolve lit provoque un blocage ; item.GetFusionCompByIndex(1).Execute(lua) modifie un comp sans ouvrir la page Fusion.

Importation et médias

  • Un ProRes par appel d'importation : plusieurs ProRes 4444 (et une fois deux nouveaux ProRes 422) en un seul appel ont planté Resolve 21.1 (UiMpController, std::out_of_range). Les MP4 de caméra, 22 en un appel, étaient corrects.
  • Après ce plantage, un processus ResolvePython orphelin fait que le MCP launch_resolve signale Resolve comme en cours d'exécution : tuez-le et rouvrez Resolve.
  • ImportMedia avec une liste de chemins : le formulaire avec des dictionnaires a retourné None pour MP4 sur 21.1.
  • Resolve met en cache le décodage par chemin : un fichier que vous rendez à nouveau reçoit un nouveau nom.
  • Le PCM 24 bits little-endian dans MOV est lu comme du bruit blanc : utilisez pcm_s24be.
  • L'HEVC iPhone a planté le décodeur macOS : éditez à partir de ProRes.
  • L'HDR iPhone (HLG, Dolby Vision) : notre propre mappage tonal semblait délavé et a été rejeté deux fois. Demandez une exportation SDR au début.
  • Un .mov d'une trame s'importe comme une image fixe de 150 trames : donnez-lui au moins 3 trames et rognez sur la timeline.
  • Alpha droite : Resolve lit l'alpha non prémultiplié, donc une superposition faite avec ffmpeg overlay sur un fond transparent devient sombre ; positionnez-la avec pad=W:H:x:y:[email protected].

Rendu

  • Avec SelectAllFrames, StartRendering retourne parfois False : définissez MarkIn/MarkOut (render.py mark), ce qui coupe aussi les queues sonores qui allongent une timeline.
  • Un travail H.264 créé juste après un travail audio uniquement est sorti sans vidéo : chargez un préréglage avant SetRenderSettings, et vérifiez la présence du flux vidéo avec ffprobe.
  • VideoQuality H.264 est un plafond, pas une moyenne : 20000 a donné 14.7 Mbps et 27300 a donné 20.7 Mbps à 1440x2560.
  • "Forcer le redimensionnement à la meilleure qualité" n'est pas une clé SetRenderSettings, mais il voyage à l'intérieur d'un préréglage de rendu (ForceHighestQualitySizing).
  • ExportRenderPreset(name, path) traite path comme un dossier ; ImportRenderPreset nomme le préréglage d'après le fichier.
  • Les préréglages stockent une fréquence d'images : définissez FrameRate à partir de la timeline, ou une timeline à 29.97 est convertie en rendu (render.py le fait).
  • ExportFrame (21.1.2) a donné 4 trames à 1440x2560 en 0.75 s, entre 41 et 46 dB du rendu : vérifiez les trames sans rendu.

Son et transcriptions

  • Une coupe entre deux prises peut joindre un mot répété ("decide, decide") : transcrivez le mix final et cherchez les doublons. Corrigez sans changer la longueur : terminez la première pièce avant le mot, commencez la seconde plus tôt dans la pause de la bonne prise.
  • La transcription n'entend pas les murmures et les souffles : les points de coupe proviennent du son de la caméra (cut_list.py).
  • Scribe a placé un mot 3 s trop tôt, après un clap et un murmure : confirmez sur la forme d'onde avant de déplacer une coupe.
  • Les effets sonores MP3 arrivent environ 60 ms en retard (le délai de l'encodeur n'est pas compensé) : utilisez WAV pour tout ce qui doit tomber sur une trame.
  • loudnorm en un seul passage est dynamique et modifie le mix approuvé ; en deux passages, il revient silencieusement en dynamique : utilisez loudness.py.

Séquences et plateformes

  • 25 fps sur Instagram : servi à 25 (ffprobe des fichiers servis, novembre 2026). Le bégaiement provient des iPhones ProMotion, qui n'ont pas de mode 25 ou 50 Hz. Gardez les séquences 25 fps à 25 (la conversion à 30 répète une trame sur cinq) ; tournez de nouvelles séquences à 29.97 avec un obturateur 1/50.
  • Le scintillement sous les lumières 50 Hz dépend de l'obturateur, pas de la fréquence d'images : 1/50 et 1/100 ne scintillent pas ; 1/60 à 30 fps oui.
  • Instagram ré-encode sur le téléphone et à nouveau sur le serveur : la livraison de base est d'environ 720x1280 à 1.4 Mbps, avec un son normalisé à environ -14 LUFS, donc un master au-dessus de -14 ne gagne rien. qc.py --simulate montre ce qui survit.
  • CRF dans ffmpeg affame les fonds sombres : un reel laissé à 6.8 Mbps. Vérifiez le débit binaire réel avant de livrer.
  • Une exécution sans tête claude -p termine son tour lorsque le rendu commence, sauf si l'invite dit d'attendre.

Scripts

ScriptCe qu'il fait
scripts/media/transcribe.pyJSON mot par mot par clip (clé via stdin, jamais dans la liste des processus)
scripts/media/dossier.pychaque clip sous forme de texte compact : phrases avec temps, pauses, tentatives répétées, feuilles de trame optionnelles
scripts/media/inspect_range.pyune image d'une plage : trames, forme d'onde, mots avec temps
scripts/media/cut_list.pyprend plan.json, transcrit, chemins des clips → cuts.json avec limites de trames alternance du zoom
scripts/media/loudness.pyapplique un gain linéaire et un limiteur, pas de loudnorm
scripts/media/deliver.pyexport propre sans timecode, métadonnées, édition ; moov first ; comparaison octet par octet
scripts/media/qc.pyvérifie les trames, transcrit le rendu, compare avec la version de référence, simule Instagram
scripts/resolve/run.pyconnecte à Resolve, exécute un script avec resolve, project, P, __file__, imprime result JSON
scripts/resolve/project.pycrée un projet avec résolution, fréquence d'images
scripts/resolve/assemble.pyimporte des médias, assemble la timeline à partir de cuts.json, zoom, isolation vocale
scripts/resolve/render.pydémarre le rendu avec un préréglage, interroge l'état
scripts/resolve/frames.pyexporte des trames depuis la timeline sans rendu

Skills associés