Skip to content

Instantly share code, notes, and snippets.

@arenagroove
Last active May 15, 2025 05:05
Show Gist options
  • Select an option

  • Save arenagroove/909b39246d6fc648f28c42e2a78f5d4a to your computer and use it in GitHub Desktop.

Select an option

Save arenagroove/909b39246d6fc648f28c42e2a78f5d4a to your computer and use it in GitHub Desktop.
A PowerShell script that pulls evenly spaced frames from a video or GIF and arranges them into a single image strip, either horizontal or vertical. You can resize the frames, adjust spacing between them, and optionally convert the result to WebP. It can also generate a JSON file with metadata. Useful for web-based sprite animations, like CSS zoe…

FFmpeg Sprite Generator — PowerShell Script

Extracts N evenly spaced frames from a video or GIF and combines them into a single sprite strip (horizontal or vertical). Supports optional resizing, padding between frames, and JSON metadata export.

Features:

  • Automatically detects media type (GIF or video)
  • Supports frame-accurate or keyframe-based seeking
  • Optional resizing with -ResizeTo
  • Adjustable padding between frames via -TilePadding
  • JSON metadata export
  • Preserves transparency (PNG/WebP)

Usage Examples:

From GIF (horizontal layout by default)

.\ffmpeg-sprite-generator.ps1 -InputFile "horse.gif" -Duration 1.5 -NumFrames 24

From MP4, vertical layout, resized, with spacing

.\ffmpeg-sprite-generator.ps1 -InputFile "video.mp4" -StartTime 48 -Duration 4 ` -NumFrames 24 -Layout "vertical" -ResizeTo "480x270" -TilePadding 6

Works with CSS/JS sprite-based animation systems. Example: https://codepen.io/luis-lessrain/pen/pvzKgdY

param(
[string]$InputFile = "input.mp4", # Input file (GIF or video)
[double]$StartTime = 48, # Start time for video input
[double]$Duration = 4, # Duration to sample
[int]$NumFrames = 24, # Number of frames to extract
[string]$OutputPrefix = "output_strip", # Base name for output files
[ValidateSet("horizontal", "vertical")]
[string]$Layout = "horizontal", # Layout direction
[string]$ResizeTo = "", # Optional: scale output (e.g. "480x270")
[int]$TilePadding = 0 # Optional: spacing between frames (px)
)
# Auto-detect input type
$IsGif = $InputFile.ToLower().EndsWith(".gif")
$OutputPNG = "$OutputPrefix.png"
$OutputWebP = "$OutputPrefix.webp"
$OutputJSON = "$OutputPrefix.json"
$FrameInterval = [math]::Round($Duration / $NumFrames, 4)
# Log configuration
Write-Output "`n🔧 Sprite Generation Configuration"
Write-Output " Input file: $InputFile"
if ($IsGif) {
Write-Output " Detected as: GIF"
} else {
Write-Output " Detected as: Video"
}
Write-Output " Start time: $StartTime"
Write-Output " Duration: $Duration"
Write-Output " Num frames: $NumFrames"
Write-Output " Frame every: $FrameInterval s"
Write-Output " Layout: $Layout"
Write-Output " Resize to: $ResizeTo"
Write-Output " Tile padding: $TilePadding px"
Write-Output ""
# Clean old frames
Remove-Item -ErrorAction Ignore frame_*.png
# Frame extraction
if ($IsGif) {
# Frame-accurate seek for GIFs
ffmpeg -i $InputFile -ss $StartTime -t $Duration -vf "fps=1/$FrameInterval" -vframes $NumFrames frame_%04d.png
} else {
# Keyframe-aligned seek for video
ffmpeg -ss $StartTime -i $InputFile -t $Duration -vf "fps=1/$FrameInterval" -vframes $NumFrames frame_%04d.png
}
# Construct tile filter
$TileBase = if ($Layout -eq "horizontal") { "${NumFrames}x1" } else { "1x${NumFrames}" }
$TileFilter = "tile=$TileBase"
if ($TilePadding -gt 0) {
$TileFilter += ":padding=$TilePadding"
}
# Optional resize
$ResizeFilter = if ($ResizeTo -ne "") { ",scale=$ResizeTo" } else { "" }
# Generate PNG sprite strip
ffmpeg -i frame_%04d.png -vf "$TileFilter$ResizeFilter" -frames:v 1 $OutputPNG
# Generate WebP sprite
ffmpeg -i $OutputPNG -c:v libwebp -lossless 1 -qscale 100 -preset default $OutputWebP
# Clean temp frames
Remove-Item frame_*.png
# Export metadata
$Metadata = @{
input = $InputFile
startTime = $StartTime
duration = $Duration
numFrames = $NumFrames
frameEvery = $FrameInterval
layout = $Layout
size = if ($ResizeTo -ne "") { $ResizeTo } else { "original" }
spacing = $TilePadding
outputPNG = $OutputPNG
outputWebP = $OutputWebP
timestamp = (Get-Date).ToString("s")
}
$Metadata | ConvertTo-Json -Depth 3 | Out-File $OutputJSON -Encoding UTF8
# Done
Write-Output "`n✅ Sprite strip generated:"
Write-Output " PNG: $OutputPNG"
Write-Output " WebP: $OutputWebP"
Write-Output " JSON: $OutputJSON"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment