{"slug": "show-hn-a-video-editor-where-the-llm-never-watches-the-video", "title": "Show HN: A video editor where the LLM never watches the video", "summary": "A developer known as ranahaani released 'i-hate-editing', an open-source AI video editor skill for Claude Code, Cursor, and Codex that edits talking-head footage without the LLM ever watching the video, relying instead on audio transcription via whisper.cpp and local scripts. The tool automates take selection, silence removal, captioning, screen capture, and sound effects, and is installed via 'npx skills add ranahaani/i-hate-editing'.", "body_md": "Drop in raw talking-head takes. Get back something you can publish.\n\nI named it after a note to myself: never hand back work that still needs fixing by hand.\n\n*Same recording on both phones. Left is what came off the camera; right is\n  what came back.\n  [Instagram reel this\n  footage shipped as](https://www.instagram.com/reel/Db3VN1Boyej/).*\n\nThe skill picks the take, decides the repo and the docs page were worth capturing, where to zoom, which line gets the highlighter, what goes on each card, and where every sound lands. You say \"punchier.\" It owns the numbers.\n\n- Cuts from silence and word onsets, not from scrubbing the timeline\n- Re-transcribes a short window around every seam so repeated words and mid-clause cuts get caught before you see a preview\n- Writes captions that still read on a phone, with a proofread gate before they ship\n- Captures real pages as tall stills, then scrolls, zooms, and highlights the line you said (no mocked screenshots)\n- Places free-licensed SFX by intent and aligns peaks so a short window is actually audible\n- Hands back a package: master, platform crops, ranked thumbnails, post lines\n- Remembers corrections in `taste.md` so the tenth video is better than the first\n- Runs transcription on your machine with `whisper.cpp` . No cloud STT key.\n\nBuilt for talking-head reels and YouTube explainers.\n\n```\nnpx skills add ranahaani/i-hate-editing\n```\n\nThat registers the skill with your agent. You still need the local tools\n(`ffmpeg`, `whisper-cpp`, Playwright Chromium). Details in\n[`install.md`](/ranahaani/i-hate-editing/blob/main/install.md).\n\nWorks in Claude Code, Cursor, Codex, and anything else with a shell:\n\n```\nSet up https://github.com/ranahaani/i-hate-editing for me.\n\nRead install.md first: clone the repo to a stable path, symlink it into this\nagent's skills directory, install ffmpeg + whisper.cpp, create the Python venv\nwith playwright + pillow, and optionally run scripts/sfx_library.py install.\nThen read SKILL.md for daily usage. After install, don't start editing —\ntell me it's ready and wait for me to drop footage into a folder.\ngit clone https://github.com/ranahaani/i-hate-editing ~/Developer/i-hate-editing\nln -sfn ~/Developer/i-hate-editing ~/.claude/skills/i-hate-editing   # Claude Code\nln -sfn ~/Developer/i-hate-editing ~/.cursor/skills/i-hate-editing   # Cursor\n# ln -sfn ~/Developer/i-hate-editing ~/.codex/skills/i-hate-editing  # Codex\n\ncd ~/Developer/i-hate-editing\nuv venv .venv && uv pip install --python .venv playwright pillow\n.venv/bin/playwright install chromium\nbrew install ffmpeg whisper-cpp   # macOS; use your package manager on Linux\ncd /path/to/your/footage\nclaude   # or your agent of choice\n```\n\nedit these into a reel\n\nIt scans the machine, asks five questions, picks a Whisper model for your\nlanguage and hardware, and starts. More in [`install.md`](/ranahaani/i-hate-editing/blob/main/install.md).\n\nThe model does not watch the video. Audio is the clock. Scripts do the mechanical work; the agent only makes taste calls.\n\n```\n%%{init: {\n  \"theme\": \"base\",\n  \"themeVariables\": {\n    \"fontFamily\": \"ui-sans-serif, system-ui, sans-serif\",\n    \"fontSize\": \"14px\",\n    \"primaryTextColor\": \"#0f172a\",\n    \"lineColor\": \"#94a3b8\",\n    \"clusterBkg\": \"#ffffff00\",\n    \"clusterBorder\": \"#e2e8f0\",\n    \"edgeLabelBackground\": \"#ffffff\",\n    \"tertiaryColor\": \"#f8fafc\"\n  },\n  \"flowchart\": {\n    \"curve\": \"basis\",\n    \"padding\": 16,\n    \"nodeSpacing\": 32,\n    \"rankSpacing\": 40,\n    \"htmlLabels\": true\n  }\n}}%%\nflowchart TB\n  RAW([\"🎬 raw takes\"]):::src\n  PROF([\"🎛️ profile.yml\"]):::cfg\n\n  subgraph A[\"🎧 1 · LISTEN\"]\n    direction LR\n    SCAN([\"🔍 scan\"]):::listen\n    ASR([\"🗣️ whisper.cpp\"]):::listen\n    PACK([\"📄 pack\"]):::listen\n    SIL([\"🔇 silences\"]):::listen\n    TAKES[(\"takes.md\")]:::artBlue\n    GAPS[(\"gaps.json\")]:::artBlue\n    SCAN --> ASR --> PACK --> TAKES\n    SCAN --> SIL --> GAPS\n  end\n\n  subgraph B[\"✂️ 2 · CUT  ·  HARD GATE\"]\n    direction LR\n    EDL[(\"edl.json\")]:::artAmber\n    RND([\"🎞️ render\"]):::cut\n    VER{\"🛡️ verify<br/>seam re-ASR\"}:::gate\n    GRD([\"🎨 grade\"]):::cut\n    CUTV[(\"cut.mp4\")]:::artAmber\n    EDL --> RND --> CUTV --> VER\n    VER -- \"❌ fail\" --> EDL\n    VER -- \"✅ pass\" --> GRD\n  end\n\n  subgraph C[\"✨ 3 · ENRICH\"]\n    direction LR\n    CAP([\"💬 captions\"]):::enrich\n    PRF([\"🌐 proof\"]):::enrich\n    SFX([\"🔊 sfx + music\"]):::enrich\n    CMP([\"🧩 compose\"]):::enrich\n    MASTER[(\"master.mp4\")]:::artPink\n    CAP --> CMP\n    PRF --> CMP\n    SFX --> CMP\n    CMP --> MASTER\n  end\n\n  subgraph D[\"🚀 4 · SHIP\"]\n    direction LR\n    DEL([\"📦 deliver\"]):::ship\n    PKG[(\"studio/out\")]:::artGreen\n    REV([\"👀 review\"]):::ship\n    DEL --> PKG --> REV\n  end\n\n  RAW --> SCAN\n  PROF -.-> SCAN\n  PROF -.-> CAP\n  TAKES --> EDL\n  GAPS --> EDL\n  GRD --> CAP\n  GRD --> PRF\n  GRD --> SFX\n  MASTER --> DEL\n\n  classDef src fill:#0f172a,stroke:#facc15,stroke-width:3px,color:#fef08a\n  classDef cfg fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#92400e\n  classDef listen fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#1e3a8a\n  classDef cut fill:#ffedd5,stroke:#ea580c,stroke-width:2px,color:#9a3412\n  classDef enrich fill:#f3e8ff,stroke:#9333ea,stroke-width:2px,color:#581c87\n  classDef ship fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d\n  classDef gate fill:#fee2e2,stroke:#dc2626,stroke-width:3px,color:#7f1d1d\n  classDef artBlue fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1d4ed8\n  classDef artAmber fill:#fffbeb,stroke:#d97706,stroke-width:2px,color:#b45309\n  classDef artPink fill:#fdf4ff,stroke:#c026d3,stroke-width:2px,color:#86198f\n  classDef artGreen fill:#f0fdf4,stroke:#22c55e,stroke-width:2px,color:#15803d\n\n  style A fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e40af\n  style B fill:#fff7ed,stroke:#f97316,stroke-width:2px,color:#c2410c\n  style C fill:#faf5ff,stroke:#a855f7,stroke-width:2px,color:#7e22ce\n  style D fill:#f0fdf4,stroke:#22c55e,stroke-width:2px,color:#15803d\n\n  linkStyle 8 stroke:#dc2626,stroke-width:2.5px\n  linkStyle 9 stroke:#16a34a,stroke-width:2.5px\n```\n\n`verify` blocks the cut. `review` is when you look at the package. If you change\nthe cut after captions and sound are built, those timestamps are wrong. Start\nthat layer over.\n\n```\nfootage/\n├── take-01.mp4      your sources stay put\n└── studio/          everything the skill writes\n    ├── profile.yml\n    ├── taste.md\n    ├── transcripts/\n    ├── edl.json\n    ├── composition/\n    └── out/         what you publish from\n```\n\nTwo things matter. The rest is plumbing.\n\nJoins love to leave a word sitting there twice. Cuts land mid-clause and flip what you meant. A whole-file transcript papers over both. So after the cut renders, verify re-transcribes short windows on each seam. Repeats are mechanical. Broken clauses get flagged for a human call.\n\nAnd when you correct something, it sticks. \"Captions feel early\" goes into\n`taste.md` and shows up on the next job. You should not have to teach the same\nlesson twice.\n\nYou also should not be asked which font, which transition, or what decibel\nlevel. Say *punchier*, *slower*, *less music*. The studio owns the numbers.\n\nName a repo, an article, a number. The skill opens the real page in a vertical viewport, grabs one tall still, then scrolls, zooms, and draws a highlighter across the line you said.\n\nA screen recording locks scroll speed forever. A still plus motion in the composition can re-time with the cut and sit on the same timeline as your face, captions, and sound.\n\nTargets are text, not CSS selectors. If the line is not on the page, it says so instead of grabbing something nearby.\n\nEach rule exists because a render failed once and we paid for it.\n\n| File | Covers | \n|---|---|\n| [`HARD-RULES.md`](/ranahaani/i-hate-editing/blob/main/HARD-RULES.md) | Silent failures. Non-negotiable. | \n| [`rules/cutting.md`](/ranahaani/i-hate-editing/blob/main/rules/cutting.md) | Take selection, seams, what to remove | \n| [`rules/hooks.md`](/ranahaani/i-hate-editing/blob/main/rules/hooks.md) | Openings, headline, retention | \n| [`rules/captions.md`](/ranahaani/i-hate-editing/blob/main/rules/captions.md) | Timing, chunking, style | \n| [`rules/sound.md`](/ranahaani/i-hate-editing/blob/main/rules/sound.md) | Placement, levels, audibility | \n| [`rules/motion.md`](/ranahaani/i-hate-editing/blob/main/rules/motion.md) | Zooms, pacing, easing | \n| [`rules/framing.md`](/ranahaani/i-hate-editing/blob/main/rules/framing.md) | Crops, splits, composition | \n| [`rules/proof.md`](/ranahaani/i-hate-editing/blob/main/rules/proof.md) | Screenshots, B-roll, zoom, highlight | \n\nAgent instructions: [`SKILL.md`](/ranahaani/i-hate-editing/blob/main/SKILL.md). Threat model: [`SECURITY.md`](/ranahaani/i-hate-editing/blob/main/SECURITY.md).\n\n| Tool | Why | Required | \n|---|---|---|\n| `ffmpeg` /`ffprobe` | Media | Yes | \n| `whisper.cpp` | Local transcription | Yes | \n| `node` 22+ | HyperFrames | Yes | \n| `playwright` +`pillow` | Proof capture, thumbnails | For proof / deliver | \n| `yt-dlp` | Reference footage | Optional | \n\n- Talking-head short-form and explainers. Not travel montages or multi-cam.\n- You bring the music bed. The skill ducks it; it does not license tracks.\n- Proof capture needs Chromium. Skip it if face + captions is enough.\n- First Whisper download is roughly 0.5–3 GB, depending on language and hardware.\n\nBest PR is a rule: what failed, what it cost, what you will never do again. Add\nit under [`rules/`](/ranahaani/i-hate-editing/blob/main/rules) or in [` HARD-RULES.md`](/ranahaani/i-hate-editing/blob/main/HARD-RULES.md).\n\n```\nuv venv .venv && uv pip install --python .venv pytest\n.venv/bin/pytest -q\n```\n\nFootage stays on your machine. Scripts can still hit the network for proof\npages, Mixkit SFX, and a pinned HyperFrames package. See\n[`SECURITY.md`](/ranahaani/i-hate-editing/blob/main/SECURITY.md).\n\nCopyright on `yt-dlp` downloads and music beds is on you. Brand marks from\nSimple Icons / Lucide are for editorial use; check trademark rules before ads.\n\n`review.py` binds localhost by default. Only pass `--lan` on a network you\ntrust. No auth on that server.\n\nComposition and rendering by\n[HyperFrames](https://github.com/heygen-com/hyperframes) (version pinned in\n`scripts/compose.py`).\n\nMIT. Vulnerabilities: [`SECURITY.md`](/ranahaani/i-hate-editing/blob/main/SECURITY.md).", "url": "https://wpnews.pro/news/show-hn-a-video-editor-where-the-llm-never-watches-the-video", "canonical_source": "https://github.com/ranahaani/i-hate-editing", "published_at": "2026-09-07 12:06:45+00:00", "updated_at": "2026-09-07 12:27:25.147719+00:00", "lang": "en", "topics": ["ai-tools", "ai-agents", "developer-tools", "generative-ai"], "entities": ["ranahaani", "i-hate-editing", "Claude Code", "Cursor", "Codex", "whisper.cpp", "ffmpeg", "Playwright"], "alternates": {"html": "https://wpnews.pro/news/show-hn-a-video-editor-where-the-llm-never-watches-the-video", "markdown": "https://wpnews.pro/news/show-hn-a-video-editor-where-the-llm-never-watches-the-video.md", "text": "https://wpnews.pro/news/show-hn-a-video-editor-where-the-llm-never-watches-the-video.txt", "jsonld": "https://wpnews.pro/news/show-hn-a-video-editor-where-the-llm-never-watches-the-video.jsonld"}}