Layout Language

Glance layouts are JSON trees rendered natively on iOS. This guide covers the design system every layout and Glance AI follow — including mapping, views, and the v2 density nodes.

Design principles

  • Glanceable — one clear takeaway in under two seconds
  • Native — SF typography, semantic colors, calm density like Apple system widgets
  • One hero — every size has a single focal point (hero stat, headline, or image)
  • Intentional spacing — pick 8 / 12 / 16 pt rhythm and stick to it

Canvas sizes

SizeCanvas (pt)Safe zone inset
small170 × 17022 pt from each edge
medium364 × 17022 pt from each edge
large364 × 38222 pt from each edge

Root container padding is typically 12 pt (16 pt on airy large layouts). Use spacer with flex: 1 to push footers to the bottom on large widgets.

Bindings

SyntaxMeaning
{{field_name}}Dynamic — appears in upload form & automations
Plain stringStatic label — fixed in the layout
https://…Static image URL on image components
bag.fillSF Symbol name on icon components

Node shape

Every node is a JSON object. Containers nest children. Leaf nodes carry bindings.

FieldWhere
idRequired. Unique in the tree.
typeA registry type — 19 v1 nodes plus shape, calendar, chart, grid, table.
variantv2 nodes. Shape, calendar, chart, and grid pick a visual form here — not as a separate type.
actionPro+ family_views. set_view (another screen) or toggle_flag (same-screen reveal). XOR with href.
visibleFlagPro+. Slug on any node. Shown when that flag is true. Flags default false. Pair with toggle_flag — not a named view.
layoutContainers only: vertical | horizontal | z-stack. Not a style key.
styleOptional object. Fields depend on type — see Components.
childrenContainers and gradient only.
binding, value, label, href, …Type-specific. Static string or {{field}}.

Style

style is a static object. Extra keys are ignored. The interpreter only reads the fields listed for that type. CSS names from the web do not map over.

Ignored keyUse instead
gapspacing on container and gradient. gap is valid only on status_dot.
textAlignalignment
borderRadiuscornerRadius
backgroundColorbackground on container. backgroundColor is valid on badge, button, and avatar.
margin / flexGrow / objectFit / numberOfLinespadding, flex, contentMode, maxLines

Allowed values

  • alignmentleading | center | trailing. Containers also accept stretch.
  • fontWeightregular (default), medium, semibold, bold, light, heavy
  • fontFamilysf-pro (default), sf-rounded, sf-mono
  • contentModefill (default) | fit

Bindable style keys

Most style values are literals. These keys may also take a binding so color or a background image can change with the feed:

  • Color — background, color, fillColor, trackColor, dotColor, borderColor, gradientStart, gradientEnd, or any key ending in Color
  • URL — backgroundImage

Typography

Use sf-pro (or omit fontFamily). At most 3 font sizes and 2 weights per widget. Set maxLines: 1 on titles and hero lines in small/medium widgets.

Color

  • iOS renderer accepts 6-digit hex only (#RRGGBB) — 8-digit alpha hex is ignored
  • Primary text: #000000 or omit for system primary
  • Secondary labels: #8E8E93
  • One accent hue per widget unless the user requests a branded look
  • Color, opacity, and visible may be a map object instead of a hex or binding — see Mapping

Mapping

A closed function of a number. No JavaScript. from is {{field}}. Choose stops (interpolate) or when (first match: lt / lte / gt / gte / eq), never both. visible may only use when.

colorScale on chart, grid, and table is the same object, evaluated per bar or cell. Zero on a grid uses emptyColor.

Charts

Pro+ type: "chart" with variant bar | line | pie | candle | scatter. showAxes: true draws the plot plane (grid, Y ticks, X labels).

On bar only, showAverage: true draws a dashed line at the arithmetic mean of the current y series — use it when each bar should be judged against a typical day (weekday counts, new users, tickets). Optional averageColor (default #636366). Pair with showAxes: true. It is not a second binding or a second chart; line, pie, scatter, and candle ignore it. Web preview and the iOS Home Screen widget both paint it.

Views

Pro+ family_views is two patterns. Pick one per tap.

IntentMechanismGolden
Tap shows/hides content on the same screentoggle_flag + visibleFlag. No views map.v2-vocab-flip
Tap goes to another screenset_view + viewsv2-mission-control

tree is always home. Optional sibling views holds up to four named screens. Slugs are a-z plus digits and underscore. Reload returns home and clears flags. The next ingest keeps the current view. Discover tiles stay on home.

In-place reveal — flags default false:

{
  "action": { "type": "toggle_flag", "flag": "show_answer" },
  "children": [
    { "id": "prompt", "type": "text", "binding": "{{prompt}}" },
    { "id": "answer", "type": "text", "binding": "{{answer}}", "visibleFlag": "show_answer" }
  ]
}

Plans

Shape, mapping, and calendar are Free. Views (named screens and in-place reveal), charts, activity grids, and tables are Pro and Power — authoring only. A subscriber still sees a Pro creator's chart. Downgrade keeps rendering; the next edit that still contains a premium family 403s. bar_chart / pie_chart are invalid; use type: "chart" and a variant.

Next steps