I wanted to find out whether a laptop can make an animated short with AI. Not "can a
model generate a picture" — the whole thing: music, voices, character art that stays
the same person across shots, and motion.
The machine is an M1 Pro with 16GB of unified memory. Everything below was measured on
it over three days. Two parts worked better than I expected. One part did not work at
all, and that is the part worth writing down, because "it does not run on this
hardware" is the answer people actually need before they spend a weekend on it.
I did not want to pay for Suno or Udio, so I wrote a synthesiser. Plucked strings are
Karplus-Strong: fill a buffer the length of one period with noise, then walk it,
averaging each sample with its neighbour. The averaging is a low-pass filter applied
once per period, so the high harmonics die first and you get a string.
The first version was unlistenable and I could not say why. So I measured it against a
reference track — FFT, energy per band, stereo correlation, dynamic range:
| Metric | Reference | My v1 | My v2 |
|---|---|---|---|
| bass 60-250Hz | 34.3% | 85.2% | |
| 32.4% | |||
| mid 500-2kHz (melody) | 42.6% | 1.5% | |
| 49.4% | |||
| simultaneous partials | 6 | 2 | 8 |
| L/R correlation | 0.47 | 1.00 | |
| 0.10 | |||
| dynamic range | 2.7dB | 9.8dB | 4.8dB |
Two things jump out. 85.2% of the energy was in the bass and 1.5% was in the band where melody lives — the tune was not quiet, it was absent. And the L/R correlation
48 seconds of finished audio synthesises in 3.5 seconds.
Four attempts, in order: edge-tts (two Japanese voices total, so you cannot cast a
scene), VOICEVOX (43 speakers, genuinely good, but built for utility narration),
Style-Bert-VITS2 with an emotional corpus (seven emotions as a continuous weight), and finally a higher-fidelity model.
I spent that whole ladder assuming the flatness was a model-quality problem. It was
not. The script contained period vocabulary, and the TTS was reading it wrong:
| Written | What the TTS said | Correct |
|---|---|---|
| 明智日向守 (a title: "Akechi, Governor of Hyūga") | Akechi Hyūga Mamoru | |
| Akechi Hyūga no Kami | ||
| 濃姫 (a name: "Nōhime") | Noohime | |
| Nohime |
It parsed 守 — the "governor" in a court title — as the given name Mamoru. That was in
the most dramatic line in the script. No amount of model swapping fixes a wrong reading.
VOICEVOX's /audio_query
endpoint returns the kana and accent position it is about to
use, so you can check every proper noun before you synthesise anything. I had never
looked at it.
Practical notes if you go down this path: Style-Bert-VITS2 needs Python 3.11 (pyopenjtalk
does not build on 3.13), and the distributed BERT weights are fp16 while the synthesis
side runs fp32, so CPU inference dies with Input type (c10::Half) and bias type (float)
until you cast it.
should be the same
Animagine XL 4.0, 832x1216, 28 steps: about 5 minutes per image on MPS. Character consistency held. Same seed plus the character's appearance written out
identically in every prompt, and the same person appears in a rain-lit corridor and at a
banquet. That was the risk I expected to sink the project, and it did not.
What broke was hands. A shot described as "pouring sake into a cup" produced three hands. I had chosen close-ups of hands deliberately — the source material has no male
Also, without negative prompts for it, a 1560 Japanese castle grows roses, and a naginata
becomes a katana.
Wan 2.1 T2V 1.3B, Apache-2.0, through ComfyUI. 832x480, 33 frames — about two seconds of footage — at 20 steps.
| Progress after 90 minutes | 9 of 20 steps | | Process CPU | 10.4% | | Swap in use | 23.3GB of 24.5GB | | System memory free | 19% |
It never finished. The CPU figure is the tell: the process was not computing, it was
waiting on disk. The text encoder alone is 6.7GB; add the diffusion weights, the VAE and
the intermediate tensors and you exceed 16GB of unified memory, and the overflow goes to
SSD. Swap cannot be read at the speed a sampler wants it.
So: not "slow". Not running. If you want generated motion on this class of machine, the
honest options are a hosted model or a rented GPU.
I downloaded the same model twice, in two different ways, and did not notice until
someone asked why the disk was filling up.
hf_hub_download
puts the file in a cache and returns the path; copying it to your
models directory leaves two full copies — 21GB in my case. Then, holding
ComfyUI-format weights already, I called diffusers
' from_pretrained()
, which
downloaded the entire Diffusers-format repository of the same model — another 5.2GB.
Move the file instead of copying it, delete the cache entry after, and if you already
have ComfyUI-format weights, drive ComfyUI rather than handing the name to diffusers.
Synthesis and stills are yours for free and they are good. Prosody is a data problem
before it is a model problem — check what your TTS thinks the words are. Composition
choices decide whether generation breaks, so avoid hands. And measure the video step
before you plan around it: an hour and a half of swap thrashing for nine steps is the
kind of number that changes a project, and it takes one run to find.
Part of an ongoing 6-month experiment running three AI-curated directory sites. The technical claims here are real; this article was AI-assisted.