Build a Free AI Reels Editor

Turn a Claude Code video editor into a standalone Gemini and LiteLLM pipeline.

Introduction

30 Second Summary

A short talking-head recording can hide minutes of retakes, pauses, and repeated lines. Cutting those moments by hand turns one Reel into a slow editing session.

In this project, you will adapt Maximus Soares's open-source video editor into a standalone Windows pipeline. Gemini 3.8 Flash makes the editorial decisions through LiteLLM, while the original local Python and Remotion code handles transcription, frame-accurate cuts, captions, and the final render.

What You'll Build

You'll drop raw footage into a folder on your G: drive and play a vertical Reel with retakes removed, word captions timed to the audio, and the repository's original motion templates rendered on top.

By the end of this project, you'll have:

  • A standalone editor on your G: drive that runs without Claude Code and keeps its source, models, renders, and working files in one named workspace.
  • A Gemini cut planner that uses LiteLLM and a strict JSON Schema to turn transcript evidence into the repository's native spans.json file.
  • A finished vertical Reel rendered by the original FFmpeg cut engine, caption presets, Remotion components, and Card edit style.
  • Secret Mission: Add a confidence gate that separates questionable Gemini removals for human review before rendering.

Are there any prerequisites?

You need Windows with a writable G: drive, Python 3.10 to 3.14, Git, FFmpeg 4.4 or newer, and Node.js 20 or newer. The first setup downloads roughly 1.5 GB of models and renderer packages.

You also need a Google AI Studio key and one short talking-head video. Personal local rendering and Gemini's free tier keep this path at no cost, while free-tier prompts may be used to improve Google's products.

Before We Start

Before We Start...

Before you touch the source code, lock in what you are adapting and why. You are turning an agent-driven editor into a standalone pipeline while keeping its original cutting and rendering engine intact.

Create the Gemini Key and Verify the Workspace

Extract the Original Editor on Your G: Drive

The original editor is a complete engine, so rebuilding its cut and render logic would throw away tested work. This step copies that engine intact and gives it a predictable home on your G: drive.

You will use the repository's own setup doctor to prepare Python, FFmpeg, Node.js, local transcription, and Remotion. A separate virtual environment holds LiteLLM so the repository's pinned engine packages stay unchanged.

In this step, get ready to:
  • Verify the required Windows tools.
  • Copy the exact repository engine and legal notices to G:\AIReelsEditor.
  • Bootstrap the engine and secure the Gemini key.
Verify the local tools

The repository requires Python 3.10 through 3.14 for this adaptation, FFmpeg 4.4 or newer, Node.js 20 or newer, and Git. LiteLLM 1.105.1 does not support Python 3.15.

  • Open PowerShell through Windows Search.
  • Check all four tool versions by running:
python --version
ffmpeg -version
node --version
git --version

What do these checks prove?

  • python --version must report Python 3.10 through 3.14.
  • ffmpeg -version must report FFmpeg 4.4 or newer.
  • node --version must report Node.js 20 or newer.
  • git --version confirms that PowerShell can download the repository.

Before you continue, do you expect the repository's doctor to accept all four tools?

One of the commands is unavailable?

Install or upgrade only the tool named by the failed command. Open a fresh PowerShell window after an installer changes your Windows PATH.

Help me fix the failed prerequisite check.

Copy the original engine

The supplied repository address currently redirects to its maintained repository slug. Keep the command below unchanged so your project records the exact source requested for this build.

  • Create the workspace and clone the exact repository by running:
New-Item -Path 'G:\AIReelsEditor' -ItemType Directory -Force

git clone

https://github.com/nextwork-projects/ai-video-editor.git 'G:\AIReelsEditor\source'

What does this create?

The first command creates the named workspace. The second command downloads the repository into source without searching for or combining code from another project.

  • Confirm the repository contains the editor by running:
Get-ChildItem 'G:\AIReelsEditor\source\plugins\ai-editor'

You should see folders including lib, presets, remotion, requirements, and skills.

  • Copy the complete editor tree and its legal notices by running:
Copy-Item -Path 'G:\AIReelsEditor\source\plugins\ai-editor' -Destination 'G:\AIReelsEditor\engine' -Recurse -Force

Copy-Item -Path 'G:\AIReelsEditor\source\LICENSE','G:\AIReelsEditor\source\NOTICE','G:\AIReelsEditor\source\THIRD_PARTY_NOTICES.md' -Destination 'G:\AIReelsEditor' -Force

What was copied?

