VHS : générer des GIFs de terminal (CLI)
Mise à jour :

VHS est un outil en ligne de commande créé par Charmbracelet qui permet de générer des GIFs et vidéos de sessions terminal à partir d’un fichier déclaratif. Plutôt que de filmer votre écran, vous décrivez le scénario : commandes tapées, sorties attendues, pauses, style visuel. L’outil rejoue ensuite ce script pour produire un rendu propre, reproductible et versionnable.
Prérequis & installation
Cette section commence par l’installation des prérequis système, puis explique plusieurs méthodes d’installation de VHS. L’objectif est que même un débutant en ligne de commande puisse exécuter une première tape en quelques minutes.
Étape 1 : Installer les prérequis
Avant d’installer vhs, assurez-vous que les composants indispensables sont disponibles :
ffmpeg: encode les images successives en GIF / MP4 / WebMttyd: fournit un terminal pseudo‑graphique contrôlé par VHS (souvent installé automatiquement par les paquets)- Un shell : bash / zsh / fish (bash par défaut sur la plupart des distributions)
Installation de ffmpeg
Commandes d’installation selon l’OS :
# Debian / Ubuntusudo apt update && sudo apt install -y ffmpeg curl git
# Fedora / Rocky / Alma / RHELsudo dnf install -y ffmpeg curl git
# Arch Linuxsudo pacman -Syu --needed ffmpeg git curl
# macOS (si Homebrew pas encore installé) - facultatif/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"brew install ffmpeg
# Windows (PowerShell) - installation ffmpeg via wingetwinget install Gyan.FFmpegVérifiez ensuite :
# Version (utile pour diagnostiquer un build manquant de codecs)ffmpeg -versionSi ffmpeg est absent, l’encodage échouera (GIF/vidéo non produits).
Installation de ttyd
ttyd est optionnel mais recommandé pour des rendus plus réalistes (curseur, sélection, etc.). Il est recommandé d’installer une version récente (>= 1.7.2). Le plus simple étant d’installer le dernier binaire précompilé depuis la page des releases GitHub ↗.
# Exemple pour Linux x86_64curl -L https://github.com/tsl0922/ttyd/releases/latest/download/ttyd-linux-x86_64.tar.gz -o ttydsudo install ttyd /usr/local/bin/ttyd --versionttyd version 1.7.7-40e79c7Étape 2 : Installer VHS
Choisissez UNE méthode (la plus simple pour vous). Les résultats sont équivalents.
Méthode A – Homebrew (macOS & Linux)
brew install vhsvhs --versionMéthode B – Gestionnaire de paquets distribution
Arch Linux :
sudo pacman -Syu vhsMéthode C – Windows (winget / Scoop)
# Wingetwinget install charmbracelet.vhs
# Ou Scoopscoop install vhsMéthode D – Binaire précompilé (rapide)
La méthode la plus universelle, sans gestionnaire de paquets. Téléchargez le binaire et installez‑le manuellement.
curl -L https://github.com/charmbracelet/vhs/releases/latest/download/vhs_Linux_x86_64.tar.gz -o vhs.tar.gztar -xf vhs.tar.gzsudo mv vhs /usr/local/bin/vhs --versionAdapter le nom du fichier selon votre OS / architecture.
Méthode E – Depuis la source (Go)
La méthode la plus flexible si vous avez Go installé.
go install github.com/charmbracelet/vhs@latestÉtape 3 : Tests post‑installation
# Afficher la version installéevhs --version# Générer une tape de test minimale et produire un GIFcat > quick.tape <<'EOF'Output quick.gifSet TypingSpeed 120msType "echo VHS OK"EnterSleep 1sEOFvhs quick.tape && ls -lh quick.gifSi quick.gif est créé sans erreur, l’environnement est opérationnel. Votre fichier .gif devrait ressembler à ceci :

