Animated link previews from a URL

Point your page's og:video at an og.video URL. The video renders at the edge on the first view, streams out faster than it plays, and is cached for every view after that.

https://og.video/kinetic.mp4?text=Every+link+deserves+a+*moving+picture*&by=og.video

How it works

No headless browser. Each scenario is a small program that draws frames with a Rust compositor and encodes them with x264, both compiled to WebAssembly and running inside a Cloudflare Worker.

Starts instantlyThe opening seconds are encoded ahead of time and sent before any rendering starts.
Streams faster than it playsThe rest renders frame by frame and goes out as it is encoded, usually 10 to 30 times faster than realtime.
Renders onceEach distinct video is stored in R2 and the edge cache, so later views cost a cache read.

Scenarios

Change the fields to build a URL. Fields left at their default stay out of the URL.

/kinetic

1200x630, 7 s

/title-card

1200x630, 7 s

/diagram

1200x630, 7 s

/metric

1200x630, 7 s

/bars

1200x630, 7 s

/release

1200x630, 7 s

API

GET  /<scenario>.mp4?<params>    the video (H.264 MP4, streamed)
GET  /<scenario>.png?<params>    the last frame, for og:image
GET  /<scenario>?<params>        a share page with og:video tags
GET  /<scenario>.json?<params>   resolved params, content id, packed URL
POST /<scenario>                 JSON params in, a short /<scenario>/<id>.mp4 out

Arrays and objects go in the query string as JSON, or packed into ?s=. For long params, POST them once and use the short URL. Renders that miss the cache are rate limited per address.

<meta property="og:video" content="https://og.video/kinetic.mp4?title=Hello">
<meta property="og:video:type" content="video/mp4">
<meta property="og:video:width" content="1200">
<meta property="og:video:height" content="630">
<meta property="og:image" content="https://og.video/kinetic.png?title=Hello">