@oddbits/gifbits
v0.1.1
Published
Plan animated AVIF, WebP, GIF, or PNG-sequence exports from video (ffmpeg)
Readme
@oddbits/gifbits
Crop a clip to 16:9, 1:1, or 9:16, trim it, choose an output frame rate, and export animated WebP, GIF, AVIF, or a PNG image sequence (zip of images/frame_0001.png, …). The same encode plan runs in ffmpeg.wasm on the Oddbits site or with desktop ffmpeg via the CLI.
Where formats are available
| Surface | Outputs |
| --- | --- |
| Oddbits browser workshop | Animated WebP (default), GIF, PNG zip. AVIF is not offered in wasm (AV1 is too slow for typical sessions). |
| CLI / your own ffmpeg | Defaults match the CLI (recipe / convert): AVIF is the default format there; you can also ask for WebP, GIF, or a PNG sequence recipe. |
Frame rate is explicit (fps on the encode plan, default 12). maxDimensionPx caps the longest side after crop (same idea as ImageBits maxDimension — scale=WxH:force_original_aspect_ratio=decrease). quality (1–100) controls output quality/file size tradeoff (WebP -q:v, GIF palette size, AV1 -crf) and does not change resolution by itself.
Animated AVIF needs ffmpeg built with libaom-av1. Use the CLI or a local ffmpeg build; the browser workshop does not encode AVIF.
This package does not embed ffmpeg in Node; it exports filter graphs and argv builders you can pass to ffmpeg yourself.
Oddbits desktop (browser workshop)
On the Oddbits site, open the GifBits window and use How To / ? for the in-app guide. The workshop mirrors this README: h2 + .docs-section layout (apps/web/UI_THEME.md). Encoding uses ffmpeg.wasm from @ffmpeg/core, loaded and bundled by Vite for the web app; nothing is uploaded.
Install
npm install @oddbits/gifbitsLibrary
import {
buildVideoFilterChain,
clampPlanFps,
describeRecipe,
resolveEncodeParams,
type GifBitsEncodePlan,
} from '@oddbits/gifbits';
const plan: GifBitsEncodePlan = {
cropRatio: '9:16',
trimStart: 0,
trimEnd: 6,
quality: 75,
maxDimensionPx: 1080,
fps: 15,
format: 'avif',
};
console.log(describeRecipe(plan, 'promo.mp4', 'hero.avif'));
const resolved = resolveEncodeParams(plan.quality);
const vf = buildVideoFilterChain(plan, resolved);Optional: raster Bodymovin JSON
For rare pipelines that need a minimal Bodymovin JSON over PNG assets, buildRasterLottieJson() remains exported from ./lottie-raster. It is not used by the Oddbits workshop UI (which ships PNG-only zips for image sequence).
CLI
CLI defaults: --format avif, --fps 12 (the browser workshop defaults to WebP because AV1 is slow in wasm).
Print a shell-ready ffmpeg command (no local ffmpeg required):
npx @oddbits/gifbits recipe --ratio 9:16 --start 0 --end 4.5 --format avif --quality 80 --fps 12PNG sequence recipe (no zip; bundle frames yourself or use the workshop):
npx @oddbits/gifbits recipe --format image-sequence --fps 12 --start 0 --end 3Run ffmpeg if it is on your PATH (AVIF, WebP, or GIF — not PNG zip):
npx @oddbits/gifbits convert -i clip.mp4 -o out.avif --ratio 1:1 --start 1 --end 5 --format avif --fps 15gifbits convert does not write PNG zip archives; use recipe --format image-sequence or the browser workshop for numbered PNGs.
Privacy
Planning code only; ffmpeg runs wherever you invoke it (browser wasm or your machine). Oddbits does not upload your media.
License
MIT. Bundled ffmpeg.wasm binaries used by the Oddbits web app are GPL-2.0-or-later (see project CREDITS.md).
