← The Bench
LOG 014·Jul 2026·Prototype

Data-Bound Video

A promo video that never goes stale. The footage is rendered once; the numbers on top of it stay current on their own. One production cost, no re-renders, ever.

BAKED RENDER · 16:9 · 30FPS
$59
240 left
LAUNCH WEEK
14:02:00
● LIVE · polling every 2s

Same footage. The price, stock, offer, and timestamp are being polled live and composited into the render right now — no re-export.

Open the full-screen demo ↗

01The problem

A product promo is out of date the moment it renders. The price in the video is whatever it was on export day. Stock counts, launch offers, countdowns — all frozen in the file. The fix is usually a re-export, or a careful edit to avoid ever showing a number. Both are expensive, and neither scales past a handful of variants.

02The idea

Separate the render from the data. Bake the footage once — motion, lighting, brand, everything expensive. Then declare, in a small manifest, which rectangles of the frame are data-bound and where their values come from. A thin player draws the baked footage every frame and composites the live values into those regions on top, frame-synced to the render.

The value lives in the toggle above. As baked is what a normal exported video shows forever. Live data is the same footage with the numbers polled fresh. Same pixels of footage, always current data.

03How the binding works

Everything the player needs is declarative. Regions are positioned in fractional coordinates (0–1 of the frame), so a binding survives any export size — 1080p, a 9:16 crop, a retina still. Each region names a bind path into a polled source and a format so values render correctly without per-video code.

Turn on Inspect regions in the demo to see the four bound boxes outlined on the frame, each labelled with its live bind path and resolved value.

04What’s built

This is a working proof-of-concept, not a product: a canvas-rendered stand-in for the baked footage, a mock inventory endpoint whose values drift each poll, a live/stale toggle, and a region inspector. The next steps are real video decode as the baked layer, a signed manifest format, and an editor to place regions visually instead of by hand.

05Source

The demo runs on the exact objects below — nothing is illustrative-only. The manifest is the whole contract; the player is a few dozen lines around it.

manifest.json — the binding contract
the-bench/data-bound-video/manifest.ts
{
  "render": {
    "width": 1280,
    "height": 720,
    "fps": 30,
    "bakedAt": "2026-06-28T14:02:00Z"
  },
  "sources": [
    {
      "id": "inventory",
      "url": "https://api.example-store.com/v1/product/AC-118/inventory",
      "pollMs": 2000
    }
  ],
  "regions": [
    {
      "id": "price",
      "label": "Price",
      "bind": "inventory.price",
      "format": "usd",
      "kind": "headline",
      "align": "left",
      "box": {
        "x": 0.06,
        "y": 0.63,
        "w": 0.34,
        "h": 0.18
      }
    },
    {
      "id": "stock",
      "label": "In stock",
      "bind": "inventory.stock",
      "format": "count",
      "kind": "pill",
      "align": "left",
      "box": {
        "x": 0.06,
        "y": 0.83,
        "w": 0.3,
        "h": 0.08
      }
    },
    {
      "id": "offer",
      "label": "Offer",
      "bind": "inventory.offer",
      "format": "text",
      "kind": "badge",
      "align": "center",
      "box": {
        "x": 0.7,
        "y": 0.08,
        "w": 0.24,
        "h": 0.1
      }
    },
    {
      "id": "updated",
      "label": "Updated",
      "bind": "inventory.updatedAt",
      "format": "time",
      "kind": "caption",
      "align": "right",
      "box": {
        "x": 0.62,
        "y": 0.9,
        "w": 0.32,
        "h": 0.06
      }
    }
  ]
}
player — bind + composite loop (excerpt)
watch-time compositing
// Bind live data into a baked render, frame-synced.
const store = { ...bakedSnapshot };            // frozen values baked into the footage
const timers = manifest.sources.map((src) =>
  setInterval(async () => {
    if (mode !== 'live') return;                // 'stale' shows what was baked
    Object.assign(store, await fetch(src.url).then((r) => r.json()));
  }, src.pollMs),
);

// Each frame: draw baked footage, then composite bound regions on top.
function drawFrame(t) {
  drawBakedFootage(ctx, t);                     // the pre-rendered layer
  for (const region of manifest.regions) {
    const value = resolveBind(store, region.bind);
    paintRegion(ctx, region, formatValue(value, region.format));
  }
}
The Bench · LOG 014Bench No. 2308