Making Marketing Videos with Local AI: ComfyUI, Flux, and Wan 2.2
October 25, 2026 · 8 min read
Small businesses need video. A roofing company that can show a homeowner what premium underlayment actually does, or what a crew looks like on the job, gets more trust than one with a static website. But a video shoot costs real money, and a small contractor will not pay for one every time they want to promote a product.
So I started building those videos with AI, almost entirely on my own machine. The stills, the motion, the voiceover, and the edit all happen locally. The only paid service involved is my electricity bill.
This post covers the pipeline I landed on, the hardware it runs on, and what I learned about getting usable video out of open models instead of melting roofs and extra limbs.
The pipeline
Video script (plain text)
│
├─► Ollama (local LLM) ── breaks the script into one image prompt per slide
│ │
│ ▼
│ ComfyUI + Flux Schnell ── one 1024x1024 still per slide
│ │
│ ▼
│ ComfyUI + Wan 2.2 I2V ── each still animated into a ~3s clip
│
├─► Kokoro / Piper TTS ── voiceover from the same script
│
▼
Kdenlive ── cut clips, lay voiceover, export
Everything is driven by one script. The narration I write for the voiceover is the same text the LLM reads to plan the visuals, so the pictures and the words stay in sync without me storyboarding by hand.
The hardware
All of this runs on a desktop with an AMD Radeon RX 9070 XT, which has 16GB of VRAM. That is a consumer card, not a data-center GPU, and it shapes every decision below. The video model in particular does not fit at full precision, so a lot of the work was finding the quantization, resolution, and frame-count settings that fit in 16GB without the output falling apart.
Step 1: Let a local LLM write the image prompts
Writing a good image prompt for every slide is tedious, and I was doing it by hand at first. Now a ComfyUI workflow does it. The comfyui-ollama custom node sends my script to a local model (I use qwen2.5:7b-instruct through Ollama for this) with an instruction along these lines:
You are a prompt generator for an image model. Read the video script below
and break it into distinct visual slides. For EACH slide, output ONE
single-line, detailed, photographic image-generation prompt describing the
scene. Output ONLY the prompts, one per line, with no numbering, no blank
lines, no commentary, no markdown. Each line must be self-contained.
One prompt per line is the important constraint. It means the output can be split on newlines and fed straight into the image step, one line per queued run. Any chatter from the model, such as numbering or a friendly intro, would become a broken slide, so the prompt is strict about format.
Step 2: Stills with Flux Schnell
The stills come from Flux Schnell in FP8, which fits comfortably on the card and is fast: 4 steps, CFG 1.0, euler sampler. Schnell ignores the negative prompt, so all the steering goes into the positive prompt plus a shared style suffix that gets appended to every line so the slides look like they belong to the same video.
A second workflow covers the case where I want to write the slide descriptions myself. I put one description per line in slides.txt, set the ComfyUI batch count to the number of lines, and a LoadPromptsFromFile node advances one line per run. Each slide is saved with a predictable filename so it is easy to find in the next step.
For some shots I also used images generated in Gemini, and real photos from the client's job sites. Which brings me to the most useful lesson of the whole project.
Step 3: Image-to-video with Wan 2.2
This is where a still becomes a clip. I use Wan 2.2's image-to-video model (the 14B "A14B" variant) as a GGUF quantization, loaded through the ComfyUI-GGUF custom node. At Q4_K_M it fits on a 16GB card. Q3_K_S is the fallback if I run out of memory, and Q5_K_M gives better quality but needs to offload to system RAM.
Native generation is slow at the default 20 or so steps, so I pair it with the Lightx2v 4-step LoRA. Wan 2.2 I2V uses two models, a high-noise one and a low-noise one, so the 4 steps are split two and two between them. My defaults look like this:
- Resolution: 832x480 (landscape) or 480x832 (Reels / TikTok)
- Frame rate: 16 fps
- Frames: 49 for ~3s (Wan wants 4n+1 counts: 33, 49, 65)
- Steps: 4 total, 2 high-noise and 2 low-noise
- CFG: 1.0 with the 4-step LoRA (3.5-5 at ~20 steps without it)
- Sampler / scheduler:
euler/simple
I keep a shot list as a JSON file: one entry per shot with the start image, the positive prompt, a note on the intended motion, and any per-shot settings. A shared negative prompt covers the usual failures:
blurry, distorted, warped hands, extra limbs, morphing, flickering,
jittery motion, unstable geometry, melting roof, deformed ladder,
text artifacts, watermark, oversaturated, low quality, camera shake,
people teleporting
"Melting roof" and "deformed ladder" are in there for a reason.
For each shot I generate four to six takes and keep the clean ones. That is the real cost of local video: not money, but rerolls.
What actually makes the video usable
Most of my early output was unusable. These are the rules that changed that, written down in the shot list so I stop relearning them:
- The prompt directs motion, not the scene. Image-to-video already has your composition from the still. Re-describing the house and the crew in detail just gives the model more chances to change them. Describe the camera move and the action.
- One action per clip. "A roofer walks across the roof carrying shingles, camera pans to follow" works. Add a second action and that is where morphing starts.
- Match frame count to the shot. Fewer frames (33) for close-ups with hands and tools, which warp easily. More (49 to 65) for slow camera moves on a wide shot.
- When output warps, back off in order. Lower the frame count first, then the resolution, then step down the quant.
- Use real photos where you can. Stills of the client's actual crew on an actual job are cleaner and more on-brand than generated roofers. AI is best at adding motion to real footage, not inventing the whole scene.
Step 4: Voiceover with local TTS
The narration is generated locally too, with Kokoro (an ONNX text-to-speech model) and Piper voices as an alternative. A small shell script reflows the script so paragraphs become single lines, which stops the TTS engine from pausing mid-sentence at line breaks, then synthesizes a WAV with a chosen voice and speed. I usually run narration slightly faster than default, around 1.25x, because the default pacing sounds slow over video.
There is also a batch version that renders the same script in every available voice, so I can listen through the samples and pick one instead of guessing from voice names.
Step 5: Cut it in Kdenlive
The final edit is done by hand in Kdenlive: arrange the clips, trim the bad frames at the start and end of each take, lay the voiceover underneath, and export at the right aspect ratio for where it is going. This is the step I have no interest in automating. Timing and pacing are where a video feels professional or doesn't, and that is a judgment call.
Things I tried that didn't make the cut
- AnimateDiff. My first attempt at motion used AnimateDiff with a Stable Diffusion 1.5 motion module. It produced movement, but nowhere near the coherence of Wan 2.2. It was a good way to learn ComfyUI's video nodes, and that is about all.
- Talking avatars. I experimented with SadTalker, FLOAT, and Wav2Lip to animate a presenter's face from a single image and a voiceover track. It is fun, and the technology is moving fast, but for a contractor's marketing video, real footage plus a voiceover reads as more trustworthy than a generated spokesperson.
Takeaways
- A 16GB consumer GPU is enough for useful short-form video with the right quantization and a step-distillation LoRA.
- Chain the models around one script. Use an LLM to plan the visuals, an image model for stills, a video model for motion, TTS for voice. Each step is replaceable on its own.
- Image-to-video beats text-to-video for client work. Starting from a still, ideally a real photo, gives you control over what ends up on screen.
- Write your lessons into the workflow. A shot list with settings, shared negatives, and prompting rules turned a lot of trial and error into something I can repeat.
- Keep a human on the edit. The models generate the parts. Deciding what is good enough to show a customer is still my job.