- TypeScript 98.3%
- CSS 1.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .zed | ||
| public | ||
| src | ||
| .cta.json | ||
| .gitignore | ||
| .oxfmtrc.json | ||
| bun.lock | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| tsr.config.json | ||
| vite.config.ts | ||
| worker-configuration.d.ts | ||
| wrangler.jsonc | ||
gifslop
A small TanStack Start app that converts MOV/MP4 videos to GIFs entirely in the browser.
Why client-side?
For a small, occasional-use app this is the simplest and most private architecture:
- video bytes never leave the device
- no upload storage, job queue, or conversion server to operate
- static/serverless-friendly deployment
The app reads only the required parts of the file with Mediabunny, decodes frames with the browser's native WebCodecs implementation, and encodes them in a small gifenc worker pool. High color builds a stable 256-color palette from representative frames across the clip and applies ordered Bayer dithering, closely matching the previous FFmpeg palette pipeline. Balanced uses a 256-color RGB565 palette per frame; Fast uses a smaller 64-color RGB444 palette. The video remains on the device throughout.
Browser and operating-system codec support varies. Videos that cannot be decoded through WebCodecs are reported as unsupported.
The homepage is prerendered by TanStack Start and served through Cloudflare's static asset layer. Width, frame rate, and color mode are validated URL search parameters, so conversion presets can be bookmarked without storing user data.
Develop
bun install
bun --bun run dev
Code quality
The project uses the Oxc toolchain:
bun run format
bun run lint
bun run typecheck
bun run check
Deploy to Cloudflare Workers
The app uses Cloudflare's official Vite plugin with TanStack Start's Worker entrypoint.
bunx wrangler login
bun run deploy
Generate binding types after adding Cloudflare bindings to wrangler.jsonc:
bun run cf-typegen
The editor defaults to five seconds and limits conversions to 30 seconds so a long compressed source cannot create an unbounded browser workload.