{"id":50309550,"url":"https://github.com/jurczykpawel/captions-cli","last_synced_at":"2026-05-28T20:00:19.731Z","repository":{"id":360977335,"uuid":"1252546237","full_name":"jurczykpawel/captions-cli","owner":"jurczykpawel","description":"Burn word-level karaoke captions onto videos — local Whisper + ffmpeg/libass, zero SaaS.","archived":false,"fork":false,"pushed_at":"2026-05-28T18:07:53.000Z","size":13344,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-28T18:17:50.682Z","etag":null,"topics":["bun","captions","cli","ffmpeg","karaoke-captions","libass","reels","shorts","subtitles","transcription","typescript","video","whisper","whisper-cpp"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jurczykpawel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-28T16:20:00.000Z","updated_at":"2026-05-28T18:07:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jurczykpawel/captions-cli","commit_stats":null,"previous_names":["jurczykpawel/captions-cli"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/jurczykpawel/captions-cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jurczykpawel%2Fcaptions-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jurczykpawel%2Fcaptions-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jurczykpawel%2Fcaptions-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jurczykpawel%2Fcaptions-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jurczykpawel","download_url":"https://codeload.github.com/jurczykpawel/captions-cli/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jurczykpawel%2Fcaptions-cli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33624221,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bun","captions","cli","ffmpeg","karaoke-captions","libass","reels","shorts","subtitles","transcription","typescript","video","whisper","whisper-cpp"],"created_at":"2026-05-28T20:00:17.321Z","updated_at":"2026-05-28T20:00:19.619Z","avatar_url":"https://github.com/jurczykpawel.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# captions-cli\n\n[![CI](https://github.com/jurczykpawel/captions-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/jurczykpawel/captions-cli/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Bun](https://img.shields.io/badge/runtime-Bun%20%E2%89%A51.1-black)](https://bun.sh)\n\n**Burn word-level karaoke captions onto videos. Local Whisper + pluggable render engine. Zero SaaS.**\n\nA one-command CLI that does what Submagic / CapCut Pro / Veed / Descript do — transcribe audio\nwith Whisper, then render an animated caption overlay onto your video. Difference: it runs on\nyour machine, with open-source tools, with no monthly fee, and your video never leaves the\nlaptop.\n\n```bash\ncaptions reel.mp4                                   # free style (clean-white)\ncaptions reel.mp4 --preset hormozi --lang pl        # basic pack\ncaptions reel.mp4 --preset single-word-pop          # premium pack\n# → reel-captioned.mp4\n```\n\n## Quick start (no terminal experience needed)\n\nYou don't need to know how to code. You need [Docker Desktop](https://www.docker.com/products/docker-desktop/)\n(free) and about 5 minutes.\n\n1. **Install Docker Desktop** and open it — wait until its whale icon says *running*.\n2. **Put your video in one folder.** Example: a folder `videos` with `reel.mp4` inside.\n3. **Open a terminal in that folder:**\n   - **macOS:** right-click the folder in Finder → *New Terminal at Folder*.\n   - **Windows:** open the folder, click the address bar, type `cmd`, press Enter.\n4. **Paste this one line** and press Enter. Change `reel.mp4` to your filename, and `en` to\n   your spoken language (`pl`, `de`, `es`, …):\n   ```bash\n   docker run --rm -v \"$PWD:/work\" -v captions-cache:/data ghcr.io/jurczykpawel/captions-cli:slim /work/reel.mp4 --lang en\n   ```\n   On **Windows** use `\"%cd%:/work\"` instead of `\"$PWD:/work\"`.\n5. **Done.** A new `reel-captioned.mp4` appears next to your video. The first run downloads a\n   ~140 MB speech model (one time); after that it's instant and fully offline.\n\nThat's it — nothing is uploaded, no account, no subscription. Want other caption styles, a\none-line installer, or to run without Docker? See [Install](#install) below.\n\n## Make it a real `captions` command\n\nDon't want to paste the long `docker run …` line every time? Install a tiny wrapper once, then\njust run `captions yourvideo.mp4 --lang pl` from any folder. It finds your video, mounts its\nfolder into the container, and writes the captioned copy right next to it.\n\n**macOS / Linux:**\n\n```bash\nsudo curl -fsSL https://raw.githubusercontent.com/jurczykpawel/captions-cli/main/scripts/captions \\\n  -o /usr/local/bin/captions \u0026\u0026 sudo chmod +x /usr/local/bin/captions\n```\n\n**Windows (PowerShell):** download [`captions.cmd`](scripts/captions.cmd) **and**\n[`captions.ps1`](scripts/captions.ps1) into one folder that's on your `PATH`.\n\nThen, from anywhere:\n\n```bash\ncaptions reel.mp4 --lang pl\ncaptions ~/Videos/talk.mp4 --lang en\ncaptions --list-presets\n# HF engine / other styles: point the wrapper at a different image\nCAPTIONS_IMAGE=ghcr.io/jurczykpawel/captions-cli:full captions reel.mp4 --engine hf\n```\n\nStill uses the Docker image under the hood (so Docker must be running) — but nothing else to\ninstall. Want a **native** binary with no Docker at all? That's also a real `captions` command —\nsee [Install](#install) (Options B, C, E).\n\n## Style packs (ASS engine)\n\nThe ASS engine ships **25 caption presets organized into three packs**. Free pack is\nincluded in the public Docker image. Basic and Premium are paid one-time downloads\nshipped as separate Docker tags.\n\n| Pack | Count | Price | Includes |\n|---|---|---|---|\n| **Free** | 1 | included | `clean-white` — bold white + heavy black outline. Always readable. |\n| **Basic** | 4 | **47 PLN** *(one-time)* | Free + `outline-pop`, `hormozi`, `pill`, `pop-word` |\n| **Premium** | 20 | **97 PLN** *(one-time)* | Basic + 20 premium styles (color variants, single-word, news-ticker, mrbeast, neon-*, karaoke-*, cinema-classic, …) |\n\nPreview grids:\n\n| Free | Basic | Premium |\n|---|---|---|\n| ![free](assets/previews/grids/free.png) | ![basic](assets/previews/grids/basic.png) | ![premium](assets/previews/grids/premium.png) |\n\nRun `captions --list-presets` to see the full grouped catalog. See [`PACKS.md`](PACKS.md)\nfor the design rationale behind the split (which look serves which use case).\n\n## Two render engines\n\nThe CLI dispatches to one of two engines via `--engine`:\n\n| Engine | What it uses | Image | Render speed (41 s clip) | Style pack support |\n|---|---|---|---|---|\n| **`ass`** *(default)* | `ffmpeg` + `libass` (no browser) | **~870 MB** | **~3 s** | Free / Basic / Premium pack split (this is where the catalog lives) |\n| **`hf`** | Hyperframes (HTML+CSS+GSAP via headless Chromium) | ~1.6 GB | ~40 s | 9 universal presets — full CSS power for exact fidelity (filter blur, 3-D transforms) |\n\nBoth engines produce valid karaoke captions with the same word-level timing. Pick `hf`\nwhen you need CSS-perfect effects that libass simplifies (multi-layer glow, easing curves).\n\n```bash\ncaptions reel.mp4                              # ASS, free pack default\ncaptions reel.mp4 --engine hf                  # opt in for full CSS power\ncaptions reel.mp4 --engine hf --preset glow    # HF-only CSS glow\n```\n\n## Why this exists\n\nSubmagic is 19-69 USD/month. CapCut Pro is 89 PLN/month. Veed.io is 25 EUR/month. Descript\nCreator is 24 USD/month. They all run [Whisper](https://github.com/openai/whisper) (open-source\nsince 2022) plus [ffmpeg](https://ffmpeg.org) (open-source since 2000). Your laptop has both.\n\nA 60-second reel transcribes in ~3 s on an M-series Mac and burns captions in another ~3 s with\nthe ASS engine. End-to-end: under 10 seconds, free, offline.\n\nThis CLI is the open-source companion to a TechSkills Academy guide on captioning video locally.\nFree, MIT-licensed, no watermark.\n\n## Install\n\nPick one. Listed easiest → most flexible.\n\n### Option A — Docker (zero local deps)\n\nTwo image variants. **Pre-built images are published to GHCR with each\n[release](https://github.com/jurczykpawel/captions-cli/releases)** (tags `:slim` / `:full`,\nplus the version, e.g. `:1.0.0-slim`):\n\n```bash\n# SLIM: ass engine only. ~870 MB. Recommended for most use cases.\ndocker pull ghcr.io/jurczykpawel/captions-cli:slim\ndocker run --rm \\\n  -v \"$PWD:/work\" \\\n  -v \"captions-cache:/data\" \\\n  ghcr.io/jurczykpawel/captions-cli:slim \\\n  /work/reel.mp4 --lang pl\n\n# FULL: ass + hf. ~1.6 GB. Use when you need --engine hf. (linux/amd64 only;\n# on Apple Silicon it runs under emulation — for arm64-native use :slim.)\ndocker pull ghcr.io/jurczykpawel/captions-cli:full\ndocker run --rm -v \"$PWD:/work\" -v \"captions-cache:/data\" \\\n  ghcr.io/jurczykpawel/captions-cli:full \\\n  /work/reel.mp4 --engine hf --preset glow\n```\n\nThe named volume `captions-cache` persists the Whisper model (~140 MB) — the first run\ndownloads it, subsequent runs are offline.\n\nOr build the image yourself (always works, no release needed):\n\n```bash\ngit clone https://github.com/jurczykpawel/captions-cli\ncd captions-cli\ndocker build -f Dockerfile.slim -t captions-cli:slim .   # ass engine, free pack\n# docker build -f Dockerfile.full -t captions-cli:full .  # + hf engine\ndocker run --rm -v \"$PWD:/work\" -v \"captions-cache:/data\" captions-cli:slim /work/reel.mp4 --lang pl\n```\n\n\u003e The public image ships the **free** `clean-white` preset. Paid packs are built into private\n\u003e images — see [Building images with paid packs](#building-images-with-paid-packs).\n\n### Option B — one-liner installer (Mac + Linux)\n\n```bash\n# ASS engine only (default)\ncurl -fsSL https://raw.githubusercontent.com/jurczykpawel/captions-cli/main/install.sh | bash\n\n# also install the HF engine (hyperframes)\ncurl -fsSL https://raw.githubusercontent.com/jurczykpawel/captions-cli/main/install.sh | bash -s -- --with-hf\n```\n\nInstalls `ffmpeg`, `whisper-cpp` and `bun`, then **builds** the `captions` binary from source\nand drops it into `/usr/local/bin`. Idempotent — safe to re-run. The installer checks whether\nyour `ffmpeg` has libass and warns if not (the ASS engine needs it — see Troubleshooting).\n\n### Option C — pre-built binary (no Node, no Bun)\n\nGrab the binary for your OS from [Releases](https://github.com/jurczykpawel/captions-cli/releases)\n(available from v1.0.0 on), then install the system tools manually:\n\n```bash\nbrew install ffmpeg whisper-cpp           # Mac. Note: brew's stock ffmpeg\n                                          # may lack libass — see Troubleshooting.\nsudo apt install ffmpeg                   # Linux (whisper.cpp from source)\nchmod +x /usr/local/bin/captions\n```\n\nFor HF engine: also `npm install -g hyperframes` (needs Node 22+ once).\n\nThe binary is ~60 MB (Bun runtime is baked in). No Node/Bun required to **run** it.\n\n### Option D — VPS via Stackpilot (`./local/deploy.sh captions-cli`)\n\nIf you already use [Stackpilot](https://github.com/jurczykpawel/stackpilot) to manage a VPS,\ncaptions-cli ships as a built-in app:\n\n```bash\n./local/deploy.sh captions-cli                # installs slim image (~870 MB)\nVARIANT=full ./local/deploy.sh captions-cli   # if you need --engine hf\n```\n\nThe installer pulls the Docker image and drops a `/usr/local/bin/captions` wrapper that mounts\n`$PWD` as `/work`. Then you SSH in and use the CLI like a native binary:\n\n```bash\nssh user@vps\ncd ~/captions\ncaptions reel.mp4 --preset hormozi --lang pl\n```\n\nSame UX as local Docker (Option A), zero hosting setup. Works on a 1 GB Mikrus with `slim`.\n\n### Option E — from source (developers)\n\n```bash\nbrew install ffmpeg whisper-cpp bun       # Mac\ngit clone https://github.com/jurczykpawel/captions-cli\ncd captions-cli\nbun install                               # workspaces install\nbun run captions video.mp4\n```\n\nBuild your own standalone binary:\n\n```bash\nbun run build                             # → ./dist/captions\n```\n\n## Project layout\n\nThis is a **Bun workspaces monorepo**. Each engine is its own package; the CLI dispatches\nbetween them by `--engine` flag.\n\n```\ncaptions-cli/\n├── package.json                 # workspaces: [\"packages/*\"]\n├── packages/\n│   ├── core/                    # shared: types, ffprobe, transcribe, cue grouping\n│   ├── engine-hf/               # Hyperframes (CSS+GSAP) + presets/\n│   │   └── src/presets/         # only `text.ts` ships in git; basic + premium\n│   │                            # are gitignored, repopulated at build time\n│   ├── engine-ass/              # ffmpeg+libass + presets/\n│   │   └── src/presets/         # only `clean-white.ts` ships in git; basic +\n│   │                            # premium are gitignored, repopulated at build time\n│   └── cli/                     # bin entry, dispatcher\n├── packs/                       # GITIGNORED — paid pack source, per engine\n│   ├── ass/{basic,premium}/     # ffmpeg+libass preset packs\n│   └── hf/{basic,premium}/      # Hyperframes preset packs\n├── scripts/\n│   ├── install-pack.sh          # `./install-pack.sh \u003cfree|basic|premium\u003e`\n│   ├── generate-presets-index.mjs   # auto-generates presets/index.ts\n│   ├── demo-packs.sh            # renders every preset → ~/Downloads/caption-packs-demo/\n│   └── demo-final.sh            # legacy 9-preset demo\n├── assets/previews/             # 25 preview PNGs + 3 grids (committed)\n├── PACKS.md                     # design rationale for the 3-tier split\n├── Dockerfile.slim              # ASS-only (~870 MB)\n├── Dockerfile.full              # ASS + HF (~1.6 GB)\n├── install.sh                   # Mac + Linux installer\n└── README.md\n```\n\n### Building images with paid packs\n\nThe public repo ships only the free `clean-white` preset. Owners of the basic/premium packs\ndrop the `.ts` files into `packs/` and bake them into a private image:\n\n```bash\n./scripts/install-pack.sh premium       # copies packs/* into presets/, regenerates index.ts\ndocker build -f Dockerfile.slim -t captions-cli:slim-premium .\n./scripts/install-pack.sh free          # restore git-clean state (free pack only)\n```\n\n## Preset designer (offline)\n\n`studio/index.html` is a self-contained HTML+JS app. Open it in any modern\nbrowser via `file://` — no server, no backend. Tweak typography / outline /\nanimation / position with live CSS preview, then click **Download .ts** to\nget a ready-to-drop preset file. Move it into `packs/\u003cengine\u003e/premium/` (e.g.\n`packs/ass/premium/`), run `./scripts/install-pack.sh premium`, and the CLI sees your custom slug.\n\n```bash\nopen studio/index.html      # macOS\nxdg-open studio/index.html  # Linux\n```\n\nThe preview is a CSS approximation — the real ffmpeg+libass render may\ndiffer slightly for blur and outline rendering, but typography, colour,\nand active-state effects are pixel-accurate.\n\n## Usage\n\n```bash\ncaptions \u003cvideo.mp4\u003e [options]\ncaptions --list-presets [--engine hf|ass]\ncaptions --list-engines\ncaptions --help\n```\n\nCommon recipes:\n\n```bash\n# Default look (clean-white, free pack, English, ASS engine)\ncaptions reel.mp4\n\n# Polish, Hormozi-style, custom highlight colour (basic pack)\ncaptions reel.mp4 --preset hormozi --lang pl --color \"#F59E0B\"\n\n# Submagic-style: one word at a time (premium pack)\ncaptions reel.mp4 --preset single-word\n\n# 3-state karaoke (past white / active amber / upcoming grey)\ncaptions reel.mp4 --preset outline-pop --upcoming \"#8E8E9C\"\n\n# Switch to HF engine for CSS-perfect glow\ncaptions reel.mp4 --engine hf --preset glow\n\n# Custom output path\ncaptions reel.mp4 --output viral.mp4\n\n# Use OpenAI Whisper API instead of local whisper-cpp\nexport OPENAI_API_KEY=sk-…\ncaptions reel.mp4 --whisper openai\n```\n\n## Preset catalog (ASS engine)\n\nRun `captions --list-presets` for the live grouped list. Each preset has a 6-second\npreview rendered at `assets/previews/\u003ctier\u003e/\u003cslug\u003e.png` — see [`PACKS.md`](PACKS.md) for\nthe rationale behind the split.\n\n### Free pack (included)\n\n| Slug | Look |\n|---|---|\n| `clean-white` | **Default.** Bold white + 8 px black outline. Multi-word. No animation, no color highlight. Reads on any background. |\n\n### Basic pack — 47 PLN\n\n| Slug | Look |\n|---|---|\n| `outline-pop` | UPPERCASE + 10 px outline + active word in accent color. Submagic-style. |\n| `hormozi` | White Bold + active word in accent + scale 1.15. Business benchmark. |\n| `pill` | Solid colored pill bg behind active word. |\n| `pop-word` | White Bold + subtle scale bounce on active. Reads on any background. |\n\n### Premium pack — 97 PLN\n\n20 styles across all categories (single-word focus, color variants, decorative\nbackgrounds, motion, cinematic). Includes basic + free.\n\n- **Single-word focus** — `single-word`, `single-word-pop`, `single-word-fade`\n- **Color variants** — `hormozi-red`, `hormozi-green`, `hormozi-cyan`, `neon-yellow`, `neon-cyan`, `neon-pink`\n- **Backgrounds** — `box-highlight`, `pill-shadow`, `news-ticker`\n- **Motion** — `bouncing`, `underline-sweep`\n- **High-energy** — `mrbeast`\n- **Karaoke** — `karaoke-fill`, `karaoke-shadow`\n- **Cinematic** — `subtitle-classic`, `whisper-mini`, `mono-block`\n\n### HF engine presets\n\nThe HF engine ships **9 universal presets** independent of the pack split (`outline-pop`,\n`hormozi`, `pop-word`, `pill`, `glow`, `underline-sweep`, `box-highlight`, `single-word`,\n`text`). Pick HF when you need CSS-only effects like multi-layer glow.\n\n## All options\n\n```\n--engine \u003cname\u003e          ass (default) | hf\n--preset \u003cslug\u003e          ASS engine: 25 presets in 3 packs (see --list-presets). Default: clean-white\n                         HF engine: 9 universal presets. Default: outline-pop\n--output \u003cpath\u003e          Default: \u003cinput\u003e-captioned.mp4\n--lang \u003ccode\u003e            Whisper language (en, pl, de, fr, …). Default: en\n--color \u003chex\u003e            Active word colour. Default: #F59E0B (amber)\n--upcoming \u003chex\u003e         Not-yet-spoken word colour (3-state karaoke)\n--position \u003c0-100\u003e       Vertical % from top (65 = cross-platform safe zone). Default: 65\n--font-size \u003cpx\u003e         Default: 64\n--font-color \u003chex\u003e       Past-word colour. Default: #FFFFFF\n--whisper \u003cprovider\u003e     whisper-cpp (default, free, local) | openai\n--whisper-model \u003cid\u003e     ggml-tiny|base|small|medium|large-v3-turbo.bin\n                         Default: ggml-base.bin (~140 MB, balanced)\n```\n\n## How it works\n\n```\ninput.mp4\n  └─ ffprobe → duration + dimensions\n       └─ ffmpeg → 16 kHz mono WAV (audio extract)\n            └─ whisper-cpp / OpenAI → word-level timestamps\n                 └─ groupWordsIntoCues → cues (≤5 words / ≤3 s each)\n                      ├─ engine=ass → libass → ffmpeg subtitles filter → MP4\n                      └─ engine=hf  → hyperframes → headless Chromium → MP4\n```\n\nThree colour states per word are tracked by:\n- **ASS**: inline tag transitions `\\t(t1,t1+1,\\c\u003ccolor\u003e)` flipping colour at word boundaries\n- **HF**: GSAP timeline applies `.word--past` / `.word--active` / `.word--upcoming` classes per\n  frame, CSS rules from the preset block style them\n\nBoth engines respect the same 3 colours: past = `--font-color`, active = `--color`,\nupcoming = `--upcoming` (defaults to past when omitted).\n\n## Whisper providers\n\n**`whisper-cpp` (default)** — runs locally, free, offline. Requires `whisper-cli` on PATH\n(`brew install whisper-cpp`). Models live in `~/.cache/whisper.cpp/`.\n\n**`openai`** — OpenAI's hosted Whisper API. Requires `OPENAI_API_KEY`. Costs ~$0.006 per audio\nminute. Faster than whisper-cpp on slower CPUs and on languages where small whisper-cpp models\nhallucinate.\n\n## Whisper model cheat-sheet\n\n| Model | Size | Speed | Quality | When to use |\n|---|---|---|---|---|\n| `ggml-tiny.bin` | 39 MB | fastest | low | Quick drafts, English-only |\n| `ggml-base.bin` | 140 MB | fast | OK | **Default** — good balance |\n| `ggml-small.bin` | 466 MB | medium | good | Multilingual, mid-quality |\n| `ggml-medium.bin` | 1.4 GB | slow | great | Long-form, proper nouns |\n| `ggml-large-v3-turbo.bin` | 1.5 GB | medium | best | Production captions |\n\nOverride with `--whisper-model ggml-small.bin` etc.\n\n## Three-state karaoke\n\nEach word goes through three states as the timeline plays:\n\n- **Past** (already spoken) → `--font-color` (default white)\n- **Active** (being spoken now) → `--color` (default amber `#F59E0B`)\n- **Upcoming** (not yet spoken) → `--upcoming` (default = past, so 2-state)\n\nPass `--upcoming \"#8E8E9C\"` for the full Submagic-style 3-state read where unspoken words are\ndimmed grey and \"fill in\" as they're hit.\n\n## Troubleshooting\n\n| Error | Fix |\n|---|---|\n| `whisper-cli: command not found` | `brew install whisper-cpp` |\n| `ffmpeg: command not found` | `brew install ffmpeg` |\n| `ffmpeg was built without libass` (or `No such filter: 'subtitles'`) | Your ffmpeg lacks libass. Easiest: use the Docker image (ships it). Or `brew reinstall ffmpeg` (macOS) / rebuild with `--enable-libass`. Verify: `ffmpeg -filters \\| grep subtitles`. Or switch engines: `--engine hf`. |\n| `hyperframes: command not found` *(only with `--engine hf`)* | `npm i -g hyperframes` (or `bun add -g hyperframes`). Slim image doesn't ship HF — use `:full`. |\n| `Unknown engine \"hf\"` from slim image | Slim is ASS-only. Use `:full` Docker image or install HF deps locally. |\n| Wrong language detected | Pass `--lang pl` (or whatever) explicitly |\n| Captions misaligned | Try `--whisper-model ggml-large-v3-turbo.bin` |\n| `OpenAI Whisper failed: 401` | `export OPENAI_API_KEY=sk-…` |\n| Render takes minutes on first HF run | Hyperframes downloads Chromium (~150 MB). Subsequent fast. |\n| Polish diacritics garbled | Default `ggml-base.bin` handles Polish; if still wrong, try `ggml-large-v3-turbo.bin` |\n\n## License\n\nMIT. Built on top of:\n\n- [ffmpeg](https://ffmpeg.org) + [libass](https://github.com/libass/libass) — LGPL/GPL/ISC\n- [Hyperframes](https://hyperframes.heygen.com) — Apache-2.0 (only `--engine hf`)\n- [whisper.cpp](https://github.com/ggerganov/whisper.cpp) — MIT\n- [Bun](https://bun.com) — MIT (only at build time when compiling the standalone binary)\n\n## See also\n\n- **TechSkills Academy guide** (Polish) — on captioning video locally; this CLI is its\n  open-source companion.\n- **ReelStack** — the larger reel-generation pipeline (TTS + LLM director) these caption\n  presets were originally extracted from; captions-cli is the minimal standalone carve-out.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjurczykpawel%2Fcaptions-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjurczykpawel%2Fcaptions-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjurczykpawel%2Fcaptions-cli/lists"}