1#!/usr/bin/env bash 2# Builds the link preview from the cat's own data: card.png (1200x630) and loop.mp4 (H.264, 3# yuv420p, faststart, no audio). Reproducible: the same source gives the same bytes. 4# 5# mise run web:preview (or web/tools/preview [outdir [cargo args]] with the tools of mise.toml on PATH) (default worker/public/preview) 6# 7# Extra arguments go to cargo. The preview draws the default mascot (Ginger). 8# 9# 1. previewgen writes the background, the card and every frame as SVG, from the same scene and the same tour 10# the page plays (previewgen/src/lib.rs). 11# 2. resvg rasterises them (no fonts needed: the words are drawn as pixels). 12# 3. ffmpeg encodes the frames. Metadata is stripped and the encoder told to be bit-exact, so 13# the file does not change unless the picture does. 14set -euo pipefail 15cd "$(dirname "$0")/.." 16out="${1:-worker/public/preview}" 17fps=20 18work="$(mktemp -d)" 19trap 'rm -rf "$work"' EXIT 20mkdir -p "$out" 21 22shift $(( $# > 0 ? 1 : 0 )) 23cargo run -q -p previewgen "$@" -- frames "$work" 24 25# The dot field and the pink band never change: drawn once, and laid under every frame. 26resvg "$work/background.svg" "$work/background.png" 27resvg "$work/card.svg" "$out/card.png" 28 29# One resvg process per core; each rasterises a share of the frames. 30printf '%s\n' "$work"/frame-*.svg | xargs -P "$(nproc)" -I{} sh -c 'resvg "$1" "${1%.svg}.png"' _ {} 31 32ffmpeg -v error -y -framerate "$fps" -i "$work/frame-%04d.png" \ 33 -c:v libx264 -preset veryslow -tune animation -crf 24 -profile:v high -pix_fmt yuv420p \ 34 -g $((fps * 2)) -movflags +faststart -an \ 35 -map_metadata -1 -fflags +bitexact -flags:v +bitexact \ 36 "$out/loop.mp4" 37 38# What these files were drawn from, so a later build can tell whether they are current. 39tools/preview-hash > "$out/.sources" 40ls -l "$out/card.png" "$out/loop.mp4"