# `SpriteSheetGenerator` _(no submodules)_ ## Purpose `SpriteSheetGenerator` renders an N×M grid of thumbnails into a single image using ffmpeg's `tile` filter. A sprite sheet is the canonical artefact for video scrubbers and timeline previews — one HTTP fetch, one decode, then arbitrary in-page hovers slide a `background- position`. The generator delegates the actual ffmpeg invocation to an injectable `FfmpegRunner` (default: `FluentFfmpegRunner` with bundled ffmpeg/ffprobe binaries) and auto-detects video duration via the runner's `probe` when the caller does not pass one explicitly. ## Features - Configurable grid: `columns`, `rows`, `thumbnailWidth`, `thumbnailHeight`, `interval`, `format`. - Auto-detection of video duration via `runner.probe` when caller omits `duration`. - Frame count is capped at `columns × rows` and at `floor(duration / interval)` — whichever is smaller — so short videos do not produce padded grids. - Zod boundary validation with code-specific failures (`INVALID_DIMENSIONS`, `FORMAT_UNSUPPORTED`, `INVALID_OPTIONS`). - OTel: `video_thumbnails.sprite_sheet.duration_ms{outcome,format}` plus `video_thumbnails.sprite_sheet.frames{format}`. - `AbortSignal` propagated through every call; aborts surface as `VIDEO_THUMBNAILS.ABORTED`. ## Usage: Basic ```ts import { SpriteSheetGenerator } from "@suaveplan/video-thumbnails/sprite-sheet"; const generator = new SpriteSheetGenerator(); const result = await generator.generate("/data/clip.mp4", "/tmp/sprite.jpg"); console.log(result.frameCount, result.columns, result.rows); ``` ## Usage: Advanced ```ts import { SpriteSheetGenerator } from "@suaveplan/video-thumbnails/sprite-sheet"; const generator = new SpriteSheetGenerator({ columns: 8, rows: 6, thumbnailWidth: 192, thumbnailHeight: 108, interval: 2, format: "jpg", }); const controller = new AbortController(); const result = await generator.generate( "/data/long-movie.mp4", "/tmp/movie-sprite.jpg", 7200, controller.signal, ); // result.width === 8 * 192, result.height === 6 * 108, result.frameCount === 48 ``` ## API Reference - `class SpriteSheetGenerator` - `constructor(config?: SpriteSheetConfigInput, runner?: FfmpegRunner)` - `generate(inputPath, outputPath, duration?, signal?): Promise` Throws `VideoThumbnailsError` on `INVALID_DIMENSIONS`, `FORMAT_UNSUPPORTED`, `INVALID_OPTIONS`, `VIDEO_INVALID`, `EXTRACT_FAILED`, `PROBE_FAILED`, or `ABORTED`. ## Implementation Notes `rows` is recomputed against the actual `frameCount` (rather than blindly using the configured upper bound) so a 5-second clip with a 10-frame grid does not produce four trailing black cells. The generator never directly invokes ffmpeg — every call routes through the supplied runner so consumers can swap in a hardware-accelerated or hosted variant without touching this class. OTel records before throwing on failure so dashboards distinguish counts from timings even on errors. `duration` is validated when passed explicitly: non-finite or non-positive values are rejected with `VIDEO_INVALID`, mirroring the probe path.