Étape 4 : Dépannage rapide
- GIF vide ou non généré : vérifier
ffmpeg -version - Erreur de dépendance : ajouter la directive
Require ffmpegen tête de la tape pour échouer tôt - Thème non appliqué : s’assurer que la directive
Set Themeest placée avant toute commandeType - Commande lente imprévisible : remplacer pause fixe par
Waitaprès la commande
Ecriture d’une tape VHS
Le cœur de VHS : un fichier texte avec extension .tape décrivant la session.
Chaque ligne est une instruction.
Structure générale :
Output ./demo.gifSet FontSize 16Set TypingSpeed 120msRequire ffmpegType "echo 'Bonjour VHS'"EnterSleep 500msType "uname -s"EnterPrincipales instructions
Output <chemin>: définit le fichier de sortie. Format selon extension (.gif,.mp4,.webm,.png-> séquence)Set <Paramètre> <Valeur>: personnalisation (police, thème, vitesse, curseur, dimensions)Type "texte": simule la frappe humaine d’une chaîneEnter: envoie la touche EntréeSleep <durée>: pause (ex:500ms,2s)Wait: attend la fin de la sortie précédente (utile pour des commandes longues)Require <binaire>: vérifie la présence d’une dépendance avant exécutionHide/Show: masquer temporairement une portion pour ne pas l’afficherSource <fichier.tape>: inclure un sous-script (modularisation)
Bonnes pratiques structure
- Grouper les
Seten début de fichier - Toujours définir explicitement
Output - Utiliser
Requirepour des dépendances critiques (ffmpeg,git) - Préférer
Sleepcourts +Waitplutôt que des pauses longues arbitraires - Versionner le
.tape, ignorer les rendus (.gitignore)
Enregistrement actif : vhs record
Si vous préférez partir d’une capture réelle, VHS propose :
# Enregistrer une session interactive et générer un fichier .tapevhs record > session.tapeVous tapez vos commandes normalement, puis terminez avec Ctrl+D. Le fichier
généré peut être nettoyé pour :
- Retirer les fautes de frappe
- Ajuster les temporisations (
Sleep) - Ajouter des
Setcohérents (police, thème, vitesse de frappe)
Cette approche hybride (record puis édition) combine vitesse et précision.
Génération du GIF / vidéo
Une fois la tape prête :
# Génère le média selon l'extension Outputvhs demo.tapeFormats supportés :
.gif: diffusion web / README.mp4: taille réduite, réseaux sociaux.webm: optimisation web moderne.png(dossier) : spritesheet potentielle / post‑traitement
Changez simplement l’extension dans l’instruction Output pour obtenir un autre
format, sans modifier le reste du scénario.
Paramètres Set disponibles
Résumé des principaux réglages supportés (à placer avant toute commande
non‑Set / non‑Output).
Set Shell <bash|zsh|fish|...>: shell utilisé pour exécuter les commandesSet Width <px>/Set Height <px>: dimensions du terminal renduSet FontSize <px>: taille des caractèresSet FontFamily "Nom": police monospacée (doit être installée côté système ou embarquée)Set LetterSpacing <px>: espacement horizontal entre lettresSet LineHeight <ratio>: interligne (ex:1.4)Set TypingSpeed <durée>: délai entre frappes (ex:120ms,0.1secondes)Set Theme { JSON }ouSet Theme "Nom": thème 16 couleurs + foreground/background/cursorSet Padding <px>: espace interne autour de la zone terminalSet Margin <px>: marge externe du cadre vidéoSet MarginFill "#RRGGBB": couleur de fond de la margeSet WindowBar <Colorful|ColorfulRight|Rings|RingsRight|None>: barre décorativeSet BorderRadius <px>: arrondi des coins (souvent avec marge + couleur)Set Framerate <fps>: fréquence de capture (ex:30,60)Set PlaybackSpeed <facteur>: accélération ou ralentissement de lecture finale (ex:1.2)Set LoopOffset <frames|%>: frame de début de boucle GIF (thumbnails plus dynamiques)Set CursorBlink <true|false>: clignotement du curseurSet CursorStyle <Block|Underline|Bar>: forme du curseur
Astuce : regrouper tous les Set et Require en tête de fichier pour éviter
qu’ils ne soient ignorés.
Paramètres d’affichage utiles
Set Width 1000Set Height 600Set FontSize 18Set Theme DraculaSet TypingSpeed 120msSet CursorStyle BlockPublication et partage
VHS propose un hébergement intégré :
# Génération + upload immédiat si --publish est présentvhs demo.tape --publishOu après génération :
# Publication d'un fichier existantvhs publish demo.gifLa commande retourne une URL partageable (https://vhs.charm.sh/...).
Avantages :
- Pas besoin de committer des fichiers lourds
- Rendu optimisé (hébergement Charm)
- Mise à jour automatisable (CI)
Alternative : héberger dans un dépôt GitHub (assets release) ou un CDN (Cloudflare R2 / S3) pour contrôle complet.
Automatisation & intégration CI (GitHub Actions)
Automatiser la régénération garantit que vos GIFs restent synchronisés avec le code source. Exemple de workflow minimal :
name: Generate VHS assetson: push: paths: - "demo/*.tape" workflow_dispatch:jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup VHS run: | sudo apt-get update sudo apt-get install -y ffmpeg curl -fsSL https://raw.githubusercontent.com/charmbracelet/vhs/main/install.sh | bash sudo mv bin/vhs /usr/local/bin/vhs - name: Generate GIFs run: | for f in demo/*.tape; do vhs "$f"; done - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: vhs-gifs path: demo/*.gifBonnes pratiques CI :
- Ne pas stocker les GIFs générés dans Git (poids, diffs inutiles)
- Versionner uniquement les
.tape - Publier via
--publishou artifacts compressés - Ajouter un job périodique (
schedule) si dépendances externes évoluent
Astuces & bonnes pratiques
- Définir une vitesse de frappe modérée :
Set TypingSpeed 90ms(lisible) - Utiliser
Waitaprès des commandes réseau ou build - Ajouter un prompt minimaliste pour lisibilité (
Set Prompt "$ "si supporté) - Masquer secrets / tokens : segment sous
Hide…Show - Externaliser des blocs récurrents (
Source ./fragments/init.tape) - Documenter les choix dans des commentaires en amont du fichier
.tape(lignes commençant par#) - Contrôler la police : préférer une police monospacée lisible (JetBrains Mono, Fira Code)
- Vérifier le poids final des GIFs (optimisation possible via
gifsicle)
Optimisation du poids des GIFs
Réduire la taille des GIFs améliore les performances de chargement dans la documentation.
- Limiter les dimensions : éviter > 1200px de largeur si non nécessaire
- Réduire la durée : supprimer les pauses excessives (
Sleep> 2s) - Ajuster
Framerate: 30 fps suffisent souvent, 24 fps acceptable pour commandes lentes - Palette optimisée : certains thèmes très colorés augmentent la palette → préférer un thème sobre
- Utiliser
PlaybackSpeed:1.1ou1.2fluidifie sans rendre illisible - Post‑traitement :
gifsicle -O3 demo.gif -o demo-opt.gif - Format alternatif : proposer aussi
.webmou.mp4(nettement plus léger) et garder GIF comme fallback - Découper : plusieurs courtes démonstrations plutôt qu’un long scénario monolithique
Exemple pipeline local :
# Optimisation après génération GIFvhs demo.tapegifsicle -O3 demo.gif -o demo-opt.gifOrganisation d’un répertoire demo/
demo/ 00-intro.tape 10-installation.tape 20-flux-base.tape fragments/ palette.tape header.tapeExemple de modularisation
# Fichier principalOutput ./workflow.gifSource ./fragments/header.tapeSource ./fragments/palette.tapeType "make build"EnterWaitType "./bin/outillage --help"EnterSécurité & qualité documentaire
- Éviter de montrer des chemins utilisateurs privés (
/home/user) → utiliser comptes génériques - Purger l’historique de commandes sensibles
- Indiquer dans la doc la commande pour régénérer :
vhs chemin.tape - Ajouter un badge ou une phrase : “Ce GIF est généré automatiquement via CI”
Plus d’infos
- Documentation et dépôt officiel : VHS ↗
- Publication hébergée (option
--publish) : article Charm ↗ - Intégration CI : Action GitHub officielle vhs-action ↗