How a folder of 228 high-resolution graphic novel panels became a polished teaser video, and why Go was the right language for the job.
The Project
The Odyssey Illustrated is a graphic novel rendition of Homer's epic — panel by panel, book by book. You can see the result in action on
The requirements were straightforward. Sample every fourth panel to get a manageable subset. Resize them to 1080p. Stitch them together with crossfade transitions. Add a dramatic audio track. Output an MP4. A weekend project, right?
It turned out to be one — but not in the way I expected. The language I reached for first was Python, and within an hour I was reaching for something else.
Why Python Falls Short Here
Python is excellent for a huge range of tasks. Video processing of large image sets, however, exposes some of its rougher edges.
The first problem is memory. Pillow, Python's go-to image library, loads entire images into RAM as uncompressed pixel arrays. A single 1536×1024 RGB image becomes roughly 4.7 megabytes in memory — nearly double its on-disk size. At 228 images, that's over a gigabyte just for the source frames, before any processing begins. There's no streaming decode, no lazy loading. You either fit everything in memory or you don't.
The second problem is the ecosystem. MoviePy, the most popular Python video editor, is a convenience wrapper around ffmpeg subprocess calls. It works for simple tasks, but the pipeline is fragile. Frames pass through pipes between Python and ffmpeg, with format conversions at every boundary. Debugging failures means tracing errors across two runtimes. And the API, while friendly, hides enough of the underlying mechanics that performance surprises are common.
Then there's the GIL. Python's global interpreter lock means that CPU-bound work — like resizing hundreds of images — runs on a single core regardless of how many you have. You can multiprocess around it, but that introduces its own complexity: shared memory, serialization overhead, process management.
Finally, there's the typing problem. When you're computing image dimensions across a pipeline of resize, pad, and transition operations, dimension mismatches are the kind of bug that should be caught at compile time. In Python, they surface at runtime, often after you've already processed fifty images and attempted a crossfade that silently fails.
None of these are dealbreakers in isolation. Together, they added up to friction I didn't want for a tool that should have been simple.
The Go Advantage
Go handles this kind of work with a quiet competence that's hard to overstate.
The standard library includes image/png and image/jpeg — full decode and encode with zero external dependencies. For resizing, golang.org/x/image/draw provides quality interpolation modes including bilinear and Catmull-Rom. No pip install, no version conflicts, no ABI mismatches. Just import and use.
The type system caught bugs early. When I defined the resize function to return image.RGBA, the compiler enforced that every downstream consumer worked with the correct dimensions. The padding step — necessary because moviego requires all frames to share identical pixel dimensions for transitions — was trivial to verify at compile time.
Deployment is a single binary. No virtualenvs, no dependency trees, no "works on my machine." The tool compiles to a statically linked executable that runs anywhere Go is supported.
And the concurrency model, while not fully exploited in this project, is built in. Goroutines and channels are there when you need them. A future version could resize frames in parallel across all available cores with minimal code changes.
Enter MovieGo
The piece that made this project viable in Go was is a graphic novel rendition of Homer's epic. Watch the trailer on .
SOCIAL SHARE CARD GENERATOR