The engine folder now preserves the original cut scripts, style scripts, render scripts, templates, caption presets, sample assets, and shared library. The copied notices retain NextWork's MIT copyright and the third-party attributions.

The repository history identifies Maximus Soares as its contributor. This adaptation adds a standalone controller beside his engine instead of rewriting the engine files.

  • Verify the engine and notices by running:
Test-Path 'G:\AIReelsEditor\engine\skills\cut\scripts\render.py'
Test-Path 'G:\AIReelsEditor\engine\remotion\render.mjs'
Test-Path 'G:\AIReelsEditor\THIRD_PARTY_NOTICES.md'

You should see True three times. That result proves the cut renderer, Remotion renderer, and attribution file all reached the standalone workspace.

Repository copy incomplete?

Remove an incomplete source folder before repeating the clone. If the copy is incomplete, repeat only the two Copy-Item commands.

Help me diagnose the repository copy.

Bootstrap the standalone setup

The original setup script installs its Python environment, local Whisper model, and Remotion packages under AI_EDITOR_HOME. Pointing that location at your workspace keeps the generated tools on the G: drive.

  • Set the tool home for this PowerShell session by running:
$Env:AI_EDITOR_HOME = 'G:\AIReelsEditor\.ai-video-editor'
  • Inspect the current machine with the repository's doctor by running:
python 'G:\AIReelsEditor\engine\skills\setup\scripts\setup.py' doctor

The doctor prints ok beside ready tools and FIX beside anything missing. Apply only the exact fix printed for your machine before continuing.

  • Bootstrap the original engine by running:
python 'G:\AIReelsEditor\engine\skills\setup\scripts\setup.py' bootstrap

The first bootstrap downloads roughly 1.5 GB and can sit quietly for several minutes while it installs packages, a local transcription model, and the render browser. A quiet terminal during that download does not mean the setup has stopped.

  • Create the standalone planner environment by running:
python -m venv 'G:\AIReelsEditor\.venv'

& 'G:\AIReelsEditor\.venv\Scripts\python.exe' -m pip install litellm==1.105.1

Why use two environments?

The repository environment remains pinned under .ai-video-editor\venv. The separate .venv contains LiteLLM for the new standalone controller, so provider dependencies cannot move the original engine's packages.

Creating an API key is the sensitive part of this setup. Save it as a Windows user variable so it never appears in a project file or screenshot.

  • Open the Google AI Studio API Keys page.
  • Create or select a key for the project you want to use.
  • Copy the key without placing it in a note or source file.
  • Open Environment Variables through Windows Search.
  • Click New... under your user variables.
  • Enter GEMINI_API_KEY as the variable name.
  • Paste the key as the variable value.
  • Click OK to save it.
  • Open a fresh PowerShell window through Windows Search.
  • Restore the tool-home setting by running:
$Env:AI_EDITOR_HOME = 'G:\AIReelsEditor\.ai-video-editor'
  • Run the final engine check by running:
python 'G:\AIReelsEditor\engine\skills\setup\scripts\setup.py' doctor

You should see Ready. at the end and a Gemini key row that says the key was found. The key value itself stays hidden.

Doctor cannot find the key?

Confirm that the key was saved under user variables and that you opened PowerShell after saving it. Do not paste the key into chat while troubleshooting.

Help me diagnose the missing Gemini key.

That's the foundation in place: the original editor now lives on your G: drive with its renderer, templates, models, notices, and a separate LiteLLM environment.

Next, you will feed the copied engine real footage and inspect the transcript evidence it produces before Gemini makes a single editing decision.

Render the First-Take Baseline

Prepare and Transcribe Your Reel

The original engine is installed with its local models and renderer. Now it needs one stable source video and the transcript evidence that drives every later cut.

The repository treats transcription as the timing authority. Gemini will decide what to remove later, but only the local word timestamps can place those cuts on exact frames.

In this step, get ready to:
  • Add one recording or a set of ordered takes.
  • Create one normalized source video with the original join script.
  • Generate the transcript and cut candidates locally.
Add the raw recordings

The input folder holds untouched camera files. The edits\reel folder holds every generated artifact for this Reel.

  • Open PowerShell through Windows Search.
  • Create the two folders by running:
New-Item -Path 'G:\AIReelsEditor\input','G:\AIReelsEditor\edits\reel' -ItemType Directory -Force
  • Open File Explorer through Windows Search.
  • Open the folder containing your raw Reel recordings.
  • Copy one or more .mp4 or .mov files.
  • Open G:\AIReelsEditor\input.
  • Paste the recordings into the input folder.
  • Confirm the available recordings by running:
Get-ChildItem 'G:\AIReelsEditor\input' -File | Select-Object Name,Length

You should see every selected filename and a non-zero file size. Their alphabetical order becomes the multi-take playback order.

A recording is missing or empty?

Confirm that the recordings include audio and that Windows can play each original file. Remove unrelated clips from input before continuing.

Help me inspect the input recordings.

Create one source video

One recording can become the source without re-encoding. Several recordings need the repository's join.py script so their dimensions, frame rate, audio format, and start times agree.

One recording

  • Copy your only recording into the edit folder by running:
Copy-Item 'G:\AIReelsEditor\input\[[VIDEO_FILE="your-video.mp4"]]' 'G:\AIReelsEditor\edits\reel\source.mp4' -Force

Several recordings

  • Join every recording in alphabetical order with the original script by running:
$takes = Get-ChildItem 'G:\AIReelsEditor\input' -File | Sort-Object Name | ForEach-Object FullName

python 'G:\AIReelsEditor\engine\skills\cut\scripts\join.py' 'G:\AIReelsEditor\edits\reel\source.mp4' @takes

The script writes source.mp4.parts.json beside the joined source. That report records where each original recording begins.

  • Confirm the source duration by running:
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 'G:\AIReelsEditor\edits\reel\source.mp4'

You should see a duration greater than zero. Open source.mp4 in your video player and confirm that its picture and audio remain synchronized.

The source join stopped?

The join script stops when a part has mismatched audio and video timing. Check the named source file first because the script intentionally refuses to cut an unsafe join.

Help me diagnose the join failure.

Generate the transcript evidence

The copied faster-whisper model runs on your computer and writes a start and end time for every word. It also seeds the prompt with fillers so the transcript preserves more of the evidence an editor needs.

  • Point the engine at its workspace by running:
$Env:AI_EDITOR_HOME = 'G:\AIReelsEditor\.ai-video-editor'
  • Transcribe the source with the repository's local engine by running:
python 'G:\AIReelsEditor\engine\lib\ai_editor\run.py' 'G:\AIReelsEditor\engine\skills\cut\scripts\transcribe.py' 'G:\AIReelsEditor\edits\reel\source.mp4' 'G:\AIReelsEditor\edits\reel\words.raw.json' --engine whisper

A three-minute recording usually takes one to four minutes on the first pass, so a pause after the model name is expected. The final line reports the word count and the path to words.raw.json.

Why transcribe locally?

The engine extracts 16 kHz mono audio before transcription, so it does not repeatedly decode the full video. Each output word keeps source-relative seconds for the cut engine.

  • Turn the raw word data into readable evidence by running:
python 'G:\AIReelsEditor\engine\skills\cut\scripts\retakes.py' propose 'G:\AIReelsEditor\edits\reel'

What did the proposal find?

The script writes transcript.txt as phrase-level evidence and candidates.md as possible restarts, fillers, false starts, and alternate hooks. Candidates are places to inspect, not automatic removals.

Before you inspect the files, do you expect every candidate to become a cut?

  • Preview the evidence by running:
Get-Content 'G:\AIReelsEditor\edits\reel\transcript.txt' -TotalCount 12

Get-Content 'G:\AIReelsEditor\edits\reel\candidates.md' -TotalCount 12

You should see timestamped spoken phrases followed by candidate lines that quote the recording. That is the first visible proof that the copied engine understands your footage.

Transcript files were not created?

If transcription reports that the model is missing, rerun the original setup.py bootstrap command with the same AI_EDITOR_HOME value. If FFmpeg cannot read audio, test the named source file in your video player.

Help me diagnose the evidence-generation failure.

Your source is synchronized and every spoken phrase now has local timing evidence. Gemini has not touched the footage or made a cut yet.

Next, you will replace Claude Code's editorial role with a standalone LiteLLM request that writes the exact spans.json contract the original engine expects.

Transcribe Every Take Locally

Replace Claude Code with Gemini and LiteLLM

Your copied engine has turned the source into readable transcript evidence and a focused candidate list. The missing piece is the editorial decision that Claude Code made in the original workflow.

A standalone LiteLLM script can fill that role. It sends only text evidence to Gemini 3.8 Flash and requires a JSON Schema response that matches the repository's spans.json contract.

In this step, get ready to:
  • Build the standalone Gemini cut planner.
  • Generate quoted removal decisions through LiteLLM.
  • Validate the decisions with the original timeline builder.
Read the original evidence

