#!/usr/bin/env bash
# Captures App Store media from the simulator: a 25 s App Preview video per required
# device size (transcoded to Apple's exact accepted App-Preview resolution) PLUS extra
# still frames pulled from the same recording (the pattern at different moments).
#
# Apple App-Preview accepted resolutions (verified 2026-06-21):
# iPhone 6.9" -> 886 x 1920 (portrait)
# iPad 13" -> 1200 x 1600 (portrait)
# Apple TV -> 1920 x 1080 (landscape)
# Duration 15-30 s, <=30 fps, H.264 .mp4/.mov, up to 3 previews per localization.
#
# Output:
# docs/appstore/app-previews/<device>/preview.mp4 (App-Preview, exact accepted size)
# docs/appstore/screenshots/<device>/0{2,3}-*.png (extra stills at screenshot size)
#
# Requires: Xcode + simulators (6.9" iPhone Pro Max, 13" iPad Pro, Apple TV 4K), ffmpeg.
# Run ONLY when no other xcodebuild is active (concurrent builds on the same project race).
set -euo pipefail
cd "$(dirname "$0")/.."
SCHEME="Physarum"
PROJ="apple/PhysarumApp/Physarum.xcodeproj"
BUNDLE_ID="de.jkaindl.physarum"
PREV="docs/appstore/app-previews"
SHOTS="docs/appstore/screenshots"
FORM_WAIT=10 # let the Metal pattern form before recording
REC_SECS=25 # recording length (within Apple's 15-30 s window)
command -v ffmpeg >/dev/null || { echo "error: ffmpeg not found (brew install ffmpeg)" >&2; exit 1; }
( cd apple/PhysarumApp && xcodegen generate )
# args: name-pattern, dir-label, sdk, preview-WxH, screenshot-WxH
capture() {
local sim="$1" dir="$2" sdk="$3" pvW="$4" pvH="$5"
echo "==> $dir"
local udid
udid=$(xcrun simctl list devices available | grep -E "$sim" | grep -oiE '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}' | head -1 || true)
[ -n "$udid" ] || { echo "skip: no simulator matching /$sim/"; return 0; }
xcrun simctl boot "$udid" 2>/dev/null || true
xcrun simctl bootstatus "$udid" -b
local dd="${TMPDIR:-/tmp}/physarum-media-$dir"
xcodebuild -project "$PROJ" -scheme "$SCHEME" -destination "id=$udid" -derivedDataPath "$dd" build >/dev/null
local app
app=$(find "$dd/Build/Products" -name 'Physarum.app' -path "*$sdk*" | head -1)
[ -n "$app" ] || { echo "skip: no .app built for $dir"; return 0; }
xcrun simctl install "$udid" "$app"
xcrun simctl launch "$udid" "$BUNDLE_ID"
sleep "$FORM_WAIT"
mkdir -p "$PREV/$dir" "$SHOTS/$dir"
local raw="${TMPDIR:-/tmp}/physarum-raw-$dir.mov"
rm -f "$raw"
echo " recording ${REC_SECS}s…"
xcrun simctl io "$udid" recordVideo --codec=h264 --force "$raw" &
local rec=$!
sleep "$REC_SECS"
kill -INT "$rec" 2>/dev/null || true
wait "$rec" 2>/dev/null || true
# App Preview: cover-scale to the exact accepted size (no stretch), 30 fps, <=28 s, H.264.
echo " transcoding preview ${pvW}x${pvH}…"
ffmpeg -y -loglevel error -i "$raw" \
-vf "scale=${pvW}:${pvH}:force_original_aspect_ratio=increase,crop=${pvW}:${pvH},fps=30" \
-t 25 -c:v libx264 -profile:v high -pix_fmt yuv420p -movflags +faststart \
-an "$PREV/$dir/preview.mp4"
# Extra stills at native (screenshot) resolution, the pattern at two more moments.
ffmpeg -y -loglevel error -ss 5 -i "$raw" -frames:v 1 "$SHOTS/$dir/02-still.png"
ffmpeg -y -loglevel error -ss 18 -i "$raw" -frames:v 1 "$SHOTS/$dir/03-still.png"
echo " wrote $PREV/$dir/preview.mp4 + 2 extra stills"
# Report what we produced.
ffprobe -v error -select_streams v:0 -show_entries stream=width,height,codec_name -show_entries format=duration \
-of default=noprint_wrappers=1 "$PREV/$dir/preview.mp4" | sed 's/^/ /'
}
capture "iPhone 1[5-9] Pro Max" "iphone-6.9" "iphonesimulator" 886 1920
capture "iPad Pro 13-inch" "ipad-13" "iphonesimulator" 1200 1600
capture "Apple TV 4K" "appletv" "appletvsimulator" 1920 1080
echo "Done. App previews in $PREV/*/preview.mp4 (review for taste; replace/re-record as desired)."