Skip to main content

Project Structure

A Lumio extension project has this layout:

my-extension/
+-- lumio.config.json <- Extension manifest (required)
+-- package.json <- Dependencies, scripts (dev/build/deploy/typecheck/lint)
+-- tsconfig.json <- TypeScript config
+-- eslint.config.mjs <- ESLint config (double quotes enforced)
+-- CHANGELOG.md <- Release notes (optional, recommended)
+-- src/
| +-- globals.css <- Tailwind CSS entry (@import "tailwindcss") or plain CSS
| +-- editor.tsx <- Dashboard panel (sidebar in overlay editor)
| +-- layer.tsx <- Stream overlay surface (transparent)
| +-- interactive.tsx <- Audience page (optional)
| +-- assets/ <- Static assets (images, fonts, video, audio, Lottie)
| +-- logo.png
| +-- animation.lottie
+-- server/ <- Optional (server: true in config)
+-- schema.ts <- DB schema (defineTable with validators)
+-- functions.ts <- Server functions (query/mutation/action)
Styling

During lumio init, you choose your styling approach: Tailwind CSS v4 (recommended), plain CSS, or inline styles. Tailwind extensions get src/globals.css with @import "tailwindcss" and tailwindcss as a dev dependency. See lumio build for details.

lumio.config.json​

The manifest file that defines your extension. See Configuration for all fields.

{
"$schema": "https://lumio.vision/schemas/lumio.config.schema.json",
"extensionId": "88b2478a-39c7-468e-bebd-14e52fd97ac0",
"name": "My Extension",
"description": "What this extension does",
"category": "widget",
"version": "1.0.0",
"targets": ["editor", "layer"],
"server": false,
"permissions": [],
"visibility": "private",
"pricing": {
"type": "free"
}
}

The extensionId is generated when you run lumio init or create the extension in the dashboard. It must be a valid UUID that exists in the Lumio database.

src/editor.tsx​

The editor surface renders in the dashboard overlay editor sidebar. This is where users configure your extension. Every editor file must call Lumio.render() within 10 seconds of page load.

src/layer.tsx​

The layer surface renders in Browser Sources as a transparent stream overlay. Input components (buttons, toggles, text fields) are automatically read-only on this surface.

src/interactive.tsx​

The interactive surface renders on a standalone page at /ext/\{slug\}. Viewers can interact with it directly (voting, playing games). This surface is optional.

server/schema.ts​

Defines database tables for your extension using defineSchema and defineTable. Each table gets isolated storage in ext_\{extension_id\}.* PostgreSQL schemas.

server/functions.ts​

Defines server functions that run on the Lumio API. Declarative functions (queryRows, insertRow, patchRow, deleteRow) transpile to SQL. Handler-based functions (query(), mutation(), action()) run in a V8 sandbox.

CHANGELOG.md​

Optional (recommended). If present, should follow the Keep a Changelog format. lumio deploy reads the entry for the deployed version and uses it as a fallback for release notes. The primary way to write release notes is the dashboard submission wizard.