The planner reads three repository artifacts. retake-detection.md supplies the editorial rules, transcript.txt supplies the exact words, and candidates.md narrows the places worth checking.

  • Open Visual Studio Code through Windows Search.
  • Open G:\AIReelsEditor with File, then Open Folder.
  • Create planner.py directly inside G:\AIReelsEditor.
  • Add the imports, paths, and evidence reader by pasting:
import json
from pathlib import Path
from typing import Literal

from litellm import completion
from pydantic import BaseModel, ConfigDict, Field

# Keep new orchestration beside the untouched engine.
ROOT = Path(__file__).resolve().parent
EDIT = ROOT / "edits" / "reel"
RULES = ROOT / "engine" / "skills" / "cut" / "references" / "retake-detection.md"
MODEL = "gemini/gemini-3.8-flash"


def read_context() -> str:
    # Gemini sees text evidence, never the raw video file.
    parts = [RULES.read_text(encoding="utf-8")]
    for name in ("transcript.txt", "candidates.md"):
        parts.append((EDIT / name).read_text(encoding="utf-8"))
    return "\n\n".join(parts)

What does this code prepare?

  • ROOT resolves the standalone workspace.
  • EDIT points to the repository-compatible edit folder.
  • MODEL uses LiteLLM's Google AI Studio provider prefix.
  • read_context() combines the original rules and generated evidence without opening source.mp4.
  • Save planner.py.
  • Check the first chunk's syntax in PowerShell by running:
& 'G:\AIReelsEditor\.venv\Scripts\python.exe' -m py_compile 'G:\AIReelsEditor\planner.py'; if ($?) { 'planner.py syntax is valid' }

You should see planner.py syntax is valid.

The syntax check failed?

Check that planner.py sits beside engine and edits. A missing import usually means the command used the engine environment instead of G:\AIReelsEditor\.venv.

Help me fix the planner setup.

Define the structured cut request

The response models allow only cut kinds understood by the original timeline builder. Optional disambiguators let Gemini identify a repeated phrase without inventing a timestamp.

  • Add the response models and request function below read_context() by pasting:
class Span(BaseModel):
    # Extra fields would break the engine contract.
    model_config = ConfigDict(extra="forbid")
    text: str = Field(min_length=1)
    kind: Literal[
        "alt_hook", "retake", "false_start", "filler",
        "meta", "audio_event", "redundant",
    ]
    note: str
    confidence: Literal["high", "medium", "low"]
    occurrence: int | None = Field(default=None, ge=1)
    after: float | None = Field(default=None, ge=0)


class CutPlan(BaseModel):
    model_config = ConfigDict(extra="forbid")
    spans: list[Span]


def request_plan() -> CutPlan:
    # LiteLLM maps this schema to Gemini structured output.
    response = completion(
        model=MODEL,
        reasoning_effort="low",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": read_context()},
        ],
        response_format={"type": "json_schema", "json_schema": {
            "name": "cut_plan", "schema": CutPlan.model_json_schema(), "strict": True,
        }},
    )
    return CutPlan.model_validate_json(response.choices[0].message.content)

What does the schema protect?

  • Span restricts each removal to the engine's supported kinds.
  • ConfigDict(extra="forbid") rejects unexpected model fields.
  • response_format sends the Pydantic schema as native Gemini structured output.
  • model_validate_json() refuses malformed content before a file is written.
  • Save planner.py.
  • Run the syntax check again:
& 'G:\AIReelsEditor\.venv\Scripts\python.exe' -m py_compile 'G:\AIReelsEditor\planner.py'; if ($?) { 'schema syntax is valid' }

You should see schema syntax is valid.

Write and validate the cut plan

The final chunk instructs Gemini to return removals rather than a rewritten script. It strips empty disambiguators before saving because the original resolver treats any present after field as a real number.

  • Add the system prompt and entry point at the bottom of planner.py by pasting:
SYSTEM_PROMPT = """You replace Claude Code's cut decision in this repository.
Follow the supplied retake-detection rules. Return removals only.
Every text value must be a verbatim transcript quote.
Use occurrence or after only when the same quote appears more than once.
Never invent timestamps. Keep a strong complete delivery over an earlier attempt."""


def main() -> None:
    # Remove null disambiguators before writing the native contract.
    plan = request_plan()
    spans = [span.model_dump(exclude_none=True) for span in plan.spans]
    output = EDIT / "spans.json"
    output.write_text(json.dumps(spans, indent=1), encoding="utf-8")
    print(f"Wrote {len(spans)} quoted removals to {output}")


