| name | fractal-showcase-animation |
| title | Fractal Showcase Animation with Music |
| description | Generate a short Manim video showcasing famous fractals (Mandelbrot set, Sierpinski triangle, Barnsley fern, Barnsley elephant) and add a simple background music track. The process includes on‑the‑fly generation of fractal PNGs using matplotlib, assembling them in a Manim scene, rendering, creating a clean audio track, and merging with ffmpeg.
|
| category | data-science |
Overview
This skill automates the creation of a ~1 minute fractal demonstration video with smooth transitions and background music. It is reusable for any set of fractal images and works in a standard Manim Python virtual environment.
Prerequisites
- A Manim community installation (preferably in a virtualenv, e.g.
~/.venvs/manim).
matplotlib and numpy available in the same environment (pip install matplotlib).
ffmpeg installed for audio/video processing.
Directory Structure
~/fractals-animation/
│ script.py # Manim scene (see below)
│ generate_fractals.py # optional helper Python script to pre‑generate images
└───media/videos/script/480p15/ # rendered video output
All generated PNGs are stored in a temporary directory (/tmp/fractals_imgs).
Step‑by‑Step Procedure
- Prepare the working directory
mkdir -p ~/fractals-animation && cd ~/fractals-animation
- Create the Manim script (
script.py). The script:
- Imports
matplotlib to generate the fractal PNGs the first time it runs (caches them in /tmp/fractals_imgs).
- Defines a
FractalsShowcase scene that:
- Shows a title.
- Presents each fractal image with
FadeIn → hold → FadeOut.
- Includes a brief Mandelbrot zoom animation.
- Ends with a closing caption.
- Install required Python packages (once):
source ~/.venvs/manim/bin/activate
pip install matplotlib
- Render the draft video (quick quality):
~/.venvs/manim/bin/manim -ql script.py FractalsShowcase
Output will be at media/videos/script/480p15/FractalsShowcase.mp4.
- Create a simple background music track (pure sine tone, 55 s):
ffmpeg -y -f lavfi -i sine=frequency=440:duration=55 \
-c:a pcm_s16le -ar 44100 -ac 2 /tmp/tone.wav
ffmpeg -y -i /tmp/tone.wav -c:a aac -b:a 192k -ar 44100 /tmp/bg_music.aac
(Any other royalty‑free audio can replace tone.wav – just ensure the format is AAC or MP3.)
- Merge audio and video (ensure they have the same length):
ffmpeg -y -i media/videos/script/480p15/FractalsShowcase.mp4 \
-i /tmp/bg_music.aac \
-c:v copy -c:a aac -b:a 192k -shortest \
media/videos/script/480p15/FractalsShowcase_with_music.mp4
- Optional: High‑quality render (if needed):
~/.venvs/manim/bin/manim -qh script.py FractalsShowcase
Then repeat step 6 with the higher‑resolution MP4.
Pitfalls & Gotchas
- Broadcast errors when positioning
Dot objects: always supply a 3‑element coordinate (use np.append(..., 0)).
- Malformed audio files: some downloaded MP3s from free archives may lack proper headers. Generating a tone with ffmpeg guarantees a valid track.
- Matplotlib image caching: the script checks
os.path.exists before re‑generating images, avoiding unnecessary computation.
- Manim background colour: set
self.camera.background_color = "#0D1117" for a dark‑theme consistent with other visual assets.
- Audio length mismatch: use
-shortest flag in ffmpeg to truncate the longer stream automatically.
Example script.py
"""
Famous Fractals Animated with Music
~2 min video, ~60 animations, no overlapping captions.
"""
from manim import *
import numpy as np, matplotlib.pyplot as plt, os
FRAC_DIR = "/tmp/fractals_imgs"
os.makedirs(FRAC_DIR, exist_ok=True)
Generate a short Manim video showcasing famous fractals (Mandelbrot set, Sierpinski triangle, Barnsley fern, Barnsley elephant) and add a simple background music track. The process includes on‑the‑fly generation of fractal PNGs using matplotlib, assembling them in a Manim scene, rendering, creating a clean audio track, and merging with ffmpeg.
- Confirm required inputs and credentials are available.
- Run the smallest safe command or example before scaling up.
- Check produced files, API responses, or plots before reporting success.
def save_mandelbrot(fname, width=800, height=800, max_iter=200):
xs = np.linspace(-2.0, 1.0, width)
ys = np.linspace(-1.5, 1.5, height)
X, Y = np.meshgrid(xs, ys)
C = X + 1j * Y
Z = np.zeros_like(C)
M = np.full(C.shape, True, dtype=bool)
img = np.zeros(C.shape, dtype=int)
for i (max_iter):
Z[M] = Z[M] * Z[M] + C[M]
diverged = np.greater(np.(Z), , out=np.full(C.shape, ), where=M)
img[diverged & M] = i
M[diverged] =
plt.figure(figsize=(,), dpi=)
plt.axis()
plt.imshow(img, cmap=, extent=[-,,-,])
plt.tight_layout(pad=)
plt.savefig(fname, bbox_inches=, pad_inches=)
plt.close()
():
():
depth == :
ax.fill([a[],b[],c[]],[a[],b[],c[]],color=)
:
ab = (a+b)/
bc = (b+c)/
ca = (c+a)/
triangle(ax,a,ab,ca,depth-)
triangle(ax,ab,b,bc,depth-)
triangle(ax,ca,bc,c,depth-)
fig, ax = plt.subplots()
ax.set_aspect()
ax.axis()
a=np.array([,])
b=np.array([,])
c=np.array([,np.sqrt()/])
triangle(ax,a,b,c,depth)
plt.tight_layout(pad=)
plt.savefig(fname, bbox_inches=, pad_inches=)
plt.close()
():
x=np.zeros(n); y=np.zeros(n)
i (,n):
r=np.random.random()
r<:
x[i]=; y[i]=*y[i-]
r<:
x[i]=*x[i-]+*y[i-]
y[i]= -*x[i-]+*y[i-]+
r<:
x[i]=*x[i-]-*y[i-]
y[i]=*x[i-]+*y[i-]+
:
x[i]=-*x[i-]+*y[i-]
y[i]=*x[i-]+*y[i-]+
plt.figure(figsize=(,),dpi=)
plt.scatter(x,y,s=,c=,marker=,alpha=)
plt.axis()
plt.tight_layout(pad=)
plt.savefig(fname,bbox_inches=,pad_inches=)
plt.close()
():
x=np.zeros(n); y=np.zeros(n)
i (,n):
r=np.random.random()
r<:
x[i]=; y[i]=*y[i-]
r<:
x[i]=; y[i]=*y[i-]+
r<:
x[i]=*x[i-]+*y[i-]-
y[i]= -*x[i-]+*y[i-]+
:
x[i]=*x[i-]-*y[i-]+
y[i]=*x[i-]+*y[i-]+
plt.figure(figsize=(,),dpi=)
plt.scatter(x,y,s=,c=,marker=,alpha=)
plt.axis()
plt.tight_layout(pad=)
plt.savefig(fname,bbox_inches=,pad_inches=)
plt.close()
MAN_IMG =
os.path.exists(MAN_IMG):
save_mandelbrot(MAN_IMG)
SIE_IMG =
os.path.exists(SIE_IMG):
save_sierpinski(SIE_IMG)
FERN_IMG =
os.path.exists(FERN_IMG):
save_barnsley_fern(FERN_IMG)
ELEPHANT_IMG =
os.path.exists(ELEPHANT_IMG):
save_barnsley_elephant(ELEPHANT_IMG)
():
():
.camera.background_color =
title = Text(, font_size=, color=YELLOW, weight=BOLD, font=)
.play(Write(title), run_time=)
.wait()
.play(FadeOut(title), run_time=)
.wait()
mandelbrot = ImageMobject(MAN_IMG).scale()
.play(FadeIn(mandelbrot, scale=), run_time=)
.play(mandelbrot.animate.scale().move_to([-,,]), run_time=, rate_func=linear)
.wait()
.play(FadeOut(mandelbrot, scale=), run_time=)
.wait()
():
img = ImageMobject(img_path).scale()
.play(FadeIn(img, scale=), run_time=)
.wait(hold)
.play(FadeOut(img, scale=), run_time=)
.wait()
show(SIE_IMG)
show(FERN_IMG)
show(ELEPHANT_IMG)
closing = Text(, font_size=, color=GREEN, weight=BOLD, font=)
.play(Write(closing), run_time=)
.wait()
.play(FadeOut(closing), run_time=)
The full script (including the four image‑generation functions) is stored in ~/fractals-animation/script.py.
How to Invoke the Skill
Run the skill via the Hermes CLI:
skill_manage(action='run', name='fractal-showcase-animation')
or follow the steps manually. The final video will be at:
~/fractals-animation/media/videos/script/480p15/FractalsShowcase_with_music.mp4.
Version: 1.0 (created 2026‑04‑14)
Author: Hermes (Hermi)
Maintainer: you (the user) – feel free to adjust image parameters, replace the background tone, or extend the scene with more fractals.