I recently wrote my own rendering pipeline on top of Manim to improve my video production workflow.
Normally I prioritize straightforward code.
But this time, I intentionally used Pythonic magick:
Dynamic class creation/metaclasses with type() - which allows me to switch dynamically between base/scene types (e.g. MovingScene, ThreeDScene, etc) at runtime:
def create_lna_scp(scene_type: str, args: argparse.Namespace, scpl):
DynamicLNAScpl = type(
"DynamicLNAScpl",
(LineaSceneplay, scene_type),
{},
)
return DynamicLNAScpl(args, scpl)
(With this, I can override/extend hooks, while still inheriting concrete render behaviors. The effect: one CLI flag can flip the entire scene used for rendering without conditionals or inheritance spaghetti.)
Runtime-scoped engine reconfiguration, using a context wrapped in Manim’s tempconfig(...). So I can parallelize rendering, and even do things like switching between rendering machines at the script-level (without needing to toggle CLI flags) using globals() introspection.
Remote rendering pipeline with safe staging + round-trip artifacts. It procedurally builds an SSH call, runs the remote command against the same script again via a CLI toggle, gathers outputs, then SCPs generated artifacts back and previews them locally. There's a "ship, render, fetch" loop.
Multi-scene orchestration, with selective subscene execution. I can batch-write scenes, then stitch or reorder outputs using YAML.
Dynamic module imports at runtime - a kind of metaprogramming mischief:
play_module = importlib.import_module(f"{lt}.{ifs.stem}")
construct_func = getattr(play_module, "construct")
class LNADraw(toggle_scene_type(play_module, args, RendererType.RendererDraw)):
construct = construct_func
It jacks into Manim's construct() method, and allows me to write extremely short script-like Manim code from a separate file - with debugging support, but without repeating the fluff of context setup.
I don't normally code like this.
The amount of magick going on can be overwhelming. I have to document things going on constantly - otherwise, the code is brittle.
But consider these:
I'm the only user as its developer.
I've structured the package quite well for maintainability, and I'm otherwise using best Python practices.
I see little need for new features - it's effectively feature-complete, as a purposive wrapper atop an existing framework.
I was in doubt at first about whether all the metaprogramming would lead to anything. But the amount of complexity reduction it led to when it came to actually scripting and rendering videos - and how much faster everything became - was, simply said, breathtaking.
Python's flexibility here was a creative amplifier; it made me reflect as to how powerful Python can be, if you use it judiciously. And how sometimes, complexity can be a worthwhile trade-off.
To compare: I love Golang for the limited simplicity of the language. I love it because it's not as 'expressive' as Python.
But sometimes?
It's just nice to have Python's full stack of paintbrushes, colours, palettes, etc - when you really just want to paint.