if __name__ == "__main__":
    main()

What completes the planner?

  • SYSTEM_PROMPT preserves the original last-take and verbatim-quote rules.
  • exclude_none=True removes unused disambiguation fields.
  • spans.json lands beside the transcript files that justify it.
  • Save planner.py.

✔️ Awesome, I've got everything!

Your standalone planner is complete. Double-check that the file is saved before making the model request.

ⓧ I'd like to double check the full code

Compare your file with this complete reference.

import json
from pathlib import Path
from typing import Literal

from litellm import completion
from pydantic import BaseModel, ConfigDict, Field

# Keep new orchestration beside the untouched engine.
ROOT = Path(__file__).resolve().parent
EDIT = ROOT / "edits" / "reel"
RULES = ROOT / "engine" / "skills" / "cut" / "references" / "retake-detection.md"
MODEL = "gemini/gemini-3.8-flash"


def read_context() -> str:
    # Gemini sees text evidence, never the raw video file.
    parts = [RULES.read_text(encoding="utf-8")]
    for name in ("transcript.txt", "candidates.md"):
        parts.append((EDIT / name).read_text(encoding="utf-8"))
    return "\n\n".join(parts)


class Span(BaseModel):
    # Extra fields would break the engine contract.
    model_config = ConfigDict(extra="forbid")
    text: str = Field(min_length=1)
    kind: Literal[
        "alt_hook", "retake", "false_start", "filler",
        "meta", "audio_event", "redundant",
    ]
    note: str
    confidence: Literal["high", "medium", "low"]
    occurrence: int | None = Field(default=None, ge=1)
    after: float | None = Field(default=None, ge=0)


class CutPlan(BaseModel):
    model_config = ConfigDict(extra="forbid")
    spans: list[Span]


def request_plan() -> CutPlan:
    # LiteLLM maps this schema to Gemini structured output.
    response = completion(
        model=MODEL,
        reasoning_effort="low",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": read_context()},
        ],
        response_format={"type": "json_schema", "json_schema": {
            "name": "cut_plan", "schema": CutPlan.model_json_schema(), "strict": True,
        }},
    )
    return CutPlan.model_validate_json(response.choices[0].message.content)


SYSTEM_PROMPT = """You replace Claude Code's cut decision in this repository.
Follow the supplied retake-detection rules. Return removals only.
Every text value must be a verbatim transcript quote.
Use occurrence or after only when the same quote appears more than once.
Never invent timestamps. Keep a strong complete delivery over an earlier attempt."""


def main() -> None:
    # Remove null disambiguators before writing the native contract.
    plan = request_plan()
    spans = [span.model_dump(exclude_none=True) for span in plan.spans]
    output = EDIT / "spans.json"
    output.write_text(json.dumps(spans, indent=1), encoding="utf-8")
    print(f"Wrote {len(spans)} quoted removals to {output}")


if __name__ == "__main__":
    main()

Before you run the planner, do you expect Gemini to return kept sections or quoted removals?

  • Open PowerShell through Windows Search.
  • Generate spans.json by running:
& 'G:\AIReelsEditor\.venv\Scripts\python.exe' 'G:\AIReelsEditor\planner.py'

You should see the number of quoted removals followed by G:\AIReelsEditor\edits\reel\spans.json.

The model request failed?

A missing key means this PowerShell window started before GEMINI_API_KEY was saved. A schema error means the model response did not match the strict contract, so no unsafe cut file was accepted.

Help me diagnose the planner request.

  • Point the copied engine at its local home by running:
$Env:AI_EDITOR_HOME = 'G:\AIReelsEditor\.ai-video-editor'
  • Test every quote against the original timeline builder by running:
python 'G:\AIReelsEditor\engine\skills\cut\scripts\build_timeline.py' 'G:\AIReelsEditor\edits\reel\source.mp4' 'G:\AIReelsEditor\edits\reel' --dry-run

You should see a source duration, cut count, result duration, and one CUT line per resolved removal. The final line says (dry run, nothing written).

The dry run rejected a quote?

An unmatched quote is blocked before any timeline file is written. Open spans.json and replace the named text value with the exact wording from transcript.txt.

Help me fix the rejected quote.

The editorial handoff now works without Claude Code: LiteLLM writes a schema-checked removal plan, and the original engine accepts every quote against local evidence.

Next, you will turn those accepted removals into a frame-accurate cut.mp4 with the repository's untouched timeline and render scripts.

Compare Takes in One Gemini Request

Build and Verify the AI Rough Cut

