whiskers.git / web / tools / preview
preview40 lines · 1.8 KB · raw
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"