# Reel Animator

> Use when rendering animated reel elements (kinetic typography, parcel-outline draw-on, price-bar race, loop-seam morph) for the animated_bolt32/kinetic_bolt32 edit styles (CMO Factory CP3c, issue

- Skill: `breverdbidder/reel-animator` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add breverdbidder/reel-animator`
- Raw SKILL.md: https://api.skillmd.com/api/skills/breverdbidder/reel-animator/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Design & Media
- Author: breverdbidder (https://skillmd.com/u/breverdbidder)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/breverdbidder/reel-animator

---


# Reel Animator

## Role
Own animated reel-element rendering as a budgeted, seeded, evidence-logged pipeline, not a black-box video call.

## Working Mode
Pick primary engine (revideo, MIT license, recorded reason in agents/reel_studio/animator.py) -> attempt real render within a 90s/element budget -> on failure/timeout, fall back to a deterministic seeded ffmpeg render (labeled kinetic-only, per the issue's own fallback semantics) -> on that failing too, fall back to a minimal static-hold clip -> upload to Supabase Storage -> record engine used + actual seconds, never fabricated.

## Focus Areas
1. Engine choice is recorded, not assumed -- revideo chosen for its Node-native renderer API (headless-CI-friendly); motion-canvas's own docs center an interactive editor first
2. Hard 90s/element budget -- enforced via subprocess timeout, not a soft guideline; over-budget always falls back and logs `fallback_reason`
3. Determinism -- every render is seeded (per-property/per-element integer seed), not randomized, so a re-run is reproducible
4. Brand tokens -- Navy #1E3A5F background, Amber #F59E0B accent text, Inter/DejaVu Sans Bold fallback via the same `_ensure_font()` v1/v2 biddeed_reels pipelines already use (not reinvented)
5. Four beat-slot elements only -- kinetic_hook (0-2s), parcel_outline_drawon (2-8s), price_bar_race (20-28s), loop_seam_morph (31-32s) -- matches the bolt32 assembler's slots
6. Honest fallback labeling -- the ffmpeg fallback is explicitly documented as a simplified stand-in for true canvas-drawn animation, never presented as animated_bolt32 final quality
7. Zero frame drops -- every render is ffprobe-verified against its expected duration before being counted as a pass
8. Storage, not local disk -- every successful render is uploaded via biddeed_reels_lib.storage_upload; nothing is left only in /tmp

## Quality Gates
- verify: every reported render includes engine, seconds, budget_ok (bool), and either a storage url or an explicit failure reason
- confirm: render seconds are wall-clock measured (time.time() around the actual subprocess call), never estimated
- check: ffprobe duration on the output file matches the element's expected duration (kinetic_hook=2.0s, parcel_outline_drawon=6.0s, price_bar_race=8.0s, loop_seam_morph=1.0s)
- ensure: an over-budget or failed primary-engine attempt always falls back rather than raising an unhandled exception
- call_out: if the primary engine (revideo) cannot run in this environment (e.g. no scaffolded project / no TTY for its CLI), say so explicitly rather than silently always using the fallback

## Output Format
JSON list of {element, engine, seconds, budget_ok, uploaded, url, ffprobe_duration_s, reason}.

## Constraints
- NEVER exceed the 90s/element render budget without falling back
- NEVER report a render as animated_bolt32-quality when the fallback path (ffmpeg kinetic-only or static-hold) was actually used -- report the real `engine` value
- Reuse scripts/biddeed_reels_lib.py's `_ensure_font`/`_ffprobe_duration`/`_escape_drawtext`/`storage_upload` -- do not reimplement font handling or storage upload

## Guard Rail
Do not upload or count a render whose ffprobe duration does not match the element's expected duration -- a silently truncated/corrupt clip is a failure, not a pass.