Gemini's quoted removals now pass the original dry-run resolver. That means every decision can be tied back to words that actually exist in your local transcript.

The copied cut engine now takes over. It combines the model removals with measured pauses, moves risky joins away from speech, quantizes every boundary to a frame, and renders the surviving spans with FFmpeg.

In this step, get ready to:
  • Compile the accepted removals into kept frame ranges.
  • Render the synchronized rough cut with the original script.
  • Verify the video against its expected words and audit files.
Compile the frame-accurate timeline

The timeline builder treats transcript quotes as editorial intent and the source audio as mechanical evidence. This split lets Gemini decide what should go while deterministic code decides where a safe splice belongs.

  • Open PowerShell through Windows Search.
  • Restore the engine home by running:
$Env:AI_EDITOR_HOME = 'G:\AIReelsEditor\.ai-video-editor'

Before you compile the timeline, do you expect the final duration to be shorter than the source?

  • Build the real timeline by running:
python 'G:\AIReelsEditor\engine\skills\cut\scripts\build_timeline.py' 'G:\AIReelsEditor\edits\reel\source.mp4' 'G:\AIReelsEditor\edits\reel'

What does the builder write?

  • decisions.json stores the kept source ranges.
  • report.json records model cuts, pause cuts, frame ranges, and splice diagnostics.
  • words.json retimes the surviving words onto the future cut.
  • paper-edit.md and cut-check.html provide readable audit views.

You should see the source duration, number of model removals, merged cut count, and result duration. The output paths appear after the summary.

The timeline build stopped?

An ERROR writes no replacement timeline. Fix the named quote in spans.json or pass the reported --noise value only when the engine cannot separate speech from the room.

Help me diagnose the timeline build.

Render the surviving spans

The original renderer encodes each kept video span separately and reuses unchanged spans after a correction. It cuts audio in one pass, adds an 8 ms fade at each join, and checks the final frame count.

  • Render the cut with the repository's exact script by running:
python 'G:\AIReelsEditor\engine\skills\cut\scripts\render.py' 'G:\AIReelsEditor\edits\reel\source.mp4' 'G:\AIReelsEditor\edits\reel'

Rendering time depends on the source resolution and number of kept spans. A long run prints progress as segments finish, then reports the checked frame count and writes cut.mp4.

Why does the renderer re-encode?

Each kept span is re-encoded because stream-copying across cuts can land on the wrong keyframe. Audio is assembled once to avoid encoder padding at every join.

  • Confirm the finished file exists by running:
Get-Item 'G:\AIReelsEditor\edits\reel\cut.mp4' | Select-Object Name,Length,LastWriteTime

You should see cut.mp4 with a non-zero length and a current modification time. That's the hard part done: your standalone controller has produced a real cut through the original engine.

The render failed or frames do not match?

Run the same render command one more time if the hardware encoder fails. The script automatically falls back to libx264 and removes an invalid segment cache after a frame mismatch.

Help me diagnose the rough-cut render.

Verify and audit the rough cut

A file that plays is only the first check. The repository's verification pass transcribes the rendered result and compares it with the words the timeline intended to keep.

Before you run the verification, do you expect it to find removed words in the finished audio?

  • Verify the rendered words with the local transcription engine by running:
python 'G:\AIReelsEditor\engine\lib\ai_editor\run.py' 'G:\AIReelsEditor\engine\skills\cut\scripts\verify_cut.py' 'G:\AIReelsEditor\edits\reel' --engine whisper

You should see a clean result or a focused list of MISSING, SURVIVED, DOUBLED, or join warnings. A clean pass proves the rendered speech matches the kept-word plan.

  • Open G:\AIReelsEditor\edits\reel\cut-check.html in your browser.
  • Open G:\AIReelsEditor\edits\reel\cut.mp4 in your video player.
  • Watch every jump cut from beginning to end.
  • Confirm that struck transcript words are absent from the rendered audio.

Verification found a mismatch?

Narrow a removal or increase the timeline padding when a kept word is clipped. Add a new quoted span only when a real stumble survived, then rebuild and rerender.

Help me interpret the verification result.

Your Reel now has a verified rough cut, retimed words, and a complete audit trail. The original source file remains untouched.

Next, you will copy the repository's Card edit preset into this edit and use its original Remotion templates to render the finished vertical Reel.

Render and Audit the AI Rough Cut

Style and Render the Finished Reel

Your verified cut.mp4 now contains the spoken performance you want to keep. The last step turns that clean cut into a vertical Reel using the repository's own style preset and renderer.

