| name | webalgos-reel |
| description | Build an animated coding-pattern reel (MP4) for HackProduct / WebAlgos. Teaches interview patterns — Two Pointers, Sliding Window, Binary Search, BFS/DFS, DP, and more — through motion and sound, designed to build AI-engineering judgment, not just memorization. Use this skill whenever Raja asks to build, render, or re-render a pattern reel, says "do the next pattern", "make a reel for X", "dark mode video", or anything involving producing an MP4 animation that teaches a coding pattern. Covers the full pipeline: Pillow frame rendering → procedural audio → ffmpeg H.264 MP4, always in dark mode, always 24fps 1080×1920. |
WebAlgos Reel Builder
Part of HackProduct — the AI-native practice system for product and technical judgment.
Build one animated dark-mode reel per pattern. Each reel is a self-contained Python script that generates a PNG frame sequence, procedural WAV audio, and encodes them into a final MP4 via ffmpeg. The goal: a viewer who knows nothing should understand the pattern in 45 seconds, and leave thinking about how they'd evaluate AI-generated code using it — not just how to write it.
Spec (non-negotiable)
- Resolution: 1080 × 1920 px (portrait, Instagram Reels)
- Frame rate: 24 fps
- Duration: 14–18 s (330–430 frames)
- Audio: Stereo AAC 192 kbps, 44100 Hz
- Codec: H.264 CRF 18, yuv420p
- Mode: Dark mode always — use the palette below, never light backgrounds
- Output: single
.mp4 file, named <pattern>-reel.mp4 in the WebAlgos workspace
Dark Palette (use exactly these values)
BG = (13, 14, 18)
PANEL = (22, 24, 30)
PANEL2 = (28, 31, 39)
INK = (232, 235, 240)
MUTED = (120, 128, 140)
FAINT = (70, 76, 86)
TEAL = (61, 220, 151)
YEL = (245, 197, 66)
CORAL = (240, 120, 80)
GREEN = (100, 220, 120)
CELLBG = (30, 33, 41)
CELLBR = (48, 52, 63)
SLATE = (107, 122, 153)
Script Architecture
Every render script follows the same structure. Read references/template.py for the full annotated template.
1 — SEGS table
Define the animation as a list of named segments:
SEGS = [
("fn", 48, "soft"),
("init", 50, "tuk"),
("step1", 40, "ping"),
("ret", 55, "chime"),
]
Each entry: (name, frame_count, audio_event).
Audio events: soft (intro), tuk (pointer move), ping (comparison), chime (match/result).
Target total: 330–430 frames.
2 — Audio pipeline
Use the procedural audio template — four-chord pad loop (Cmaj7→Am7→Fmaj7→G) + arpeggio sparkle + per-event tones. Events fire at SEG[name] / FPS seconds.
def at(seg): return SEG[seg] / FPS
soft(at("fn"))
tuk(at("init"))
ping(at("step1"))
chime(at("ret"))
See references/template.py → build_audio() for the full tone definitions (soft / tuk / ping / chime oscillators).
3 — Frame rendering
Critical — save frames immediately, never accumulate:
fi = [0]
def save(img):
img.save(f"{OUT}/f{fi[0]:05d}.png"); fi[0] += 1
Accumulating PIL images causes OOM at ~400 frames × 6 MB each.
Two helpers:
def hold(args, n, pulse_anim=False):
def slide_ptr(from_state, to_state, n):
Use ease(t) = 3t²–2t³ for all pointer interpolation.
4 — Frame layout (vertical zones, top to bottom)
| Zone | Y range | Content |
|---|
| Header | 80–270 | CODE · MOTION label, pattern title, teal underline |
| Problem | 290–520 | "THE PROBLEM" label, 2 description lines, target/k chip |
| Pointers | 640–750 | Pointer chips (triangle label → arrow tip) |
| Array cells | 760–920 | CY=760, CH=138, cell width varies by N |
| Index row | 920–960 | Small index labels below each cell |
| Info strip | 998–1050 | Current comparison / mid / result — PANEL2 rounded rect |
| Caption | 1072+ | 1–3 lines, 48px line height, f_cap size 37 |
| Code panel | 1230+ | Syntax-highlighted code with active-line highlight |
| Brand | H-80 | hackproduct · webalgos in FAINT |
Spacing rule: Info strip ends at y=1050. Caption centers start at y=1072. Code panel starts at y=1230. This gives clean 22px and 180px gaps — never overlap these zones.
5 — Code panel
CODE_Y0 = 1230
CODE_LH = 46
CODE_PAD = 26
Always include:
- Traffic-light dots: red
(237,106,94), yellow (245,197,66), green (61,220,151) at top-left of panel
- Line numbers in
FAINT using f_ln (size 24 mono)
- Active line:
PANEL2-ish background rect + TEAL left-edge bar (7px wide)
- Syntax highlighting: keywords in
(198,160,230) purple, numbers in (180,220,160) green, operators/punctuation in (150,158,172) grey, identifiers in INK
- Active-line text rendered in bold (
f_codeb), inactive in regular (f_code)
6 — Pointer chips
Chips sit above the cell array (py = CY - 68). Each chip = rounded rect + label + downward triangle arrow.
def chip(d, idx_f, color, label):
px = X0 + idx_f * (CW + GAP) + CW / 2
py = CY - 68
bw = d.textlength(label, font=f_ptr) + 30
rr(d, [px-bw/2, py-24, px+bw/2, py+24], 11, color)
d.text((px, py), label, font=f_ptr, fill=(13,14,18), anchor="mm")
d.polygon([(px-9,py+24),(px+9,py+24),(px,py+40)], fill=color)
Standard pointer colors: L=TEAL, R=YEL, M=CORAL (GREEN on match).
For sliding window: use a bracket (U-shape below cells) instead of chips — no L/R labels since the algorithm uses i and i-k, not named L/R pointers.
7 — ffmpeg encode
ffmpeg -y -framerate 24 -i {OUT}/f%05d.png \
-i /tmp/{name}_audio.wav \
-c:v libx264 -pix_fmt yuv420p -crf 18 \
-c:a aac -b:a 192k -shortest \
/path/to/WebAlgos/{name}-reel.mp4
Pattern-Specific Design Notes
Two Pointers
- L pointer (TEAL, left), R pointer (YEL, right) close in from both ends
- Show "L and R close in" caption clearly; highlight the
while l < r line when active
- Use
slide_ptr to animate L moving right or R moving left
Sliding Window
- No L/R pointer chips. Use a U-shaped bracket below the cells spanning k elements
- Show
enters → (green pill) above the entering cell, ← exits (red pill) above the exiting cell
- Current sum in the info strip; highlight when new max is found
Binary Search
- Three chips: L (TEAL), R (YEL), M (CORAL → GREEN on match)
- Show info strip:
mid = N nums[N] = V during comparison, then V == target → found on match
- Pulse the match cell using
sc = 1.0 + 0.05 * pulse for 65 frames with pulse_anim=True
Fast & Slow Pointers (planned)
- Slow (TEAL, 1 step), Fast (YEL, 2 steps) on a linked-list node chain
- Circular layout or linear; highlight node on collision
Caption (Instagram)
Write after the reel renders. Format:
- Hook sentence (pattern name, what it does differently)
- Real-world analogy (2–3 sentences)
- What the animation shows (1 sentence)
- AI-engineer angle: what to check when a model writes this pattern, common bugs models make
- Forward hook question: "Which pattern next?"
- Tags:
#HackProduct #codevisuals #coding #visuals #algorithms
Target: 650–900 characters. Deliver as a copy-paste HTML widget (dark background, teal copy button, char counter).
Fonts
All from /usr/share/fonts/truetype/dejavu/:
DejaVuSansMono-Bold.ttf — title (80), cell values (54), summary strip (50), ptr chips (30)
DejaVuSansMono.ttf — label (28), index (24), brand (26), code (30), line numbers (24)
DejaVuSans-Oblique.ttf — subtitle (33)
DejaVuSans.ttf — problem text (35), caption (37)
DejaVuSans-Bold.ttf — problem bold (35)
Definition of Done
- Script runs without error, prints
FRAMES N dur@24fps = Xs and Done → <name>-reel.mp4
- Review text layout: info strip (ends ≤1050) → caption (starts ≥1072) → code (starts ≥1230) — no overlaps
- Audio plays: ambient pad audible, events fire at the right moments
- MP4 plays cleanly in QuickTime / browser
- File saved to
/Users/rb-home/Documents/Claude/Projects/WebAlgos/