ac-native: extract boot animation renderer; macOS screenshot mode
Pulls the per-frame render loop out of ac-native.c's draw_startup_fade
into src/boot_anim.{c,h} so the Linux PID-1 init path and the macOS
host can share the same code. All Linux-only I/O (evdev key drain, TTS
greeting, boot melody, DRM present, /mnt writes) stays in the caller;
boot_anim only touches ACGraph + ACFramebuffer.
Linux side: boot_anim.c added to SRCS, draw_startup_fade now builds a
BootAnimConfig from existing state (handle, colors, city, build info,
install flags, auth badges) and calls boot_anim_render_frame each tick.
Matrix-rain state moved from inline arrays to BootAnimState.
macOS side: shared Makefile now pulls in graph.c/font.c/framebuffer.c/
color.c/qrcodegen.c alongside synth_core. New png_writer.c wraps
CoreGraphics/ImageIO for native PNG encoding. main.c gains a
screenshot branch: when AC_SHOT_PNG is set, the host skips SDL
entirely, allocates an ACFramebuffer at the requested size/density,
simulates N frames of the boot animation, upscales nearest-neighbor
for chunky retro pixels, and writes out a PNG.
Env knobs:
AC_SHOT_PNG = output path (required)
AC_SHOT_W/H = output resolution (default 1280x800)
AC_SHOT_DENSITY = internal FB divisor (default 2, clamped [1,8])
AC_SHOT_HANDLE = e.g. jeffrey -> 'hi @jeffrey'
AC_SHOT_CITY = e.g. 'Los Angeles' (default)
AC_SHOT_HOUR = 0-23, drives day/night palette (default 10)
AC_SHOT_FRAME = which boot-anim frame to capture (default last)
AC_SHOT_TITLE_SCALE = force MatrixChunky8 scale; auto-fits ~55%
of FB width when unset so product shots
don't inherit the tiny on-hardware scale
AC_SHOT_TITLE = full title override (otherwise built from HANDLE)
AC_SHOT_GIT_HASH / BUILD_TS / BUILD_NAME / DRIVER = version panel
AC_SHOT_FRESH / INSTALL / INSTALLED / CLAUDE / GITHUB = badges
Tested: 1280x800 + AC_SHOT_HANDLE=jeffrey + Los Angeles renders the
full boot screen with matrix rain, drifting triangles, rainbow title,
time bar, and city subtitle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>