image-to-video · git:20260919.28d30f9 · 2026-09-19 · sha256 2857df3fd9cb7bcc
image-to-video git:20260919.28d30f9A
Immutable. This exact content is served forever at /api/v1/blob/2857df3fd9cb7bcc.
---
name: image-to-video
promoted_to: video-editing
description: "FFmpeg-based video creation from image and audio."
user-invocable: false
allowed-tools:
- Read
- Write
- Bash
- Grep
- Glob
- Edit
routing:
triggers:
- image to video
- audio visualization
- static video
- mp4 from image
- music video
- podcast video
- video from image
- combine image audio
- album art video
- cover art video
pairs_with:
- workflow
complexity: simple
category: video-creation
---
# Image to Video Skill
Combine a static image with an audio file to produce an MP4 via FFmpeg. Supports resolution presets, audio visualization overlays, and batch processing. For image generation, use `image-gen`.
## Deep References
| Signal | Load | Why |
|---|---|---|
| FFmpeg filter graphs for visualization modes | `references/ffmpeg-filters.md` | Scale/pad, showwaves, showspectrum, overlay filters |
## Phase 1: VALIDATE
1. Check FFmpeg: `ffmpeg -version`. If missing, stop with install instructions.
2. Verify both input files exist with absolute paths and non-zero size. Supported: PNG/JPG/JPEG/GIF/WEBP/BMP (image), MP3/WAV/M4A/OGG/FLAC (audio).
3. Determine parameters from the user's request -- do not default to static when the user requested a visualization.
| Preset | Dimensions | Platform |
|--------|------------|----------|
| `1080p` | 1920x1080 | YouTube HD (default) |
| `720p` | 1280x720 | Standard HD |
| `square` | 1080x1080 | Instagram, social |
| `vertical` | 1080x1920 | Stories, Reels, TikTok |
Visualization modes (off unless requested): `waveform`, `spectrum`, `cqt`, `bars`.
**Gate**: FFmpeg installed, both files exist, parameters resolved.
## Phase 2: PREPARE
Use the user's output path or derive from audio filename (`/same/dir/filename.mp4`). Verify directory is writable.
## Phase 3: ENCODE
Defaults: libx264 preset medium, CRF 23, yuv420p, 192k AAC.
```bash
python3 $HOME/vexjoy-agent/skills/content/image-to-video/scripts/image_to_video.py \
--image /path/to/image.png --audio /path/to/audio.mp3 \
--output /path/to/output.mp4 --resolution 1080p --visualization static
```
Batch mode (matched pairs in `workspace/input/`):
```bash
python3 $HOME/vexjoy-agent/skills/content/image-to-video/scripts/image_to_video.py \
--process-workspace --visualization waveform
```
**Gate**: Script exits 0.
## Phase 4: VERIFY
FFmpeg can exit 0 but produce a corrupt file. Always probe:
```bash
ffprobe -v error -show_entries format=duration,size -show_entries stream=codec_name,width,height \
-of default=noprint_wrappers=1 /path/to/output.mp4
```
Confirm video duration matches audio (within 1s). Report: file path, size, duration, resolution, visualization mode.
## Error Handling
| Error | Cause | Solution |
|-------|-------|----------|
| FFmpeg not found | Not installed | `apt install ffmpeg` or `brew install ffmpeg` |
| Image/audio not found | Wrong or relative path | Use absolute paths; check with `ls -la` |
| FFmpeg filter errors | Minimal build lacks showwaves/showcqt | Install full FFmpeg; fall back to `--visualization static` |
| Cannot determine audio duration | Corrupted audio file | Test with `ffprobe`; convert: `ffmpeg -i input -acodec pcm_s16le output.wav` |