Skip to content

Bundle rules

A bundle is the folder of static files the overlay loads. LIGR serves it as static assets from its own CDN. Every rule on this page exists because a broadcast link is not a home connection, and because the overlay page renders your bundle over live video.

  • Ship plain browser files: HTML, CSS, JavaScript, fonts and images.
  • Name the entry file index.html, or name your entry file in the manifest.
  • Use relative paths only. If you use a build tool, set it to emit relative asset paths.
  • Do not run a server. LIGR serves your files as static assets.
  • Do not fetch JavaScript from anywhere at runtime. Bundle every module you need.
  • Ship your fonts and images inside the bundle. Do not link to an external font or image host.
  • Set the <body> background to transparent. The video shows through it.
  • Make no network call at runtime. Every asset ships inside the bundle.

Your graphic runs in a sandboxed frame with an opaque origin. It has no access to the overlay page, its cookies or its storage. Because the origin is opaque, every module script, font and file your graphic loads is a cross-origin request. LIGR serves the bundle with Access-Control-Allow-Origin: *, so files inside the bundle load. Ship only code you wrote or audited.

Lay out your graphic at the width and height of the manifest. The iframe has that exact size. The overlay scales the iframe to fit the output and keeps its aspect ratio. Your layout never changes with the output resolution. If the aspect ratio of the manifest matches the output, the graphic fills the output. If the aspect ratios differ, the scaled graphic sits at the top-left corner and leaves an empty band at the right or at the bottom.

LimitValue
One bundle10 MiB
One file5 MiB
Files per bundle request2000
Files per upload request200. Send uploadSessionId on the next request to add more files to the same session

PUT …/bundle checks the declared size of every file before it writes anything. It rejects an oversized bundle with 400 BUNDLE_TOO_LARGE and lists every file over the limit in details[].

A large bundle loads slowly and can miss the show cue. Compress images. Subset fonts. Tree-shake your JavaScript.

A file name is a path inside the bundle, for example assets/app.js. It must stay inside the bundle folder.

A name is refused with 400 INVALID_ASSET_PATH when it holds:

  • .. or an empty segment,
  • a control character,
  • one of ?, # or %.

Rename the file. A build tool that hashes file names produces valid names.

Send the content type of each file twice: as contentType when you request an upload URL, and as mime when you record the bundle. Send the same value in both places, and send the file body with that Content-Type header. Common values:

FileContent type
.htmltext/html
.jsapplication/javascript
.csstext/css
.woff2font/woff2
.pngimage/png
.svgimage/svg+xml
.jsonapplication/json

You do not need a build tool. A bundle is plain browser files, so an index.html that loads your own .js and .css is a complete graphic. The default template works this way.

If you do use one, it must write relative asset paths. Most bundlers default to absolute paths, which break when LIGR serves your bundle from a CDN sub-path.

The React template uses Vite. Vite emits absolute paths unless you set the base:

vite.config.ts
import { defineConfig } from 'vite'
export default defineConfig({ base: './' })

Run the build. It writes dist/index.html plus a dist/assets/ folder holding your JavaScript, CSS, fonts and images. Ship the whole dist/ folder.