CoolFace
Apppublic

cammackflight/motif-render-service

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
App README

Motif render service

Server-side ProRes 4444 encoder for Motif. Works around the FFmpeg 6 / macOS Sonoma bug that causes client-side ProRes 4444 alpha to read as opaque in Premiere / FCP / Resolve.

The YAML frontmatter above is read by Hugging Face Spaces when this directory is pushed as a Space repo. Keep it intact even if you deploy elsewhere — it's ignored by everything that isn't HF.

Why this exists

@ffmpeg/core@0.12.10 (the latest ffmpeg.wasm) wraps FFmpeg 6.x. On macOS Sonoma 14.4+/Apple Silicon, FFmpeg 6 outputs ProRes 4444 with alpha metadata that Premiere, Final Cut, and Resolve interpret as opaque — even though the alpha is in the file (After Effects, using a different decode path, shows it correctly).

FFmpeg 7 fixes it. There's no FFmpeg 7 ffmpeg.wasm build as of April 2026. Running a real FFmpeg 7 binary on a small server does.

The service accepts PNG frames uploaded from the Motif plugin, pipes them through native FFmpeg 7, and returns the encoded .mov. Auth is piggy-backed on the main API — the service forwards Authorization: Bearer mt_* tokens to /api/library for validation.

Local dev

sh
cd render-service
npm install
# Need FFmpeg 7+ on PATH for local dev. Check with `ffmpeg -version`.
# Homebrew: `brew install ffmpeg` (currently ships 7.x on macOS).
npm run dev

The service listens on :8080 by default. Hit /healthz to smoke-test.

To point the Motif panel at a local render service, set VITE_RENDER_SERVICE_URL=http://localhost:8080 in a .env.local file in the repo root and npm run dev the main app.

Deploy (Hugging Face Spaces — recommended, free, no credit card)

Hugging Face Spaces hosts the Dockerfile for free on their CPU Basic tier (2 vCPU / 16 GB RAM, plenty for ffmpeg). No credit card required at any point. The service stays running for hours of inactivity before sleeping; cold-start wake is a few seconds.

One-time setup

  1. 1.Sign up at https://huggingface.co/join — just email + password, no payment info ever requested.
  2. 2.Create a new Space: https://huggingface.co/new-space
  3. 3.Space name: motif-render-service (or anything; it becomes part of the URL)
  4. 4.License: pick whatever (e.g. MIT)
  5. 5.SDK: select Docker → "Blank" template
  6. 6.Hardware: leave on the default free CPU Basic
  7. 7.Visibility: Public is fine (the service has its own bearer-token auth — random callers will be 401'd)
  8. 8.Click Create Space
  9. 9.Push this directory's contents to the Space's git repo:
sh
   cd render-service
   # Initialize a git repo here (separate from the main motif repo's git).
   # The HF Space is its own repo at huggingface.co/spaces/<your-username>/<space-name>.
   git init
   git remote add hf https://huggingface.co/spaces/<your-username>/motif-render-service
   git add .
   git commit -m "Initial render service"
   git push hf main

When git asks for credentials, use your HF username + a write-scope access token from https://huggingface.co/settings/tokens (NOT your account password — HF deprecated password auth).

  1. 1.HF auto-builds the Dockerfile (5-10 min the first time — it's downloading FFmpeg 7). Watch progress on the Space page.
  2. 2.When the build succeeds, the Space URL becomes live: https://<your-username>-motif-render-service.hf.space
  3. 3.Smoke-test:
sh
   curl https://<your-username>-motif-render-service.hf.space/healthz
   # expect: {"ok":true,"ffmpeg":"ffmpeg"}

Wire it into Vercel

In Vercel → motif project → Settings → Environment Variables:

VITE_RENDER_SERVICE_URL = https://<your-username>-motif-render-service.hf.space

Then Deployments tab → … on latest deploy → Redeploy so the env var bakes into the build.

Future updates

Edit code in render-service/, then:

sh
cd render-service
git add .
git commit -m "Whatever"
git push hf main

HF auto-rebuilds. ~3-5 min later the new version is live.


Alternate deploys

Fly.io (requires credit card)

Has the same Dockerfile, Fly's wake-from-cold is faster than HF, and pricing is genuinely free under the trial allowance. But signup requires a credit card.

sh
brew install flyctl
fly auth signup
cd render-service
fly launch --copy-config --no-deploy
fly deploy

The committed fly.toml is set up for this.

Anywhere else with Docker support

Any Docker host works — the Dockerfile pulls FFmpeg 7 from BtbN's builds so no apt-installed FFmpeg 6 creeps in. Just point it at the directory and run.

Deploying elsewhere

Any Docker host works — the Dockerfile pulls FFmpeg 7 from BtbN's builds so no apt-installed FFmpeg 6 creeps in. Environment variables the service reads:

VarDefaultWhat
PORT8080HTTP port
FFMPEG_PATHffmpegPath to the FFmpeg binary. Leave unset if it's on PATH.
MOTIF_API_BASEhttps://motif-silk.vercel.appMain API base used for token validation.
MAX_UPLOAD_MB500Multipart upload ceiling.

API

POST /render

Multipart form data:

  • —Authorization: Bearer mt_* (required) — same tokens the rest of the plugin uses.
  • —settings (text field) — JSON { fps: number, quality?: number }.
  • —frames (file field, repeated) — PNG files named f000000.png, f000001.png, … Zero-padded 6-digit sequential indices.

Response:

  • —200 OK with Content-Type: video/quicktime — the encoded .mov bytes. Header X-Render-Ms reports encode wall clock.
  • —401 Unauthorized — missing / invalid / revoked bearer token.
  • —400 Bad Request — missing/malformed settings or frames.
  • —500 Internal Server Error — ffmpeg exited non-zero. Error message includes the tail of ffmpeg stderr.

GET /healthz

Returns { ok: true, ffmpeg: "<path>" }. Used by Fly.io's health check.

Cost ballpark

Fly.io shared-cpu-2x with 2 GB RAM, auto_stop_machines = "stop", min_machines_running = 0: pays only for actual render time plus ~10s wake-up. A 30s-render/day tester usage pattern costs under $1/month.

cammackflight/motif-render-service · CoolFace