Elements

Every element sits in a normalized box on the 16:9 canvas. Seven built-in types exist; free HTML or SVG is not allowed, because deck content reaches audience phones.

Common element fields

FieldTypeRules
idstring[A-Za-z0-9_-]{1,40}, unique in the slide. Effects (ripple, focus, zoom) target it.
type"text" | "image" | "shape" | "qr" | "icon" | "chart" | "decor"Discriminator. No other types: free HTML or SVG is not allowed.
box{ x, y, w, h }Normalized 0..1 on the 16:9 canvas, origin top-left. x + w <= 1, y + h <= 1.
fragmentinteger 1–20Optional. Element appears at that step; absent = always visible.

text

  • text: string, max 2000. \n breaks lines.
  • style (optional, all optional):
    • fontSize 8–400 (logical px on 1920x1080)
    • fontWeight 400 | 500 | 600 | 700 | 800
    • font "display" | "body" | "mono"
    • italic boolean
    • color hex
    • align "left" | "center" | "right"
    • valign "top" | "middle" | "bottom"
    • lineHeight 0.8–3
    • background hex (card fill)
    • radius 0–540 (px)
    • padding 0–200 (px)
    • card boolean: draws the preset card (surface color, radius, border, shadow). Do not combine with background or radius; let the preset decide.
    • uppercase boolean
    • tracking -0.05–0.3 (letter spacing in em; negative tightens big display type, positive opens small caps labels)
    • mark boolean: accent highlight underline behind the text. Use on one short phrase per slide.

image

  • src: https://… or assets/<path> (chars [A-Za-z0-9_\-./], no .., max 500). Local files live in decks/<id>/assets/; the CLI fails if the file is missing.
  • alt: string, required, max 300.
  • fit: "contain" | "cover" (optional).
  • style: only { radius }.

shape

  • shape: "rect" | "ellipse" | "line". A horizontal line uses h: 0.
  • style (optional): fill hex, stroke hex, strokeWidth 0–40, radius 0–540.

qr

Renders the session join QR and URL at runtime. No payload.

  • style (optional): only color and background (hex). Use a light background with dark color for scanability.
  • Put one on slide 1. Keep it at least 0.25 wide and roughly square on screen (h ≈ w × 16/9).

icon

A curated Lucide icon. The authoritative list is ICON_NAMES in shared/icons.ts (~80 kebab-case names); any other name fails validation. Check the file when unsure.

  • name: an ICON_NAMES entry, e.g. "rocket".
  • style (optional): color hex, background hex (a filled tile behind the icon), strokeWidth 1–3, radius px (rounds the background tile).
  • Default color: the preset accent, or the text color when the accent is too faint on its ground (under 3:1, e.g. yellow on light paper in brutalista). Set color only to force a specific hue.
  • Keep the box roughly square on screen: h ≈ w × 16/9 (e.g. w: 0.08, h: 0.142).

Representative names (verify against ICON_NAMES):

MeaningNames
People and talkusers, user, message-circle, heart, smile, thumbs-up, hand
Ideas and goalslightbulb, target, rocket, sparkles, trophy, flag
Data and growthbar-chart-3, trending-up, trending-down, pie-chart, database
Safetyshield-check, lock, key, alert-triangle, check-circle
Time and placeclock, calendar, map-pin, globe
Tech and workcode, cpu, cloud, zap, settings, book-open, graduation-cap

chart

Simple data chart rendered as SVG. Use it when the content has 2–8 real numbers; never invent data.

  • kind: "bar" | "donut".
  • data: array of { "label": string (max 40 chars), "value": number >= 0 }. Bar: 1–8 points, one series. Donut: 2–6 slices.
  • unit (optional): string, max 8 chars, appended to values ("%", " h", "k").
  • style (optional): only color hex (bar color; default accent). Donut uses the preset's categorical palette in fixed order.
  • Bar shows value labels on the bars and no legend. Donut shows a legend with values and the total in the center.
  • Give it room: at least w: 0.4, h: 0.5.

decor

Built-in decorative SVG shape. It carries no content: never put meaning in decor.

  • shape: "blob" | "wave" | "dots" | "rings" | "arc" | "squiggle" | "star" | "grid".
  • style (optional): color hex (default accent), opacity 0.05–1.
  • Place it before text in elements so it draws behind; keep it off the text, usually hugging a corner or an edge (boxes cannot leave the canvas). One or two per slide at most.