Communitygithub.com

AmanVarshney01/tcut

Enregistrez des vidéos de terminal reproductibles (MP4/GIF/SVG/HTML) à partir de scripts TypeScript ou de sessions en direct avec l'interface en ligne de commande tcut. Utilisez-le lorsque vous souhaitez une démo de terminal, un screencast CLI, un enregistrement TUI ou un GIF de terminal animé pour un README, un site web ou un post sur les réseaux sociaux.

Qu'est-ce que tcut ?

tcut est un outil CLI puissant conçu pour enregistrer des vidéos de terminal reproductibles et déterministes. Il utilise un véritable shell PTY avec un terminal Ghostty sans tête, garantissant que chaque enregistrement produit exactement les mêmes pixels à chaque exécution. Les scripts sont écrits en TypeScript standard, sans nécessiter l'apprentissage d'un langage dédié (DSL). L'outil prend en charge la sortie dans plusieurs formats, notamment MP4, GIF, SVG et HTML, avec des options de personnalisation étendues comme les thèmes, les superpositions de touches et le zoom sur des régions spécifiques. tcut est idéal pour les développeurs et les agents IA souhaitant créer des démos CLI, des screencasts TUI ou des GIF animés pour des documentations, des présentations ou des publications sur les réseaux sociaux, avec une reproductibilité et une intégration CI/CD faciles grâce à des fonctionnalités comme `tcut test` et `tcut diff`.

Compatible avec✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/AmanVarshney01/tcut/tree/HEAD/skills/tcut

Demander à votre IA préférée

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

Documentation

tcut — sessions terminal en vidéo

tcut enregistre un véritable shell (PTY + terminal Ghostty sans tête) et rend des vidéos déterministes. Les scripts sont en TypeScript simple — pas de DSL. Même enregistrement, mêmes pixels, à chaque fois.

Configuration

bun add -g termcut   # Bun >= 1.4, installe la commande `tcut`

MP4/GIF/WebM nécessitent ffmpeg dans le PATH. Les lecteurs SVG et HTML ne nécessitent rien d'autre. Tout prend en charge --json pour des résultats lisibles par machine ; jamais de demandes interactives.

Deux façons d'enregistrer

Scripté (recommandé pour les agents) — écrivez demo.video.ts, exécutez tcut demo.video.ts :

import { defineVideo } from "tcut";

export default defineVideo(
  { output: ["demo.mp4", "demo.gif"], preset: "x", theme: "Catppuccin Mocha", keys: true, maxPause: "1.5s" },
  async (t) => {
    await t.run("bun --version");        // tape, appuie sur Entrée, attend le retour de l'invite
    await t.expect(/1\.\d+/);            // vérifie sur l'écran rendu (échoue la vidéo si absent)
    await t.sleep("1.5s");
  },
);

En direct — tcut rec -o demo.gif ouvre un shell, enregistre jusqu'à exit, et écrit à la fois l'enregistrement exact (demo.cast) et un script modifiable (demo.video.ts) de ce qui a été tapé. tcut rec -o demo.mp4 -- npm create vite enregistre une seule commande.

