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.FFmpeg
Vérifiez ensuite :
# Version (utile pour diagnostiquer un build manquant de codecs)ffmpeg -version
Si 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 --version
Méthode B – Gestionnaire de paquets distribution
Arch Linux :
sudo pacman -Syu vhs
Méthode C – Windows (winget / Scoop)
# Wingetwinget install charmbracelet.vhs
# Ou Scoopscoop install vhs
Mé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 --version
Adapter 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.gif
Si 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 ffmpeg
en tête de la tape pour échouer tôt - Thème non appliqué : s’assurer que la directive
Set Theme
est placée avant toute commandeType
- Commande lente imprévisible : remplacer pause fixe par
Wait
aprè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"Enter
Principales 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
Set
en début de fichier - Toujours définir explicitement
Output
- Utiliser
Require
pour des dépendances critiques (ffmpeg
,git
) - Préférer
Sleep
courts +Wait
plutô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.tape
Vous 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
Set
cohé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.tape
Formats 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.1
secondes)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 Block
Publication et partage
VHS propose un hébergement intégré :
# Génération + upload immédiat si --publish est présentvhs demo.tape --publish
Ou après génération :
# Publication d'un fichier existantvhs publish demo.gif
La 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/*.gif
Bonnes pratiques CI :
- Ne pas stocker les GIFs générés dans Git (poids, diffs inutiles)
- Versionner uniquement les
.tape
- Publier via
--publish
ou 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
Wait
aprè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.1
ou1.2
fluidifie sans rendre illisible - Post‑traitement :
gifsicle -O3 demo.gif -o demo-opt.gif
- Format alternatif : proposer aussi
.webm
ou.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.gif
Organisation d’un répertoire demo/
demo/ 00-intro.tape 10-installation.tape 20-flux-base.tape fragments/ palette.tape header.tape
Exemple de modularisation
# Fichier principalOutput ./workflow.gifSource ./fragments/header.tapeSource ./fragments/palette.tapeType "make build"EnterWaitType "./bin/outillage --help"Enter
Sé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 ↗