wheelofnames
Self-hosted API that renders wheel-of-names GIF animations with Remotion.
API
POST /api/gif
Content-Type: application/json
Accept: image/gif
Authorization: Bearer change-me
{
"options": ["alice", "bob", "carol"],
"winnerIndex": 1,
"durationMs": 6500,
"holdMs": 1200,
"fps": 15,
"size": 512,
"theme": "classic"
}
Response is image/gif with winner metadata headers:
X-Wheel-Winner-IndexX-Wheel-WinnerX-Render-Duration-Ms
X-Wheel-Winner is URL-encoded so non-ASCII labels are safe in HTTP headers.
Local
Install dependencies and Chromium once:
pnpm install
pnpm browser:ensure
Start the local API:
pnpm dev
Generate GIF files locally
Generate the quick smoke fixture at the git-ignored path
fixtures/smoke.gif:
pnpm render:smoke
Generate the complete fixture set at fixtures/smoke.gif,
fixtures/vietnamese.gif, and fixtures/sixteen-options.gif:
pnpm render:fixtures
For a custom GIF, keep pnpm dev running in one terminal, then run one of
these commands in another.
PowerShell:
$body = @{
options = @("Chiều nay uống CraneTea", "Chiều nay uống CraneTea", "Chiều nay uống CraneTea", "Chiều nay uống CraneTea")
winnerIndex = 1
durationMs = 6500
holdMs = 1200
fps = 15
size = 512
theme = "classic"
} | ConvertTo-Json
Invoke-WebRequest -Method Post -Uri http://localhost:3000/api/gif -ContentType "application/json" -Body $body -OutFile wheel.gif
macOS, Linux, or Git Bash:
curl --request POST http://localhost:3000/api/gif \
--header "Content-Type: application/json" \
--output wheel.gif \
--data '{"options":["Chiều nay uống CraneTea","Chiều nay uống CraneTea","Chiều nay uống CraneTea","Chiều nay uống CraneTea"],"winnerIndex":1,"durationMs":6500,"holdMs":1200,"fps":15,"size":512,"theme":"classic"}'
The local API does not need an authorization header by default. If you
configure API_TOKEN, add --header "Authorization: Bearer <token>" to the
request. Generated GIF files are git-ignored and safe to delete.
Verify
Run the API smoke test and quality gates:
pnpm api:smoke
pnpm lint
pnpm typecheck
pnpm test
Deploy
Use a container runtime first. Static-only platforms cannot satisfy
POST /api/gif because Remotion server rendering needs Node, Chromium/runtime
dependencies, and FFmpeg/compositor support.
docker build -t wheelofnames .
docker run --rm -p 3000:3000 -e API_TOKEN=change-me wheelofnames
Recommended starting resources: 1-2 vCPU and 1-2 GB RAM, with
MAX_CONCURRENT_RENDERS=1. RENDER_TIMEOUT_MS defaults to 15000 and is
raised to Remotion's 7000ms browser timeout floor when configured lower.
API_TOKEN is required when NODE_ENV=production.