L'API t (dans defineVideo)

  • t.run(cmd, { wait? }) — tape + Entrée + attend l'invite du shell (basé sur l'écran, pas sur une minuterie)
  • t.type(text) / t.paste(text) / t.enter() / t.escape() / t.tab() — pilote les TUI touche par touche
  • t.up/down/left/right/pageUp/pageDown/home/end(), t.ctrl("c"), t.alt("b"), t.shift("tab"), t.key("f5"), t.scrollUp/scrollDown()
  • t.wait(regex?, { scope: "line" | "screen" }) — attend que l'écran l'affiche ; t.expect(re) — vérifie
  • t.sleep("800ms") — les durées acceptent "500ms", "1.5s", des nombres (ms)
  • t.hide(async () => { ... }) — exécute la configuration hors caméra (l'état persiste ; ne tuez pas les tâches en arrière-plan ici)
  • t.print(markdown) / t.title(text) — affiche des légendes Markdown dans la vidéo sans taper
  • t.zoom({ rows: [0, 5], cols: [0, 60], duration: "500ms" }) — agrandit une région ; t.zoom(null) réinitialise
  • t.slide("Déployer dans le cloud", { eyebrow: "3", subtitle: "…", during }) — carte de transition plein écran entre les démos de fonctionnalités : grand titre centré en typographie réelle, fondu entrée/sortie, enregistre un chapitre du même nom ; during: async () => … exécute cd/clear/configuration du serveur de manière invisible derrière
  • t.chapter("Installer") — vraies métadonnées de chapitre MP4, et un point de coupure : --chapters Installer / --split-chapters au moment du rendu
  • t.expect(/…/, { scope: "scrollback" }) voit la sortie qui a défilé ; t.scrollback() renvoie la transcription complète ; -o demo.log l'écrit
  • Les flèches sont envoyées en SS3 lorsque le programme a activé le mode curseur d'application, t.paste() est entre crochets lorsque le programme l'a demandé — les éditeurs se comportent comme avec un vrai terminal ; print("[text](url)") crée un lien cliquable en SVG/HTML
  • title: "auto" suit les titres OSC ; tcut doctor demo.cast explique ce qu'un enregistrement a utilisé et ce que tcut ne peut pas afficher (images intégrées)
  • t.timelapse(async () => { await t.run("bun install") }, { speed: 8 }) — tout ce qui se trouve à l'intérieur joue 8× plus vite (maxPause supprime uniquement le silence ; cela compresse la sortie)
  • t.snapshot("shot.png") / t.snapshot("hero.svg") — image fixe de ce moment exact à chaque rendu (screenshot = alias), t.clear(), t.resize(cols, rows), t.screen() / t.line() pour lire l'écran
  • Panneau navigateur : browser: { position: "right" | "overlay", width } dans la configuration, puis t.browser.goto(url), t.browser.waitFor(/text/), t.browser.click(sel), t.focus("browser" | "terminal") — enregistre une vraie WebView à côté/sur le terminal (démos de serveur de développement)

Éléments essentiels de configuration

output (tableau = plusieurs formats), preset: "readme" | "x" | "youtube" | "square", theme (~600 thèmes Ghostty, tcut themes), cols/rows ou width/height (px), fps, scale: 2 (même mise en page, 2× les pixels — utilisez pour Retina/HiDPI ou tout ce qu'un lecteur agrandira), typingSpeed/typingJitter, keys: true (superposition des touches, une puce à la fois ; { limit, font, color, background, radius, position }), maxPause: "1.5s" (compression de l'inactivité), requires: ["bun", "eza"] (échoue rapidement avant l'enregistrement si un outil manque — également dans tcut test), windowBar: "none" + margin: 0 + borderRadius: 0 pour un terminal nu, title, marginFill ("transparent" = alpha réel en png/webp/gif/webm/svg/html ; mp4 revient à la normale), shadow: true (ombre portée douce ; la marge par défaut est de 40), watermark: "© vous" ou { image: "logo.png", position: "top-left", opacity, size }.

Couper et joindre (sans ré-enregistrement)

Tout cela sur la timeline visible du cast, donc chaque format fonctionne et le résultat est toujours un .cast :

tcut render demo.cast --from 2s --to 10s -o clip.gif      # fenêtre temporelle
tcut render demo.cast --chapters Zoom,Intro -o clip.mp4    # chapitres, dans cet ordre
tcut render demo.cast --split-chapters -o demo.mp4         # demo-01-intro.mp4, demo-02-zoom.mp4 …  (bibliothèque de clips idéale pour Remotion)
tcut cut demo.cast --from 2s --to 10s                      # écrit demo-cut.cast
tcut concat intro.cast demo.cast --gap 500ms -o launch.mp4 # mêmes cols×rows requis ; l'écran se réinitialise à chaque jonction

Rendre à nouveau sans ré-exécuter

L'enregistrement (.cast) et le rendu sont séparés :

tcut render demo.cast --theme "Gruvbox Dark" -o demo.svg
tcut render demo.cast --width 1280 --height 720 --speed 1.5 -o demo.mp4

CI / tests

  • tcut test demo.video.ts — exécute le script comme un test (rapide, pas d'encodage vidéo)
  • tcut diff a.cast b.cast [--images dir] — compare le texte à l'écran de deux enregistrements, quitte avec le code 1 en cas de dérive

Pièges

  • Serveurs de développement en arrière-plan dans le PTY : bun run dev </dev/null >/tmp/dev.log 2>&1 & (les lecteurs de stdin reçoivent SIGTTIN ; les logs parasites repeignent sur les TUI)
  • Attendez l'écran, pas le temps : préférez t.run / t.wait(/Local:/, { scope: "screen" }) aux longs sleep
  • t.hide conserve l'état — un kill caché à la fin fuit dans la dernière image
  • Pour les TUI (nvim, lazygit, claude), lancez avec t.run(cmd, { wait: /quelque-chose-sur-écran/ }), puis pilotez avec les touches

Référence complète : https://tcut.amanv.dev/llms.txt

Utiliser tcut comme une bibliothèque

import { defineVideo, renderCast } from "termcut" (Bun uniquement). defineVideo(config, script) renvoie un Video : await video.run({ force, log }) enregistre et rend et renvoie { outputs, screenshots, durationSeconds, recording } ; video.record() et video.render(recording, { overrides, clip }) séparent les étapes ; renderCast(file, overrides) re-rend un cast sans shell. Également exportés : recordLive, cutRecording, concatRecordings, selectChapters, buildSvg, buildHtml, replayFrames, diffCasts, diagnoseCast, generateScript, runScriptTests, publishFiles. En CI, transmettez explicitement theme/font ("auto" lit le terminal en cours d'exécution) et effectuez le rendu d'une vidéo à la fois.

Individual skills in this repo

This repo contains 7 individual skills — each has its own dedicated page.

Skills associés