A locally-running, single-user AI filmmaking studio inspired by Google Flow. React frontend + Python (FastAPI) backend; image/video/audio generation runs on your GPU. See SPEC.md for the full design and docs/DECISIONS.md for implementation decisions.
Status: milestones M0 through M7 are done. New here? Start with Quick start and Your first film.
@mention characters,
locations and props.Install the tools in PowerShell:
winget install astral-sh.uv Gyan.FFmpeg OpenJS.NodeJS.LTS Git.Git
Then close and reopen the terminal (and VS Code, if you use its terminal) so it picks up the new
PATH. Check with uv --version; node --version; ffmpeg -version.
GPU driver (for real generation): an NVIDIA GPU with 16 GB+ VRAM and a driver new enough for CUDA 13,
meaning the header of nvidia-smi says CUDA Version: 13.0 or higher. Update it from nvidia.com or the
NVIDIA app if not. No NVIDIA GPU? Everything still runs and makes placeholder images and videos (the
FakeEngine).
Clone and install:
git clone https://github.com/lrama1/local-flow.git
cd local-flow
npm run setup
This runs uv sync in backend/ (uv fetches Python 3.12 and the packages, including the CUDA 13 build of
PyTorch from download.pytorch.org: about 4 GB) and npm install in frontend/ (about 250 MB). Without an
NVIDIA GPU, skip the GPU packages: cd backend; uv sync --no-group gpu; cd ..\frontend; npm install.
Check that PyTorch sees the GPU:
cd backend; uv run python -c "import torch; print(torch.__version__, torch.cuda.is_available())"; cd ..
Expect something like 2.14.1+cu130 True.
Choose where data goes (optional). Models need 20–80 GB, and everything lives in
%USERPROFILE%\LocalFlow unless you set another folder before the first start, e.g.
setx LOCALFLOW_DATA_DIR D:\LocalFlow.
Add an LLM key for the story tools, e.g. setx OPENAI_API_KEY "sk-..." (or ANTHROPIC_API_KEY,
OPENROUTER_API_KEY), or paste one later in Settings → API keys. See API keys.
Start:
npm start # builds the frontend, then serves everything on http://127.0.0.1:8765
Open http://127.0.0.1:8765. For development, npm run dev runs the backend on :8765 plus Vite with hot
reload on http://127.0.0.1:5173 (the backend restarts on .py changes).
Open Settings → Diagnostics. Every check should be green: data folder writable, disk space, ffmpeg, NVIDIA GPU, PyTorch + CUDA, GPU worker, secret storage (Windows Credential Manager) and LLM providers. Amber or red rows say what to fix.
Models → Catalog: install what you need. Shared parts (text encoders, VAEs) download once, so the total is less than the sum.
| Model | Used for | Download |
|---|---|---|
| FLUX.1 [dev] · GGUF Q4_K_S | ingredient images, keyframes from text | 16.7 GB |
| FLUX.1 Kontext [dev] · GGUF Q4_K_M | keyframes composed from references, character views | 16.9 GB |
| Wan 2.2 TI2V-5B · GGUF Q8_0 | video (5 s clips at 1280×704) | 19.6 GB |
| Kokoro-82M | dialogue | 0.4 GB |
| MMAudio large 44.1 kHz v2 | sound effects synced to the picture | 10.7 GB |
| MusicGen small | music | 2.4 GB |
FLUX.1 [dev] is gated: accept its license on Hugging Face and add an HF_TOKEN (Settings → API keys can
import an existing hf auth login). Kokoro and MMAudio need allow_pickle_weights = true in
config.toml (Audio). Acknowledge each model's license on its card before first use.
Projects → New project. On Story, write a few sentences, then Refine → Build bible →
Break down into shots. A 30-second story costs about $0.02–0.03 with gpt-5.4-mini.
Ingredients: generate images for the characters, locations and props and pick a primary for each, or use New character for the wizard with consistent extra views.
Shots board: open a shot, Compose keyframe, pick one, then Generate video. Or use Generate all for every shot. Check consistency compares a keyframe or take with the references.
Audio (shot panel): dialogue and sound effects. Music is generated from the timeline.
Timeline → Auto-assemble, adjust trims, order and transitions, then Export MP4. Exports also appear on the Assets tab.
The Tutorials page (sidebar) has narrated walkthroughs of steps 2–4.
'uv' is not recognized (or node, ffmpeg): the terminal is older than the install. Fully quit and
reopen VS Code or the terminal (a new VS Code terminal tab inherits VS Code's old environment), or refresh
the current PowerShell session:
$env:Path = [Environment]::GetEnvironmentVariable('Path','Machine') + ';' + [Environment]::GetEnvironmentVariable('Path','User')nvidia-smi reports CUDA 13.0+, then rerun cd backend; uv sync. If torch.__version__ ends in +cpu,
the CUDA build wasn't installed: uv sync --reinstall-package torch. The GPU worker check shows why the
FakeEngine was chosen.winget install Gyan.FFmpeg and reopen the terminal, or set ffmpeg_path and
ffprobe_path in config.toml.vram_profile = "low" in config.toml (video drops to
832×480). For video, fewer steps also help.$env:LOCALFLOW_PORT = 9000; npm start.allow_pickle_weights = true in config.toml and restart.config.toml and recent logs. Keys and tokens are redacted, and no media or database is
included. The logs (localflow.log, worker.log in <data dir>\logs\) can also be read in Diagnostics.Install uv (curl -LsSf https://astral.sh/uv/install.sh | sh), Node.js 20+, ffmpeg (e.g.
sudo apt install ffmpeg) and an NVIDIA driver with CUDA 13 support, then follow the same steps from
npm run setup. Data goes to ~/LocalFlow. Keys come from your shell environment, or Settings stores them
in the Secret Service keyring (GNOME Keyring, KWallet). Without a keyring, they go to an encrypted file in
the data dir; Diagnostics shows which.
Three optional (draft) models in Models → Catalog trade some quality for speed (about 6 GB extra, because they share files with the models above):
| Draft model | Replaces | Steps | Time on an RTX 5080 |
|---|---|---|---|
| FLUX.1 [dev] · Q4_K_S + Turbo-Alpha | FLUX.1 [dev] | 8 instead of 28 | image 17 s instead of 42 s |
| FLUX.1 Kontext [dev] · Q4_K_M + Turbo-Alpha | FLUX.1 Kontext | 8 instead of 28 | keyframe 29 s instead of 80 s |
| Wan 2.2 TI2V-5B Turbo · Q8_0 | Wan 2.2 TI2V-5B | 4 instead of 30 | 3 s clip 52 s instead of 295 s |
Use the Final / Draft switch at the top of a project. In Draft mode, anything you don't pick a model for (Generate all, keyframes, character views, new images and videos) uses the installed draft models, then falls back to the normal ones. A model you choose in a picker is always used. The switch shows which draft models are still missing. Switch back to Final to regenerate the keepers.
The FLUX drafts look nearly the same as the full models. The video draft stays faithful to the keyframe but is a little softer. Turbo-Alpha uses the FLUX.1 [dev] non-commercial license. The Wan Turbo GGUF is a community repack (Apache 2.0); the original distillation states no license.
vision_review purpose (gpt-5.4-mini works) and costs about $0.003–0.005 a check.allow_pickle_weights = true in config.toml (Kokoro and MMAudio only publish PyTorch
pickles; LocalFlow loads them with torch.load(weights_only=True)), then install Kokoro-82M
(0.4 GB), MMAudio large 44.1 kHz v2 (10.7 GB including its CLIP and vocoder) and MusicGen small
(2.4 GB) from Models → Catalog.A film-level voice-over. The words are written and edited per shot, where you can see the picture; the voice is made on the Timeline, as one continuous track.
projects/<id>/exports/ and listed under the button, with play
and download.low VRAM profile.cancel_grace_s), the
worker is restarted.@key (fixed once saved) and character info for the story LLM.@mentions: type @ in a shot, ingredient or Playground prompt to pick a character, location or prop.
The first mention becomes its name plus visual prompt, and later ones just the name. Mentioning a
character adds it to the shot. Unknown keys are flagged, and generating with one is refused. Write @@
for a literal @. The Playground mentions Cast library characters.uv run scripts/characters/make_template_thumbnails.py against the running app (npm start).Models → Catalog lists recommended models with their size, license and VRAM notes. Hugging Face
inspects any repo (org/name or URL): it shows the files, size, license and your access, lets you pick
files, and you confirm the adapter. Civitai searches checkpoints and LoRAs, with base-model mapping,
trigger words and permissions.
HF_TOKEN, or Settings → API keys →
Import existing Hugging Face login to reuse hf auth login). If the license isn't accepted yet, the card
links to the model page; accept it there, then click Check again.CIVITAI_API_TOKEN.
Early-access versions must be unlocked on civitai.com.models/hf/repos/<org>--<name>/ and models/civitai/<modelId>/<versionId>/ in the data dir.
Only .safetensors/.gguf are accepted by default. Kokoro and MMAudio ship PyTorch pickles and need
allow_pickle_weights = true in config.toml.Keys are read from environment variables first, so if these are set you don't need to do anything:
| Provider | Environment variable |
|---|---|
| OpenAI | OPENAI_API_KEY |
| Anthropic | ANTHROPIC_API_KEY |
| OpenRouter | OPENROUTER_API_KEY |
| Hugging Face | HF_TOKEN (or HUGGING_FACE_HUB_TOKEN) |
| Civitai | CIVITAI_API_TOKEN (or CIVITAI_API_KEY) |
On Windows, variables set with setx or System Properties are picked up even if the terminal was opened
before they were set. You can also paste keys in Settings; they're stored in the OS keyring (Windows
Credential Manager), and an environment variable always takes precedence. At least one LLM key is needed for
the Story tab.
Default models (override in Settings → Default models, or in config.toml):
openai/gpt-5.4-mini, anthropic/claude-sonnet-5, openrouter/anthropic/claude-sonnet-5. A 30-second
story (refine + bible + breakdown) costs about $0.02–0.03 with gpt-5.4-mini.
Everything lives in the data directory: %USERPROFILE%\LocalFlow on Windows, ~/LocalFlow elsewhere
(override with LOCALFLOW_DATA_DIR, e.g. to put the models on a bigger drive; on Windows a user variable
set with setx is honored even in terminals opened before it). It holds localflow.db, config.toml
(created with commented defaults on first run), projects/, models/, library/, logs/, and tmp/.
Every config.toml key can be overridden with an env var LOCALFLOW_<KEY>, e.g. LOCALFLOW_PORT=9000.
The server only binds to 127.0.0.1, and every API/WebSocket call needs the per-launch token.
engine = "auto" (the default) uses the GPU when it's usable and the FakeEngine otherwise; set
engine = "fake" to force placeholders. fake_llm = true answers every LLM call with a canned demo story
(no key or network needed; for offline demos and the smoke test).
npm test # backend pytest (spawns the FakeEngine worker) + frontend vitest
npm run test:e2e # Playwright smoke test: build, then idea → story → generate all → timeline → export
npm run lint # ruff, ruff format --check, mypy, eslint, prettier, tsc
npm run typegen # regenerate frontend API types from the backend OpenAPI schema
The smoke test (frontend/e2e/) starts its own server on port 8799 with a fresh data dir in the temp
folder, the FakeEngine and fake_llm, so it needs no GPU, keys or network, and never touches your data or
keyring. It takes about 15 s. Run cd frontend; npx playwright install chromium once first. A failed run
keeps a trace and video in frontend/test-results/ (npx playwright show-report).
Real-GPU regression test (Flux → Kontext → SDXL, then unload to baseline; about 2 minutes, uses the models
installed in your data dir and skips missing ones): cd backend; uv run pytest -m gpu.
Database migrations live in backend/alembic/versions/ and run automatically at startup.
Re-recording the tutorials (after UI changes): start the built app (npm start), then run
uv run scripts/tutorials/make_tutorials.py (or --only full-film / --only story-to-shots /
--only images-and-keyframes).
The script drives Chrome through the real app, narrates with edge-tts (Microsoft's online neural voices; the
narration text is sent to that service), time-lapses LLM and GPU waits, and writes MP4 + captions + poster +
index.json to frontend/public/tutorials/. The story tutorial recreates the "The Lighthouse Gull"
project and calls your default LLM (a few cents). The images tutorial runs FLUX and FLUX Kontext jobs on that
project, so record the story tutorial first. The full-film tutorial makes "The Last Rose" from scratch and
needs FLUX, FLUX Kontext, Wan 2.2 5B, Kokoro, MMAudio and MusicGen installed; it takes about an hour of GPU
time. --only smoke --out <dir> checks the pipeline without the LLM
or GPU.
backend/localflow/ FastAPI app (routers, services, models) and worker/ (GPU process + adapters)
frontend/src/ React app (api/, app/, features/, components/)
scripts/dev.mjs dev runner
scripts/tutorials/ tutorial recorder (Playwright + edge-tts + ffmpeg)
A locally-running, single-user AI filmmaking studio inspired by Google Flow. React frontend + Python (FastAPI) backend; image/video/audio generation runs on your GPU. See SPEC.md for the full design and docs/DECISIONS.md for implementation decisions.
Status: milestones M0 through M7 are done. New here? Start with Quick start and Your first film.
@mention characters,
locations and props.Install the tools in PowerShell:
winget install astral-sh.uv Gyan.FFmpeg OpenJS.NodeJS.LTS Git.Git
Then close and reopen the terminal (and VS Code, if you use its terminal) so it picks up the new
PATH. Check with uv --version; node --version; ffmpeg -version.
GPU driver (for real generation): an NVIDIA GPU with 16 GB+ VRAM and a driver new enough for CUDA 13,
meaning the header of nvidia-smi says CUDA Version: 13.0 or higher. Update it from nvidia.com or the
NVIDIA app if not. No NVIDIA GPU? Everything still runs and makes placeholder images and videos (the
FakeEngine).
Clone and install:
git clone https://github.com/lrama1/local-flow.git
cd local-flow
npm run setup
This runs uv sync in backend/ (uv fetches Python 3.12 and the packages, including the CUDA 13 build of
PyTorch from download.pytorch.org: about 4 GB) and npm install in frontend/ (about 250 MB). Without an
NVIDIA GPU, skip the GPU packages: cd backend; uv sync --no-group gpu; cd ..\frontend; npm install.
Check that PyTorch sees the GPU:
cd backend; uv run python -c "import torch; print(torch.__version__, torch.cuda.is_available())"; cd ..
Expect something like 2.14.1+cu130 True.
Choose where data goes (optional). Models need 20–80 GB, and everything lives in
%USERPROFILE%\LocalFlow unless you set another folder before the first start, e.g.
setx LOCALFLOW_DATA_DIR D:\LocalFlow.
Add an LLM key for the story tools, e.g. setx OPENAI_API_KEY "sk-..." (or ANTHROPIC_API_KEY,
OPENROUTER_API_KEY), or paste one later in Settings → API keys. See API keys.
Start:
npm start # builds the frontend, then serves everything on http://127.0.0.1:8765
Open http://127.0.0.1:8765. For development, npm run dev runs the backend on :8765 plus Vite with hot
reload on http://127.0.0.1:5173 (the backend restarts on .py changes).
Open Settings → Diagnostics. Every check should be green: data folder writable, disk space, ffmpeg, NVIDIA GPU, PyTorch + CUDA, GPU worker, secret storage (Windows Credential Manager) and LLM providers. Amber or red rows say what to fix.
Models → Catalog: install what you need. Shared parts (text encoders, VAEs) download once, so the total is less than the sum.
| Model | Used for | Download |
|---|---|---|
| FLUX.1 [dev] · GGUF Q4_K_S | ingredient images, keyframes from text | 16.7 GB |
| FLUX.1 Kontext [dev] · GGUF Q4_K_M | keyframes composed from references, character views | 16.9 GB |
| Wan 2.2 TI2V-5B · GGUF Q8_0 | video (5 s clips at 1280×704) | 19.6 GB |
| Kokoro-82M | dialogue | 0.4 GB |
| MMAudio large 44.1 kHz v2 | sound effects synced to the picture | 10.7 GB |
| MusicGen small | music | 2.4 GB |
FLUX.1 [dev] is gated: accept its license on Hugging Face and add an HF_TOKEN (Settings → API keys can
import an existing hf auth login). Kokoro and MMAudio need allow_pickle_weights = true in
config.toml (Audio). Acknowledge each model's license on its card before first use.
Projects → New project. On Story, write a few sentences, then Refine → Build bible →
Break down into shots. A 30-second story costs about $0.02–0.03 with gpt-5.4-mini.
Ingredients: generate images for the characters, locations and props and pick a primary for each, or use New character for the wizard with consistent extra views.
Shots board: open a shot, Compose keyframe, pick one, then Generate video. Or use Generate all for every shot. Check consistency compares a keyframe or take with the references.
Audio (shot panel): dialogue and sound effects. Music is generated from the timeline.
Timeline → Auto-assemble, adjust trims, order and transitions, then Export MP4. Exports also appear on the Assets tab.
The Tutorials page (sidebar) has narrated walkthroughs of steps 2–4.
'uv' is not recognized (or node, ffmpeg): the terminal is older than the install. Fully quit and
reopen VS Code or the terminal (a new VS Code terminal tab inherits VS Code's old environment), or refresh
the current PowerShell session:
$env:Path = [Environment]::GetEnvironmentVariable('Path','Machine') + ';' + [Environment]::GetEnvironmentVariable('Path','User')nvidia-smi reports CUDA 13.0+, then rerun cd backend; uv sync. If torch.__version__ ends in +cpu,
the CUDA build wasn't installed: uv sync --reinstall-package torch. The GPU worker check shows why the
FakeEngine was chosen.winget install Gyan.FFmpeg and reopen the terminal, or set ffmpeg_path and
ffprobe_path in config.toml.vram_profile = "low" in config.toml (video drops to
832×480). For video, fewer steps also help.$env:LOCALFLOW_PORT = 9000; npm start.allow_pickle_weights = true in config.toml and restart.config.toml and recent logs. Keys and tokens are redacted, and no media or database is
included. The logs (localflow.log, worker.log in <data dir>\logs\) can also be read in Diagnostics.Install uv (curl -LsSf https://astral.sh/uv/install.sh | sh), Node.js 20+, ffmpeg (e.g.
sudo apt install ffmpeg) and an NVIDIA driver with CUDA 13 support, then follow the same steps from
npm run setup. Data goes to ~/LocalFlow. Keys come from your shell environment, or Settings stores them
in the Secret Service keyring (GNOME Keyring, KWallet). Without a keyring, they go to an encrypted file in
the data dir; Diagnostics shows which.
Three optional (draft) models in Models → Catalog trade some quality for speed (about 6 GB extra, because they share files with the models above):
| Draft model | Replaces | Steps | Time on an RTX 5080 |
|---|---|---|---|
| FLUX.1 [dev] · Q4_K_S + Turbo-Alpha | FLUX.1 [dev] | 8 instead of 28 | image 17 s instead of 42 s |
| FLUX.1 Kontext [dev] · Q4_K_M + Turbo-Alpha | FLUX.1 Kontext | 8 instead of 28 | keyframe 29 s instead of 80 s |
| Wan 2.2 TI2V-5B Turbo · Q8_0 | Wan 2.2 TI2V-5B | 4 instead of 30 | 3 s clip 52 s instead of 295 s |
Use the Final / Draft switch at the top of a project. In Draft mode, anything you don't pick a model for (Generate all, keyframes, character views, new images and videos) uses the installed draft models, then falls back to the normal ones. A model you choose in a picker is always used. The switch shows which draft models are still missing. Switch back to Final to regenerate the keepers.
The FLUX drafts look nearly the same as the full models. The video draft stays faithful to the keyframe but is a little softer. Turbo-Alpha uses the FLUX.1 [dev] non-commercial license. The Wan Turbo GGUF is a community repack (Apache 2.0); the original distillation states no license.
vision_review purpose (gpt-5.4-mini works) and costs about $0.003–0.005 a check.allow_pickle_weights = true in config.toml (Kokoro and MMAudio only publish PyTorch
pickles; LocalFlow loads them with torch.load(weights_only=True)), then install Kokoro-82M
(0.4 GB), MMAudio large 44.1 kHz v2 (10.7 GB including its CLIP and vocoder) and MusicGen small
(2.4 GB) from Models → Catalog.A film-level voice-over. The words are written and edited per shot, where you can see the picture; the voice is made on the Timeline, as one continuous track.
projects/<id>/exports/ and listed under the button, with play
and download.low VRAM profile.cancel_grace_s), the
worker is restarted.@key (fixed once saved) and character info for the story LLM.@mentions: type @ in a shot, ingredient or Playground prompt to pick a character, location or prop.
The first mention becomes its name plus visual prompt, and later ones just the name. Mentioning a
character adds it to the shot. Unknown keys are flagged, and generating with one is refused. Write @@
for a literal @. The Playground mentions Cast library characters.uv run scripts/characters/make_template_thumbnails.py against the running app (npm start).Models → Catalog lists recommended models with their size, license and VRAM notes. Hugging Face
inspects any repo (org/name or URL): it shows the files, size, license and your access, lets you pick
files, and you confirm the adapter. Civitai searches checkpoints and LoRAs, with base-model mapping,
trigger words and permissions.
HF_TOKEN, or Settings → API keys →
Import existing Hugging Face login to reuse hf auth login). If the license isn't accepted yet, the card
links to the model page; accept it there, then click Check again.CIVITAI_API_TOKEN.
Early-access versions must be unlocked on civitai.com.models/hf/repos/<org>--<name>/ and models/civitai/<modelId>/<versionId>/ in the data dir.
Only .safetensors/.gguf are accepted by default. Kokoro and MMAudio ship PyTorch pickles and need
allow_pickle_weights = true in config.toml.Keys are read from environment variables first, so if these are set you don't need to do anything:
| Provider | Environment variable |
|---|---|
| OpenAI | OPENAI_API_KEY |
| Anthropic | ANTHROPIC_API_KEY |
| OpenRouter | OPENROUTER_API_KEY |
| Hugging Face | HF_TOKEN (or HUGGING_FACE_HUB_TOKEN) |
| Civitai | CIVITAI_API_TOKEN (or CIVITAI_API_KEY) |
On Windows, variables set with setx or System Properties are picked up even if the terminal was opened
before they were set. You can also paste keys in Settings; they're stored in the OS keyring (Windows
Credential Manager), and an environment variable always takes precedence. At least one LLM key is needed for
the Story tab.
Default models (override in Settings → Default models, or in config.toml):
openai/gpt-5.4-mini, anthropic/claude-sonnet-5, openrouter/anthropic/claude-sonnet-5. A 30-second
story (refine + bible + breakdown) costs about $0.02–0.03 with gpt-5.4-mini.
Everything lives in the data directory: %USERPROFILE%\LocalFlow on Windows, ~/LocalFlow elsewhere
(override with LOCALFLOW_DATA_DIR, e.g. to put the models on a bigger drive; on Windows a user variable
set with setx is honored even in terminals opened before it). It holds localflow.db, config.toml
(created with commented defaults on first run), projects/, models/, library/, logs/, and tmp/.
Every config.toml key can be overridden with an env var LOCALFLOW_<KEY>, e.g. LOCALFLOW_PORT=9000.
The server only binds to 127.0.0.1, and every API/WebSocket call needs the per-launch token.
engine = "auto" (the default) uses the GPU when it's usable and the FakeEngine otherwise; set
engine = "fake" to force placeholders. fake_llm = true answers every LLM call with a canned demo story
(no key or network needed; for offline demos and the smoke test).
npm test # backend pytest (spawns the FakeEngine worker) + frontend vitest
npm run test:e2e # Playwright smoke test: build, then idea → story → generate all → timeline → export
npm run lint # ruff, ruff format --check, mypy, eslint, prettier, tsc
npm run typegen # regenerate frontend API types from the backend OpenAPI schema
The smoke test (frontend/e2e/) starts its own server on port 8799 with a fresh data dir in the temp
folder, the FakeEngine and fake_llm, so it needs no GPU, keys or network, and never touches your data or
keyring. It takes about 15 s. Run cd frontend; npx playwright install chromium once first. A failed run
keeps a trace and video in frontend/test-results/ (npx playwright show-report).
Real-GPU regression test (Flux → Kontext → SDXL, then unload to baseline; about 2 minutes, uses the models
installed in your data dir and skips missing ones): cd backend; uv run pytest -m gpu.
Database migrations live in backend/alembic/versions/ and run automatically at startup.
Re-recording the tutorials (after UI changes): start the built app (npm start), then run
uv run scripts/tutorials/make_tutorials.py (or --only full-film / --only story-to-shots /
--only images-and-keyframes).
The script drives Chrome through the real app, narrates with edge-tts (Microsoft's online neural voices; the
narration text is sent to that service), time-lapses LLM and GPU waits, and writes MP4 + captions + poster +
index.json to frontend/public/tutorials/. The story tutorial recreates the "The Lighthouse Gull"
project and calls your default LLM (a few cents). The images tutorial runs FLUX and FLUX Kontext jobs on that
project, so record the story tutorial first. The full-film tutorial makes "The Last Rose" from scratch and
needs FLUX, FLUX Kontext, Wan 2.2 5B, Kokoro, MMAudio and MusicGen installed; it takes about an hour of GPU
time. --only smoke --out <dir> checks the pipeline without the LLM
or GPU.
backend/localflow/ FastAPI app (routers, services, models) and worker/ (GPU process + adapters)
frontend/src/ React app (api/, app/, features/, components/)
scripts/dev.mjs dev runner
scripts/tutorials/ tutorial recorder (Playwright + edge-tts + ffmpeg)