#!/usr/bin/env bash # Turns any fly-through clip into the WebP frame sequences the scroll scene scrubs through. # Desktop: 16:9 1280x720. Mobile: centre-cropped 9:16 480x854 (portrait phones). # # Usage: scripts/make-frames.sh [frame-count=120] # Then commit public/frames/**. The site reads public/frames/manifest.json. set -euo pipefail IN=${1:?video file} COUNT=${2:-120} OUT="$(cd "$(dirname "$0")/.." && pwd)/public/frames" DUR=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$IN") FPS=$(echo "$COUNT / $DUR" | bc -l) mkdir -p "$OUT/desktop" "$OUT/mobile" find "$OUT/desktop" "$OUT/mobile" -name '*.webp' -delete TMP=$(mktemp -d) ffmpeg -loglevel error -y -i "$IN" -vf "fps=$FPS,scale=1280:720:force_original_aspect_ratio=increase,crop=1280:720" \ -frames:v "$COUNT" "$TMP/d%04d.png" ffmpeg -loglevel error -y -i "$IN" -vf "fps=$FPS,crop=ih*9/16:ih,scale=480:854" \ -frames:v "$COUNT" "$TMP/m%04d.png" # cwebp (brew install webp) — encode in parallel ls "$TMP"/d*.png | xargs -P 8 -I{} sh -c 'f={}; n=$(basename "$f" .png); cwebp -quiet -q 60 -m 6 "$f" -o "'"$OUT"'/desktop/${n#d}.webp"' ls "$TMP"/m*.png | xargs -P 8 -I{} sh -c 'f={}; n=$(basename "$f" .png); cwebp -quiet -q 58 -m 6 "$f" -o "'"$OUT"'/mobile/${n#m}.webp"' rm -r "$TMP" N=$(ls "$OUT/desktop" | wc -l | tr -d ' ') printf '{ "count": %s, "desktop": "/frames/desktop/", "mobile": "/frames/mobile/" }\n' "$N" > "$OUT/manifest.json" echo "wrote $N frames -> $OUT ($(du -sh "$OUT/desktop" | cut -f1) desktop, $(du -sh "$OUT/mobile" | cut -f1) mobile)"