Communitygithub.com

AmanVarshney01/tcut

Graba vídeos reproducibles de terminal (MP4/GIF/SVG/HTML) desde scripts TypeScript o sesiones en vivo con la CLI tcut. Úsalo cuando el usuario quiera una demo de terminal, screencast de CLI, grabación TUI o un GIF animado de terminal para un README, sitio web o publicación en redes sociales.

¿Qué es tcut?

tcut es una herramienta de línea de comandos que permite grabar sesiones de terminal y convertirlas en vídeos reproducibles en múltiples formatos (MP4, GIF, SVG, HTML, WebM). Está diseñada para desarrolladores y agentes de IA que necesitan crear demos precisas de herramientas CLI, TUIs o flujos de trabajo en terminal. Su principal ventaja es que las grabaciones son deterministas: dado el mismo script y configuración, se obtienen exactamente los mismos píxeles cada vez. tcut soporta dos modos de grabación: scripteado (escribiendo un archivo TypeScript con una API fluida) y en vivo (grabando una sesión real de shell). Además, ofrece capacidades avanzadas como inserción de tarjetas de transición, navegador web integrado, zoom, capítulos MP4, superposición de teclas, y edición de grabaciones sin necesidad de regrabar (cortar, unir, dividir por capítulos). Se integra perfectamente en CI/CD con comandos para testeo y diff de grabaciones.

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

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

tcut — sesiones de terminal a vídeo

tcut graba un shell real (PTY + terminal Ghostty sin cabeza) y renderiza vídeos deterministas. Los scripts son TypeScript plano, sin DSL. La misma grabación, los mismos píxeles, siempre.

Configuración

bun add -g termcut   # Bun >= 1.4, instala el comando `tcut`

MP4/GIF/WebM necesitan ffmpeg en PATH. Los reproductores SVG y HTML no necesitan nada más. Todo soporta --json para resultados legibles por máquina; nunca pregunta.

Dos formas de grabar

Scripteada (preferida para agentes) — escribe demo.video.ts, ejecuta 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");        // escribe, presiona Enter, espera a que vuelva el prompt
    await t.expect(/1\.\d+/);            // afirma en la pantalla renderizada (falla el vídeo si no está)
    await t.sleep("1.5s");
  },
);

En vivo — tcut rec -o demo.gif abre un shell, graba hasta exit, y escribe tanto la grabación exacta (demo.cast) como un script editable (demo.video.ts) de lo que se escribió. tcut rec -o demo.mp4 -- npm create vite graba un solo comando.

La API t (dentro de defineVideo)

  • t.run(cmd, { wait? }) — escribe + Enter + espera el prompt del shell (basado en pantalla, no en temporizador)
  • t.type(texto) / t.paste(texto) / t.enter() / t.escape() / t.tab() — maneja TUIs tecla por tecla
  • 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" }) — espera hasta que la pantalla lo muestre; t.expect(re) — afirma
  • t.sleep("800ms") — duraciones aceptan "500ms", "1.5s", números (ms)
  • t.hide(async () => { ... }) — ejecuta configuración fuera de cámara (el estado persiste; no mates trabajos en segundo plano aquí)
  • t.print(markdown) / t.title(texto) — renderiza leyendas Markdown en el vídeo sin escribir
  • t.zoom({ rows: [0, 5], cols: [0, 60], duration: "500ms" }) — magnifica una región; t.zoom(null) reinicia
  • t.slide("Desplegar en la nube", { eyebrow: "3", subtitle: "…", during }) — tarjeta de transición a pantalla completa entre demos de funcionalidades: encabezado grande centrado con tipografía real, se desvanece, graba un capítulo con el mismo nombre; during: async () => … ejecuta cd/clear/configuración de servidor invisiblemente detrás
  • t.chapter("Instalar") — metadatos reales de capítulo MP4, y un punto de corte: --chapters Instalar / --split-chapters al renderizar
  • t.expect(/…/, { scope: "scrollback" }) ve la salida que se desplazó fuera; t.scrollback() devuelve la transcripción completa; -o demo.log la escribe
  • Las flechas se envían como SS3 cuando el programa activó el modo cursor de aplicación, t.paste() es bracketed cuando el programa lo solicitó — los editores se comportan como con un terminal real; print("[texto](url)") hace un enlace clickeable en SVG/HTML
  • title: "auto" sigue títulos OSC; tcut doctor demo.cast explica qué usó una grabación y qué tcut no puede mostrar (imágenes inline)
  • t.timelapse(async () => { await t.run("bun install") }, { speed: 8 }) — todo lo interno se reproduce 8× más rápido (maxPause solo elimina silencios; esto comprime la salida)
  • t.snapshot("foto.png") / t.snapshot("hero.svg") — instantánea de ese momento exacto en cada renderizado (screenshot es alias), t.clear(), t.resize(cols, rows), t.screen() / t.line() para leer la pantalla
  • Panel del navegador: browser: { position: "right" | "overlay", width } en la configuración, luego t.browser.goto(url), t.browser.waitFor(/text/), t.browser.click(sel), t.focus("browser" | "terminal") — graba una WebView real junto/sobre el terminal (demos de servidores de desarrollo)

Aspectos esenciales de configuración

output (array = múltiples formatos), preset: "readme" | "x" | "youtube" | "square", theme (~600 temas de Ghostty, tcut themes), cols/rows o width/height (px), fps, scale: 2 (mismo diseño, 2× los píxeles — úsalo para Retina/HiDPI o cualquier cosa que el reproductor vaya a escalar), typingSpeed/typingJitter, keys: true (superposición de pulsaciones de teclas, un chip a la vez; { limit, font, color, background, radius, position }), maxPause: "1.5s" (compresión de inactividad), requires: ["bun", "eza"] (falla rápido antes de grabar si falta una herramienta — también en tcut test), windowBar: "none" + margin: 0 + borderRadius: 0 para un terminal desnudo, title, marginFill ("transparent" = alfa real en png/webp/gif/webm/svg/html; mp4 usa fallback), shadow: true (sombra suave; margin por defecto 40), watermark: "© tú" o { image: "logo.png", position: "top-left", opacity, size }.

Cortar y unir (sin regrabar)

Todo en la línea de tiempo visible del cast, por lo que cada formato funciona y el resultado sigue siendo un .cast:

tcut render demo.cast --from 2s --to 10s -o clip.gif      # ventana de tiempo
tcut render demo.cast --chapters Zoom,Intro -o clip.mp4    # capítulos, en ese orden
tcut render demo.cast --split-chapters -o demo.mp4         # demo-01-intro.mp4, demo-02-zoom.mp4 …  (biblioteca de clips ideal para Remotion)
tcut cut demo.cast --from 2s --to 10s                      # escribe demo-cut.cast
tcut concat intro.cast demo.cast --gap 500ms -o launch.mp4 # mismas cols×rows requeridas; la pantalla se reinicia en cada unión

Renderizar de nuevo sin volver a ejecutar

La grabación (.cast) y el renderizado están separados:

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 / testing

  • tcut test demo.video.ts — ejecuta el script como prueba (rápido, sin codificación de vídeo)
  • tcut diff a.cast b.cast [--images dir] — compara texto de pantalla de dos grabaciones, sale con 1 si hay deriva

Advertencias

  • Servidores de desarrollo en segundo plano en el PTY: bun run dev </dev/null >/tmp/dev.log 2>&1 & (los lectores de stdin reciben SIGTTIN; los logs perdidos repintan sobre TUIs)
  • Espera en la pantalla, no en el tiempo: prefiere t.run / t.wait(/Local:/, { scope: "screen" }) sobre sleeps largos
  • t.hide mantiene el estado — un kill oculto al final se filtra en el último fotograma
  • Para TUIs (nvim, lazygit, claude), inicia con t.run(cmd, { wait: /algo-en-pantalla/ }), luego maneja con teclas

Referencia completa: https://tcut.amanv.dev/llms.txt

Usar tcut como biblioteca

import { defineVideo, renderCast } from "termcut" (solo Bun). defineVideo(config, script) devuelve un Video: await video.run({ force, log }) graba y renderiza y devuelve { outputs, screenshots, durationSeconds, recording }; video.record() y video.render(recording, { overrides, clip }) separan los pasos; renderCast(file, overrides) re-renderiza cualquier cast sin un shell. También se exportan: recordLive, cutRecording, concatRecordings, selectChapters, buildSvg, buildHtml, replayFrames, diffCasts, diagnoseCast, generateScript, runScriptTests, publishFiles. En CI pasa theme/font explícitos ("auto" lee el terminal en ejecución) y renderiza un vídeo a la vez.

Individual skills in this repo

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

Skills relacionados