30 October 2026

A film studio on one Mac

Date: 30 October 2026

The workflow is solved. The look is not.

KindDetail
GoalDecide 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.
ConstraintLocal only. No cloud model, API key or remote generation on the critical path.
ConstraintOne Apple Silicon Mac. 96 GB unified memory, 150 GB free disk minimum, 200 GB comfortable.
ConstraintOne model store. Every weight lives in ~/.cache/huggingface/hub; no duplicate ComfyUI or ollama copies.
ConstraintNo render farm. A first production has to fit an overnight or multi-day schedule.
ConstraintThe reference is the photoreal TikTok series, not a festival film. The format allows two characters, close-ups, short cuts and a controlled look.
ConstraintThe writer owns taste. The model drafts and diagnoses; a person decides.
Method 1Surveyed the skills already on the machine and a dozen external repositories, then read the strongest ones end to end.
Method 2Adopted three skills, adapted the character-consistency method from a fourth, and wrote the six that connect them.
Method 3Probed the machine: runtimes, model files, disk, ComfyUI, omlx, rapid-mlx, Unsloth and the Hugging Face cache.
Method 4Built the ten skills, filmctl.py, pull_models.py, storycheck.py and smoke_test.sh.
Method 5Tested the plumbing with a synthetic project. No real shot was generated during the investigation.
Method 6Defined 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.

StageSkillWhat it leaves behind
Storyfilm-story-developmentlogline, characters, beats, Fountain screenplay, series bible, quality report
Designfilm-design + character-designstyle lock, world bible, character packs, identity blocks, voices, continuity ledger
Planfilm-directingblocking, shot list, coverage, storyboards, animatic, sound plan
Preparefilm-generationapproved keyframes, compiled prompts, budget
Generatefilm-generationtakes, continuity QA, generation log
Assemblefilm-postproductionrough cut, picture lock
Soundfilm-postproductiondialogue, ambience, Foley, score, mix
Finishfilm-postproductiongrade, titles, captions, QC
Deliverfilm-postproduction + film-postermasters, 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.

RoleModelQuantSize
LLM, fastqwen3.6-35b-udMLX 4-bit20.2 GB
LLM, qualityqwen3.8-27b-4bitMLX 4-bit + MTP20.0 GB
Video, defaultltx-2.3-mlx-q4MLX q4, audio21.2 GB
Video, qualitywan2.2-ti2v-5b-q8MLX q818.2 GB
Image, fastflux2-klein-4bmflux 4-bit4.3 GB
TTSqwen3-tts-4bit, chatterbox-4bit, kokoro-4bitMLX 4-bit0.3 to 2.2 GB
STT / alignwhisper, qwen3-forced-alignerMLX / 8-bit1.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:

FormatShotsLocal one passRealistic schedule
60 to 180 s vertical15 to 450.5 to 1.5 han afternoon
5 to 8 min short75 to 1202 to 4 h1 to 2 days
10 to 15 min short150 to 2254 to 7 h3 to 5 days
90 min feature1,35037.5 hweeks; 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

If you run it, start with the pilot. The numbers are more useful than a claim about what a model can do.