Install
openclaw skills install @etrobot/code2animationProduce complete code-based animated videos by scripting, generating narration, creating visual assets, and rendering final MP4s using the code2animation fra...
openclaw skills install @etrobot/code2animationA comprehensive video editing and rendering skill that enables AI agents to create code-driven animations with text-to-speech narration and smooth transitions.
This skill allows agents to:
See public/projects/agentSaasPromoVideo.json for a complete working example demonstrating all transition types and stayInClip behavior.
This skill executes the following shell commands:
npx tsx scripts/generate-audio.ts <projectId>
node scripts/render.js <projectId> [--portrait]
ffmpeg -framerate 30 -i frames/frame-%05d.jpg -c:v libx264 ...ffmpeg -i video.mp4 -i audio1.mp3 -i audio2.mp3 -filter_complex ...which command to find Chrome/Chromium on Linux/macOSPUPPETEER_EXECUTABLE_PATH environment variableThe skill may expose an HTTP endpoint for TTS generation:
POST /api/tts
Content-Type: application/json
{
"text": "Text to speak",
"voice": "en-US-GuyNeural",
"rate": "+0%",
"pitch": "+0Hz"
}
This endpoint is optional and only used when pre-generated audio files are not available.
public/projects/<projectId>/public/projects/<projectId>/audio/, public/video/execSync for: browser detection, audio generation triggerOptional configuration:
PUPPETEER_EXECUTABLE_PATH: Custom browser path for PuppeteerFASTMCP_LOG_LEVEL: Logging level (default: ERROR)public/
projects/
<projectId>/
<projectId>.json # Project configuration
footage/ # HTML/CSS media components
audio/ # Generated TTS audio files
0.mp3, 1.mp3, ...
0.json, 1.json, ... # Word timing metadata
video/
render-<projectId>-landscape.mp4
render-<projectId>-portrait.mp4
# 1. Generate audio for a project
pnpm generate-audio agentSaasPromoVideo
# 2. Preview in browser
pnpm dev
# 3. Render final video
pnpm render agentSaasPromoVideo
# 4. Render portrait version
pnpm render agentSaasPromoVideo --portrait
When creating HTML animations for video rendering, use the CSS variable timeline model.
--t every frame.DOM = f(t).play/start/reset) and no hidden runtime state.transitionIn property instead.:root { --t: 0; }
--t.--p: clamp(0, calc((var(--t) - var(--start)) / var(--duration)), 1);
t).transitionanimation / @keyframeswindow.registerFrameAnimation(...)requestAnimationFrame loops for timeline progressionDate.now() / performance.now() for visual statetransitionIn in project configopacity: var(--p) instead of opacity: calc(var(--p) * (1 - var(--fade))) to keep elements visible at their final state..element {
--start: 0.5;
--duration: 1;
--p: clamp(0, calc((var(--t) - var(--start)) / var(--duration)), 1);
opacity: var(--p);
transform: translateY(calc((1 - var(--p)) * 20px));
}
Use math on progress directly:
--p: clamp(0, calc((var(--t) - var(--start)) / var(--duration)), 1);
--ease-out: calc(1 - (1 - var(--p)) * (1 - var(--p)));
opacity: var(--ease-out);
<script>
const labels = ['A', 'B', 'C'];
const el = document.getElementById('label');
window.onTimelineUpdate = (t) => {
const idx = Math.floor(Math.max(0, t) / 1.2) % labels.length;
el.textContent = labels[idx];
};
</script>
t vs globalTime)onTimelineUpdate(t, globalTime) supports two time domains:
t: clip-local time (resets to 0 when clip changes). This is the default for most HTML animations.globalTime: continuous timeline across clips. Use only when an element must stay continuous through cross-clip transitions.t is media-local. If a media appears mid-clip, t may already be large when it first becomes visible.globalTime and derive:
local = globalTime - mediaStartGlobalTimewindow.onTimelineUpdate = (t, globalTime) => {
const g = Number.isFinite(globalTime) ? globalTime : t;
// use `t` for normal clip-local animation, `g` only when continuity is required
};
t yields exactly one deterministic frame.t = totalDuration) must remain on the last clip (no wrap to first clip).This skill executes shell commands and spawns child processes for video rendering. All operations are limited to:
No arbitrary code execution or user input is passed to shell commands. All file paths and commands are predefined and validated.