# OpenGraphImage — Animated cards (GIF / WebP) ← start here: [llms.txt index](https://opengraphimage.com/llms.txt) A card can render as an ANIMATED image instead of a still. It is not a separate endpoint — the same origin/template render path emits animation when the origin's `format` config option is an animated one. Two exist: gif Animated GIF. Widest support — email clients, chat, anywhere an renders. Larger files and a limited color palette. animated_webp Animated WebP. Far smaller files, full color. Best where WebP is supported; degrades to a static WebP poster where it isn't. Static formats (`png` / `jpeg` / `webp`) keep the fast single-shot render. The animated formats route through a frame-capture pipeline, so they cost more render budget — that is what the plan gate below is about. ## Enabling it Set the origin's `format` at creation or on an existing origin. Through the CLI: og origin create --template --format gif og origin create --template --format animated_webp og origin update --format animated_webp # flip an existing origin or the GraphQL `create_origin(` mutation with `format: "gif"` / `"animated_webp"` (the update mutation takes the same `format` arg). The dashboard origin editor also exposes it as a Render Format choice (with the timing controls below) once the plan allows it. Switching back to a still is the same call with a static format (`--format webp`). The plan gate below applies on every write, so a downgrade that no longer includes animation is rejected until the format is a static one. ## The plan gate Animation is a paid feature. An origin whose organization's plan does not include it is REJECTED at write time with a validation error on `format` — it is not silently downgraded at the config layer. Professional and Enterprise plans include base (Standard) animation. There are two rungs, not one: animation can this origin be animated at all (Standard budget, a 10s render ceiling). Professional + Enterprise. animation_quality a longer/smoother render budget above the 10s Standard ceiling. Enterprise only. Without it, the render budget is clamped back to Standard on save — the animation still works, it just can't exceed the Standard timing. Separately: a WATERMARKED (unpaid) origin always serves a STATIC poster — `gif` degrades to `png`, `animated_webp` to `webp`. Only an unwatermarked (paid) origin actually animates. Removing the watermark is what turns animation on for real, on top of the plan gate. ## Tuning (dashboard config editor) When the format is animated, the origin editor surfaces optional timing knobs — all default to the system value when left blank, and every value is re-clamped to the hard system ceilings at render time: Duration (ms) total length of the loop FPS frames per second (higher = smoother, more budget) Max colors GIF palette size (2–256); ignored for animated_webp Loop count 0 = loop forever; N = play N times then hold the last frame Capture strategy how frames are stepped: `scrub` (default) scrubs each CSS/JS animation frame by frame in real time; `virtual_time` fast-forwards Chrome's virtual clock deterministically (better for time-driven JS) These live in the dashboard only — the CLI/GraphQL surface just sets `format`. ## Author + verify Author the card much like a still one (see [render modes](https://opengraphimage.com/llms/render-modes.txt)) — whether output is animated is a property of the ORIGIN's `format`, not the Liquid. CSS animations / keyframes in the template are what get captured. To drive a timeline explicitly, the template declares it in the `__og` stack: window.__og = [ ['animate', { duration: 3000, fps: 12, segments: [...] }], ['capture', '#card'], ]; `['animate', {duration, fps, segments}]` sets the loop length, frame rate, and any keyframe segments; the following `['capture', selector]` bounds the output. For VIDEO, the template implements an optional async hook `window.__ogFrame(t)` that seeks a