Headless rendering and assembling in CI
All videos of the set are made automatically, without opening an editor. Blender renders every part headless on a server in CI, ffmpeg assembles the parts into the final loops and adds a preview frame at the beginning.
The set is not one long animation, but 12 independent parts – the motto and 11 icons – each
in its own Blender (4.0) file: motto.blend, i01-bank.blend … i11-build.blend.
All parts share the same format (1080 × 1080, 24 fps, the same codecs), the same timeline
and the same music, so they can be joined in any order. Changing one icon means rendering
only that one part again; the final videos are then assembled in seconds.
Every .blend file contains two scenes and the script render.sh renders both
headless (blender -b), so it runs on a render server in a CI job as well as on a laptop:
for source; do
blender -b "${source}" -S '3D' -a
blender -b "${source}" -S 'Render' -o "${BUILD_PATH}/${source%.blend}.mp4" -a
done
build/.The paths are not hardcoded: BLENDER_PATH points to the Blender binary on the server
(by default /usr/local/blender/blender) and BUILD_PATH to the output directory
(by default build). Sources (.blend, fonts, music) are versioned in git; renders and
caches are build outputs and stay out of the repository.
All parts have identical streams, so ffmpeg joins them with the concat demuxer and stream
copy (-c copy) – no re-encoding, no quality loss, done in a moment. The list of files is
generated on the fly from the icons in the build directory:
# motto + icon1 + motto + icon2 + ...
ffmpeg -f concat -safe 0 \
-i <(printf "file '$PWD/motto.mp4'\nfile '$PWD/%s'\n" i[0-9]*.mp4) \
-c copy full.mp4
# motto + icons
ffmpeg -f concat -safe 0 \
-i <(printf "file '$PWD/%s'\n" motto.mp4 i[0-9]*.mp4) \
-c copy icons.mp4
concat.sh makes both final loops: full.mp4 (the full version) and
icons.mp4 (the short version),add_motto.sh puts the motto in front of every single icon (m-i01-bank.mp4 …),
for showing one industry on its own.Adding a new icon is just adding a new i12-….blend file – the scripts pick it up by its name.
A video on a web page or a social network shows its first frame as a preview – and the
first frame of every part is almost black, with only a tiny cursor. The script
thumbnail.sh therefore puts a chosen frame in front of the video:
-f <frame>),anullsrc, 48 kHz), so that the preview has the same
streams as the animation – without it the stream copy join would lose the sound,tn-<name>.mp4.#f0ab00