diff --git a/assets/kitty.gif b/assets/kitty.gif new file mode 100644 index 0000000..d9c6306 Binary files /dev/null and b/assets/kitty.gif differ diff --git a/tools/record-kitty.sh b/tools/record-kitty.sh new file mode 100755 index 0000000..05d7fc0 --- /dev/null +++ b/tools/record-kitty.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +source "$(dirname "${BASH_SOURCE[0]}")/record-lib.sh" + +GEOMETRY=${GEOMETRY:-1120x680} +EXAMPLE="$ROOT/examples/raytracer" +OUT="$ROOT/assets/kitty.gif" +WORK=$(mktemp -d) + +git -C "$ROOT" stash list >/dev/null 2>&1 || true +cp -a "$EXAMPLE" "$WORK/raytracer" +rm -rf "$WORK/raytracer/build" +mkdir -p "$WORK/bin" +ln -sf "$ROOT/meowc" "$WORK/bin/meowc" + +start_xvfb "$GEOMETRY" + +kitty \ + --config "$HOME/.config/kitty/kitty.conf" \ + -o remember_window_size=no \ + -o "initial_window_width=${GEOMETRY%x*}" \ + -o "initial_window_height=${GEOMETRY#*x}" \ + -o confirm_os_window_close=0 \ + --directory "$WORK/raytracer" \ + -- bash --noprofile --norc >/dev/null 2>&1 & +KITTY_PID=$! +sleep 3 + +xdotool search --sync --onlyvisible --class kitty windowactivate >/dev/null 2>&1 || true +xdotool type --delay 10 -- 'export PS1="raytracer \$ " PATH='"$WORK"'/bin:$PATH; clear' +xdotool key Return +sleep 1 + +start_capture "$GEOMETRY" "$WORK/kitty.mkv" + +send_line 'meowc build' 7 +send_line '# Nothing changed' 0.6 +send_line 'meowc build' 2.5 +send_line '# Every mtime moves, not one byte does' 0.6 +send_line 'touch src/*/*.c include/*.h' 0.8 +send_line 'meowc build' 2.5 +send_line '# Recolour a sphere in the scene description' 0.6 +send_line "sed -i 's/0.22 0.42/0.20 0.70/' scenes/studio.scene" 0.8 +send_line '# Codegen reruns, only what reads it rebuilds' 0.6 +send_line 'meowc build' 3.5 +send_line '# A comment only edit: recompiled, cascade stops' 0.6 +send_line "sed -i '1i // early cutoff' src/math/vec3.c" 0.8 +send_line 'meowc build' 3 +send_line 'meowc test' 5 + +sleep 2 +stop_capture +kill "$KITTY_PID" 2>/dev/null || true + +to_gif "$WORK/kitty.mkv" "$OUT" 11 +rm -rf "$WORK" +echo "wrote $OUT" diff --git a/tools/record-lib.sh b/tools/record-lib.sh new file mode 100755 index 0000000..882d162 --- /dev/null +++ b/tools/record-lib.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +FONT=${FONT:-JetBrainsMono Nerd Font Mono} +FPS=${FPS:-12} + +start_xvfb() { + local geometry=$1 + for n in $(seq 90 120); do + [ -e "/tmp/.X11-unix/X$n" ] && continue + DISPLAY=":$n" + Xvfb "$DISPLAY" -screen 0 "${geometry}x24" -nolisten tcp >/dev/null 2>&1 & + XVFB_PID=$! + export DISPLAY XVFB_PID + for _ in $(seq 50); do + xdotool getdisplaygeometry >/dev/null 2>&1 && return 0 + sleep 0.1 + done + kill "$XVFB_PID" 2>/dev/null || true + done + echo "no free X display" >&2 + exit 1 +} + +start_capture() { + local geometry=$1 out=$2 + ffmpeg -v error -y -f x11grab -draw_mouse 0 -framerate "$FPS" \ + -video_size "$geometry" -i "$DISPLAY" -codec:v libx264 -preset ultrafast \ + -qp 0 "$out" >/dev/null 2>&1 & + FFMPEG_PID=$! + export FFMPEG_PID + sleep 1 +} + +stop_capture() { + kill -INT "$FFMPEG_PID" 2>/dev/null || true + wait "$FFMPEG_PID" 2>/dev/null || true +} + +send_line() { + local text=$1 pause=${2:-0.9} + xdotool type --delay 42 -- "$text" + sleep 0.35 + xdotool key Return + sleep "$pause" +} + +to_gif() { + local src=$1 out=$2 fps=${3:-11} + local palette=${src%.mkv}.png + ffmpeg -v error -y -i "$src" -vf "fps=$fps,palettegen=stats_mode=diff" "$palette" + ffmpeg -v error -y -i "$src" -i "$palette" \ + -lavfi "fps=$fps[x];[x][1:v]paletteuse=dither=none:diff_mode=rectangle" \ + -loop 0 "$out" + rm -f "$palette" +} + +cleanup() { + kill "${FFMPEG_PID:-}" 2>/dev/null || true + kill "${XVFB_PID:-}" 2>/dev/null || true +} +trap cleanup EXIT