The Card edit preset controls one-word captions, placement, entrances, exits, and animation pacing. The original Remotion components convert its plan.json into the final frames.

In this step, get ready to:
  • Copy the repository's Card edit style into your Reel.
  • Build and inspect the caption and title plan.
  • Render and verify the finished vertical video.
Copy the style and prepare captions

The style file is copied from the exact repository rather than recreated from memory. Your edit receives its own copy so later changes cannot modify the source preset.

  • Open PowerShell through Windows Search.
  • Restore the engine home by running:
$Env:AI_EDITOR_HOME = 'G:\AIReelsEditor\.ai-video-editor'
  • Copy the Card edit preset into the Reel by running:
Copy-Item 'G:\AIReelsEditor\engine\presets\styles\sample-card-edit\style.json' 'G:\AIReelsEditor\edits\reel\style.json' -Force
  • Build caption words from the verified cut by running:
python 'G:\AIReelsEditor\engine\skills\cut\scripts\retakes.py' captions 'G:\AIReelsEditor\edits\reel'

You should see captions.json and captions.txt beside cut.mp4. The text file gives you a readable spelling check before captions reach the screen.

  • Open Visual Studio Code through Windows Search.
  • Open G:\AIReelsEditor\edits\reel.
  • Create visuals.json inside the reel folder.
  • Add a title drawn by the repository's original template by pasting:
[
  {
    "kind": "title",
    "text": "[[REEL_TITLE="a short title from your opening line"]]",
    "hold_s": 3.8
  }
]

What does this visual add?

kind: title routes the beat to the original title component. hold_s keeps it visible long enough to read, while the title text comes from your own opening line.

  • Save visuals.json.
  • Confirm the three style inputs by running:
Get-Item 'G:\AIReelsEditor\edits\reel\style.json','G:\AIReelsEditor\edits\reel\captions.json','G:\AIReelsEditor\edits\reel\visuals.json' | Select-Object Name,Length

You should see all three files with non-zero lengths.

A style input is missing?

Run the Step 4 verification again if retakes.py captions reports that cut.transcript.json is missing. Check the JSON punctuation if visuals.json has no length.

Help me diagnose the style inputs.

Build and inspect the visual plan

The planner combines cut.mp4, caption timing, the copied style, and your title beat. It writes the exact dimensions, frames, captions, zooms, and template props the renderer consumes.

  • Measure the speaker's face with the original script by running:
python 'G:\AIReelsEditor\engine\lib\ai_editor\run.py' 'G:\AIReelsEditor\engine\skills\style-edit\scripts\face.py' 'G:\AIReelsEditor\edits\reel'
  • Build the vertical plan from the copied style by running:
python 'G:\AIReelsEditor\engine\skills\style-edit\scripts\plan.py' 'G:\AIReelsEditor\edits\reel\style.json' --aspect 9:16 --out 'G:\AIReelsEditor\edits\reel\plan.json'

What is inside plan.json?

  • captions.chunks times each displayed word.
  • texts carries the title beat.
  • cards carries any repository templates or copied assets.
  • durationInFrames sets the render's exact length.
  • Check the plan with the repository's validator by running:
python 'G:\AIReelsEditor\engine\skills\style-edit\scripts\check.py' plan 'G:\AIReelsEditor\edits\reel' --plan plan.json --style 'G:\AIReelsEditor\edits\reel\style.json'

Fix every FAIL before rendering. Warnings describe differences or review points that may still be acceptable for your footage.

The first stills run installs or warms the render browser and may take a few minutes. That delay is the original renderer preparing its local bundle, not a model request.

  • Render the review stills by running:
python 'G:\AIReelsEditor\engine\skills\style-edit\scripts\edit.py' stills 'G:\AIReelsEditor\edits\reel'

You should see a labelled sheet at G:\AIReelsEditor\edits\reel\stills\sheet.png and a timed stills video beside it.

  • Open stills\sheet.png.
  • Check that the title and captions remain inside the vertical safe area.
  • Check that the text does not cover the speaker's face.

The plan or stills look wrong?

Rerun face.py if the measured face box is missing. Rerun plan.py after changing the title or style because stills always reflect the saved plan.

Help me diagnose the visual plan.

Render and verify the finished Reel

The local target bundles the copied remotion\src templates with your plan and media. It renders H.264 video with synchronized audio, then writes the result beside the rough cut.

Before you render, do you expect the final video to keep the verified cut's spoken timing?

  • Render the finished Reel on your computer by running:
python 'G:\AIReelsEditor\engine\skills\style-edit\scripts\edit.py' render 'G:\AIReelsEditor\edits\reel'

Remotion prints rendered-frame progress while it works. The final line confirms G:\AIReelsEditor\edits\reel\render.mp4.

  • Check the finished render with the original quality script by running:
python 'G:\AIReelsEditor\engine\lib\ai_editor\run.py' 'G:\AIReelsEditor\engine\skills\style-edit\scripts\check.py' render 'G:\AIReelsEditor\edits\reel' --plan plan.json --style 'G:\AIReelsEditor\edits\reel\style.json'

A clean check confirms the expected size, frame count, caption timing, audio alignment, and visual bounds. Resolve any FAIL before the final review.

  • Open G:\AIReelsEditor\edits\reel\render.mp4 in your video player.
  • Watch the full Reel with sound.
  • Confirm that the title appears over the opening.
  • Confirm that each caption follows the spoken word.
  • Confirm that every jump cut keeps synchronized audio.

You made the complete handoff: Gemini supplied editorial intent through LiteLLM, while Maximus Soares's original cut scripts, presets, templates, and renderer produced the pixels.

The final render or check failed?

Run the local render once more if the render browser times out. If the check reports caption contrast, rebuild plan.json so the planner can add the appropriate text treatment before rendering again.

Help me diagnose the final render.

Secret mission

Add a Confidence Review Gate

Add a confidence gate that sends Gemini's medium- and low-confidence removal decisions to human review before a future render.

Clean Up Your Resources

Clean Up Your Resources

This project runs locally, so leaving the files on your G: drive creates no ongoing charge. Decide whether to keep the editor ready, close it for now, or remove the workspace and Gemini credential.

Resources you used:

  • The G:\AIReelsEditor workspace containing the copied engine, local environments, models, source footage, evidence, plans, and rendered videos.
  • The GEMINI_API_KEY Windows user environment variable.
  • The API key created or selected in Google AI Studio.

Keep everything running

No action is needed. Choose this if you want to process another Reel with the same local engine and Gemini project.

  • Keep G:\AIReelsEditor on your G: drive.
  • Keep GEMINI_API_KEY under your Windows user variables.
  • Keep the selected API key active in Google AI Studio.
  • Start each future PowerShell session by setting AI_EDITOR_HOME to G:\AIReelsEditor\.ai-video-editor.

Pause - I'll come back to this later

Close the local tools to free memory while keeping every file and credential ready for later. No background cloud resource continues running.

  • Close the video player.
  • Close Visual Studio Code.
  • Close the PowerShell window.
  • Keep G:\AIReelsEditor unchanged.
  • Keep the Gemini key active for your next session.

Delete - I don't want to use this again

Remove all project resources and start fresh. Deleting the workspace is permanent, so copy render.mp4 somewhere else before you begin if you want to keep it.

Confirm what will be deleted

This cleanup removes only the local editor workspace and the Gemini key used by it. Your original recordings remain safe when they are stored outside G:\AIReelsEditor.

  • Copy any finished videos or reports you want to keep to a folder outside G:\AIReelsEditor.
  • Close Visual Studio Code.
  • Close every video player using a file from the workspace.
  • Open a fresh PowerShell window through Windows Search.
  • Delete the complete local workspace by running:
Remove-Item 'G:\AIReelsEditor' -Recurse -Force
  • Confirm the folder was removed by running:
Test-Path 'G:\AIReelsEditor'

You should see False.

  • Open the Google AI Studio API Keys page.
  • Locate the key used for this project.
  • Click its deletion control.
  • Confirm the key deletion.
  • Open Environment Variables through Windows Search.
  • Select GEMINI_API_KEY under your user variables.
  • Click Delete.
  • Click OK to save the change.

The workspace, stored environment variable, and remote API key are now removed.

Nice Work!

Nice Work!

Excellent work! You adapted Maximus Soares's open-source editor into a standalone Gemini and LiteLLM pipeline, then rendered a captioned vertical Reel through its original cut and Remotion engines.

You've learned how to:

  • Extract and preserve an existing open-source engine with its MIT notices, local models, cut scripts, presets, assets, templates, and renderer intact.
  • Replace an agent dependency with a standalone Gemini planner that uses LiteLLM and strict structured output to write repository-compatible removal decisions.
  • Produce a verified vertical Reel with frame-accurate cuts, synchronized audio, timed captions, a title template, and the repository's Card edit style.
  • Secret Mission: Add a confidence gate that routes medium- and low-confidence Gemini removals to human review.

Ready to quiz yourself?