| Kind | Detail |
|---|---|
| Goal | Decide whether a local, on-machine pipeline can produce a film or series that holds up against the photoreal AI series on TikTok, and what that costs in models, time and craft. I am not trying to prove local is better. I want the boundary: which parts are solved, which are not, and what a producer should do about it. |
| Constraint | Local only. No cloud model, API key or remote generation on the critical path. |
| Constraint | One Apple Silicon Mac. 96 GB unified memory, 150 GB free disk minimum, 200 GB comfortable. |
| Constraint | One model store. Every weight lives in ~/.cache/huggingface/hub; no duplicate ComfyUI or ollama copies. |
| Constraint | No render farm. A first production has to fit an overnight or multi-day schedule. |
| Constraint | The reference is the photoreal TikTok series, not a festival film. The format allows two characters, close-ups, short cuts and a controlled look. |
| Constraint | The writer owns taste. The model drafts and diagnoses; a person decides. |
| Method 1 | Surveyed the skills already on the machine and a dozen external repositories, then read the strongest ones end to end. |
| Method 2 | Adopted three skills, adapted the character-consistency method from a fourth, and wrote the six that connect them. |
| Method 3 | Probed the machine: runtimes, model files, disk, ComfyUI, omlx, rapid-mlx, Unsloth and the Hugging Face cache. |
| Method 4 | Built the ten skills, filmctl.py, pull_models.py, storycheck.py and smoke_test.sh. |
| Method 5 | Tested the plumbing with a synthetic project. No real shot was generated during the investigation. |
| Method 6 | Defined a blind pilot of sixty to ninety seconds to measure the look against a reference clip. |
The sources, the rejected options and the model versions are in the package.
What the reference series do
TikTok is full of six-part series that claim every frame was generated. The faces hold, the voices hold, the cuts land every two seconds. Then you count the shots and notice the same two rooms, the same two faces, the same three camera setups. The format is doing as much work as the model.
The pattern is boring once you see it.
- Two characters, maybe three. Two rooms. A corridor.
- Close-ups and singles. Very few wides, because wides are where faces turn to mush.
- Cuts every one to three seconds, which hides the fact that nothing moves for long.
- A locked reference image, or a small LoRA, for each face.
- A cloned voice per character, reused across episodes.
- Native dialogue on the model, or a dedicated lip-sync pass afterwards.
- A grade, grain, sound design, music. The picture is not the finished thing.
- Forty takes for the one that works.
None of that is a model. It is production. The generator, the part everyone talks about, is one line in the budget.
What I built
Ten skills, nine stages, five approvals. The approvals are the useful part. A bad premise is cheap to fix before design and expensive to fix after a thousand generations.
| Stage | Skill | What it leaves behind |
|---|---|---|
| Story | film-story-development | logline, characters, beats, Fountain screenplay, series bible, quality report |
| Design | film-design + character-design | style lock, world bible, character packs, identity blocks, voices, continuity ledger |
| Plan | film-directing | blocking, shot list, coverage, storyboards, animatic, sound plan |
| Prepare | film-generation | approved keyframes, compiled prompts, budget |
| Generate | film-generation | takes, continuity QA, generation log |
| Assemble | film-postproduction | rough cut, picture lock |
| Sound | film-postproduction | dialogue, ambience, Foley, score, mix |
| Finish | film-postproduction | grade, titles, captions, QC |
| Deliver | film-postproduction + film-poster | masters, key art, one-sheet, thumbnail, manifest |
The pipeline does not generate. It refuses to let you skip the cheap decisions. Each stage writes an artifact the next stage reads, and a gate decides whether the next stage may start. The state lives on disk, not in a chat window.
What runs locally
The default runtime is rapid-mlx: it reads the Hugging Face cache directly and serves
text, image, video, TTS and STT through one OpenAI-compatible API. Unsloth Studio is the
second runtime, with a UI, audio.cpp for speech and music, and MiniMax-H3, speech-to-video,
avatar and lip-sync models. ComfyUI handles GGUF models, control nets and upscaling, with
its models symlinked into the same cache.
The core set is about 91 GB.
| Role | Model | Quant | Size |
|---|---|---|---|
| LLM, fast | qwen3.6-35b-ud | MLX 4-bit | 20.2 GB |
| LLM, quality | qwen3.8-27b-4bit | MLX 4-bit + MTP | 20.0 GB |
| Video, default | ltx-2.3-mlx-q4 | MLX q4, audio | 21.2 GB |
| Video, quality | wan2.2-ti2v-5b-q8 | MLX q8 | 18.2 GB |
| Image, fast | flux2-klein-4b | mflux 4-bit | 4.3 GB |
| TTS | qwen3-tts-4bit, chatterbox-4bit, kokoro-4bit | MLX 4-bit | 0.3 to 2.2 GB |
| STT / align | whisper, qwen3-forced-aligner | MLX / 8-bit | 1.2 to 2.9 GB |
Four-bit and q4 are the fast ones. q8 and bf16 are for hero shots with nothing else loaded.
Every weight lives in ~/.cache/huggingface/hub; there is no second model store. The pull
script skips what is already there, resumes partial downloads, and refuses to start if the
disk cannot hold the set plus a reserve.
[[note: the tell is in the coverage, not the pixels]]
Where quality actually comes from
Not from a bigger model. A bigger model raises the ceiling; it does not raise the floor. The floor is a set of decisions that have nothing to do with generation.
The story skill runs a rubric with eight dimensions and requires scene and line evidence for anything below a three. Then it asks three readers and a hostile producer to attack the draft in separate contexts. A model asked whether its own draft is good will say yes. A model asked to find the scene that could be cut will find it.
Each principal becomes a contract: a fixed identity block, a five-view sheet, a hero frame, a voice, a drift audit. Each recurring location gets an establishing frame, a reverse and a floor plan. A video model does not know where the last shot put the camera. The floor plan is how you tell it.
The still decides the shot. The video model re-animates it. If the keyframe is wrong, the video take is not a performance problem. It is a photograph problem. Fix the photograph.
Then the pilot. Sixty to ninety seconds, two faces, one room, four to six lines. Run the same script and keyframes through LTX-2.3 and Wan 2.2 I2V, and through one cloud model only if you allow it. Score blind on identity, lip-sync, realism, voice consistency and emotional read. If identity or lip-sync fails, the local route is not enough for that format. Pick the hybrid, narrow the format, or accept the lower tier. Do not argue with the score.
None of this guarantees taste. It catches the failures taste would catch later, at a higher price.
The arithmetic
At roughly four seconds per shot:
| Format | Shots | Local one pass | Realistic schedule |
|---|---|---|---|
| 60 to 180 s vertical | 15 to 45 | 0.5 to 1.5 h | an afternoon |
| 5 to 8 min short | 75 to 120 | 2 to 4 h | 1 to 2 days |
| 10 to 15 min short | 150 to 225 | 4 to 7 h | 3 to 5 days |
| 90 min feature | 1,350 | 37.5 h | weeks; hybrid required |
Three variants per shot triples the generation time. Retries add another 20 to 50%. A feature is not a long render. It is a campaign, and most of it should be animatic, stock, 2D inserts or selective generation. Make a five-minute film first. Not a feature.
Setup
The full runbook is written for an agent to execute on a fresh Mac. The short version:
brew install ffmpeg rapid-mlx
python3 -m pip install --user -U "huggingface_hub[cli]"
mkdir -p ~/src/ml/skills && cd ~/src/ml/skills
curl -fL -o film-production-skills-2026-10-30.tar.gz \
https://nyimbi.com/downloads/film-production-skills-2026-10-30.tar.gz
tar -xzf film-production-skills-2026-10-30.tar.gz
cd film-production-skills
python3 sync-skills.py
python3 skills/film-production/scripts/pull_models.py --tier core --check
python3 skills/film-production/scripts/pull_models.py --tier core --yes
./smoke_test.sh
Then start the servers on 8001 and up, because omlx may already own 8000:
rapid-mlx serve qwen3.6-35b-ud --port 8001
rapid-mlx serve flux2-klein-4b --port 8002
rapid-mlx serve ltx-2.3-mlx-q4 --port 8003 --video-output-dir ~/films/_gen
rapid-mlx serve qwen3-tts-4bit --port 8004
rapid-mlx serve whisper --port 8005
The runbook covers preflight, disk and memory, optional Unsloth and ComfyUI installs, model
tiers, health checks, the smoke test, the first project, the pilot and the failure modes.
It stops on conflicts and failed disk checks. It does not use cloud keys, duplicate model
stores, or rm -rf.
Limits
Two model families were retired in the five weeks before this was written. Sora 2 and the OpenAI Videos API went on 24 September. Veo 3.1 Preview left the Gemini API on 22 October. A pipeline that hardcodes a provider has an expiry date.
The rest is craft. Photoreal human motion is the hardest local target. Lip-sync still fails on profiles, teeth, occlusion and fast speech. Local voices are consistent but flatter than the best commercial work. Upscaling adds sharpness, not detail. Four bits is fast because it has given something up.
A local-only pipeline is a choice with a look. Make it on purpose.
Downloads
- The skills package: ten skills, scripts, runbook, research report, notices. 1.4 MB.
- Checksum.
- Agent setup runbook: the step-by-step another agent can run.
- Research monograph: the model survey, local stack, quality ceiling and pilot protocol, in one document.
- Research report as Markdown and as HTML.
If you run it, start with the pilot. The numbers are more useful than a claim about what a model can do.