fortax-demo-shoot
by amit-voais
README.md
# Fortax Demo Shoot
Give it a product URL. Get back a narrated demo video in your own voice, with branded
intro and outro, on-screen callouts, zooms on every click, captions, and three shapes:
16:9 for YouTube, 1:1 for LinkedIn, 9:16 for Reels and Shorts.
It plans the walkthrough, drives the product in a real browser, records it, speaks every
step, and renders the result. Run it from the command line, or just ask your coding agent
— Claude Code, Codex, OpenCode or hiSAI — for "a demo video of my app".
## Demo
**English** — planned, recorded and narrated with no hands on the keyboard.
https://github.com/user-attachments/assets/f2575a30-87b2-4a34-91ba-6d1736192bf1
**हिंदी** — the same demo, narrated in Hindi.
https://github.com/user-attachments/assets/39644a8e-a057-4250-9f02-30267b64dd2d
Full-quality files in all three shapes, in both languages, are on the
[v0.1.0 release](https://github.com/amit-voais/fortax-demo-shoot/releases/tag/v0.1.0).
## How it works
```
brand reads the site (and repo, if given) -> name, tagline, colours, logo
plan an LLM writes the walkthrough -> steps, narration, callouts
voice every line is spoken first -> your cloned voice, or a preset voice
record a real browser performs each step -> waits while each line plays
compose the recording is edited -> zoom on each click, cursor, captions
film the brand wraps the recording -> intro, callouts, outro, 16:9 / 1:1 / 9:16
```
Every stage writes a file, so any stage can be re-run on its own. Voice lines that did
not change are reused.
Two things it refuses to do quietly:
- **A click that would land on the wrong element fails the step.** Before every click it
checks what is actually under the pointer (sticky headers, overlays, a different
control inside the same label) and stops rather than record a video that shows the
wrong thing.
- **A voice line that fails stops the run** with the engine's real error, instead of
producing a silent video. Without `--ref`, a failed line is first retried with
Hidrogen's preset voice, and the log says so (`! s03: used Hidrogen's preset voice
instead of omnivoice`). With `--ref`, your cloned voice is never silently swapped for a
different one: pass `--allow-fallback` to accept Hidrogen's voice for those lines, or
`--allow-silent` if captions-only is what you want.
## Install
```bash
git clone https://github.com/amit-voais/fortax-demo-shoot && cd fortax-demo-shoot
./install.sh
```
Needs Python 3.10+, `ffmpeg` and Node.js 18+. `install.sh` creates a virtual
environment, downloads Playwright's own Chromium (no Chrome install needed), links the
`demoshoot` command into `~/.local/bin`, and registers the skill and the MCP server with
every coding agent it finds on the machine. `./install.sh --dry-run` shows what it would
do without changing anything; `./install.sh --uninstall` removes the agent registrations,
the skill links and the `~/.local/bin/demoshoot` link (only if it still points into this
checkout). It leaves the repo's `.venv` in place; delete the folder to remove that too.
Voice cloning uses [OmniVoice](https://github.com/k2-fsa/OmniVoice) in its own Python
environment; point `OMNIVOICE_PYTHON` at that environment's `python`.
## Make a demo
```bash
demoshoot make --url https://your-product.com \
--brief "Show how a new customer builds a plan and sees the yearly price" \
--ref my-voice.wav -o out/
```
`my-voice.wav` is 5–15 seconds of you speaking clearly, one speaker, no music. Without
`--ref`, pick a preset voice: `--instruct "male, indian accent, middle-aged, moderate pitch"`.
`out/` then contains `demo-16x9.mp4`, `demo-1x1.mp4`, `demo-9x16.mp4`, `demo.srt`,
`poster.jpg`, `plan.json`, `brand.json`, and one editable video project per shape.
| Option | What it does |
|---|---|
| `--project DIR` | also read the product's source repo for its name, colours and logo |
| `--plan plan.json` | use a plan you wrote or edited instead of asking the LLM |
| `--aspects 16:9,9:16` | only render some shapes |
| `--no-film` | one plain `demo.mp4`, no branded scenes |
| `--llm ollama` | plan with a local model instead of the default |
**Hindi or Hinglish.** Write the plan in that language first, then record it:
```bash
demoshoot plan --url https://your-product.com --brief "…" --lang hi -o plan.json
demoshoot make --plan plan.json --ref my-voice.wav -o out-hi/
```
Captions render in Devanagari.
**Change a callout or the tagline after a run** by editing `out/plan.json` or
`out/brand.json`, then re-render the scenes without re-recording:
```bash
demoshoot film --screen out/work/screen.mp4 --brand out/brand.json \
--plan out/plan.json --work out/work -o out/
```
Your agent can do the same with the `film` tool, which only needs the `out/` folder.
## Use it from a coding agent
After `install.sh`, ask your agent for a demo video. It has these tools:
| Tool | Use it for |
|---|---|
| `make_demo` | the whole thing in one call: URL in, finished videos out |
| `brand` | see what the tool reads as the product's name, tagline and colours |
| `plan_demo` | get a walkthrough plan to review or edit before recording |
| `shoot_demo` | record and narrate a plan into one plain video |
| `film` | re-render the branded scenes of a `make_demo` result after editing it |
| `doctor` | check what works on this machine |
Recording takes a few minutes and drives a real browser against the URL. It only
navigates, clicks, scrolls, hovers, types into visible fields and presses keys.
## Choices
| Stage | Option | Needs |
|---|---|---|
| Plan | `--llm hidrogen` (default) | `HIDROGEN_API_KEY` |
| | `--llm ollama` | a local model (`OLLAMA_MODEL`, default `qwen2.5:14b`) |
| | `--llm openai` | any OpenAI-compatible server (`OPENAI_BASE_URL`) |
| | `--llm claude` / `codex` / `hisai` | that CLI, logged in (see Safety) |
| Voice | `--voice omnivoice --ref me.wav` (default) | local OmniVoice (`OMNIVOICE_PYTHON`) |
| | `--voice omnivoice --instruct "…"` | a preset voice, no sample needed |
| | `--voice omnivoice-server` | `OMNIVOICE_URL` (OmniVoice on a GPU box) |
| | `--voice hidrogen` | `HIDROGEN_API_KEY` |
| | `--voice none` | captions only |
Valid `--instruct` words: male, female, child, teenager, young adult, middle-aged,
elderly, low pitch, moderate pitch, high pitch, very low pitch, very high pitch, whisper,
and the accents american, australian, british, canadian, chinese, indian, japanese,
korean, portuguese, russian (written as `indian accent`).
## Safety
- Plans that contain delete / pay / cancel-style steps are refused before the browser
opens. `shoot`, `run` and `record` accept `--allow-destructive` for a plan you have
checked yourself; `make` never does.
- If a click leaves the product's own domain, the browser goes back.
- Passwords never go in a plan. Write `{{secret:LOGIN_PASS}}` in the step and set
`DEMOSHOOT_SECRET_LOGIN_PASS` in the environment; it is typed in, never logged. Only
type secrets into password fields: a secret typed into an ordinary text field is
visible in the video.
- Plans may only open `http://` and `https://` pages.
- The planner reads text from the product's pages. `--llm claude` runs Claude Code with
no tools and no MCP servers; `hisai` runs without plugins in an empty folder but can
still use its own tools; `codex` runs as configured. Prefer `hidrogen`, `openai` or
`ollama` for sites you do not control.
- `demoshoot serve` (the job API) refuses to listen beyond localhost unless
`DEMOSHOOT_TOKEN` is set, and does not accept secrets or the agent-CLI planners.
- Your voice sample stays on your machine when you use local OmniVoice.
## Licence
Apache-2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE). If you redistribute this or build
on it, keep the NOTICE file and credit **Fortax Demo Shoot by Amit Yadav (Fortax)**.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues