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
| Size | Canvas (pt) | Safe zone inset |
|---|---|---|
| small | 170 × 170 | 22 pt from each edge |
| medium | 364 × 170 | 22 pt from each edge |
| large | 364 × 382 | 22 pt from each edge |
| extra_large | 378 × 611.3 | 20.2 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. extra_large is the iOS 27 portrait page. Its inset is 20.2 pt, the corner measured on the iPhone 18 Pro Max. The other sizes stay at 22 pt. Use the extra height as more than one region. A large layout scaled up does not fill the page. The reference layout is xl-morning-brief.
Bindings
| Syntax | Meaning |
|---|---|
| {{field_name}} | Dynamic — appears in upload form & automations |
| Plain string | Static label — fixed in the layout |
| https://… | Static image URL on image components |
| bag.fill | SF Symbol name on icon components |
Node shape
Every node is a JSON object. Containers nest children. Leaf nodes carry bindings.
| Field | Where |
|---|---|
| id | Required. Unique in the tree. |
| type | A registry type — 19 v1 nodes plus shape, calendar, chart, grid, table. |
| variant | v2 nodes. Shape, calendar, chart, and grid pick a visual form here — not as a separate type. |
| action | Pro+ family_views. set_view (another screen) or toggle_flag (same-screen reveal). XOR with href. |
| visibleFlag | Pro+. Slug on any node. Shown when that flag is true. Flags default false. Pair with toggle_flag — not a named view. |
| layout | Containers only: vertical | horizontal | z-stack. Not a style key. |
| style | Optional object. Fields depend on type — see Components. |
| children | Containers 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 key | Use instead |
|---|---|
| gap | spacing on container and gradient. gap is valid only on status_dot. |
| textAlign | alignment |
| borderRadius | cornerRadius |
| backgroundColor | background on container. backgroundColor is valid on badge, button, and avatar. |
| margin / flexGrow / objectFit / numberOfLines | padding, flex, contentMode, maxLines |
Allowed values
alignment—leading|center|trailing. Containers also acceptstretch.fontWeight—regular(default),medium,semibold,bold,light,heavyfontFamily—sf-pro(default),sf-rounded,sf-mono,heebo,rubik,frank_ruhl_libre,varela_round,secular_one,playpen_sans. Details are under Typography.contentMode—fill(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 inColor - URL —
backgroundImage
Typography
Omit fontFamily and the text draws in SF Pro. Reserve sf-rounded for playful widgets and sf-mono for code and hashes. At most 3 font sizes and 2 weights per widget. Set maxLines: 1 on titles and hero lines in small/medium widgets.
Six more faces are bundled on every plan. Use the id. An unknown name still draws as SF Pro. The family applies on text, timer, clock, date, and relative_time. stat, badge, and status_dot stay on the system face.
| ID | Sample | Scripts in the file |
|---|---|---|
| heebo | Good morningשלום | Latin, Hebrew |
| rubik | Good morningשלום مرحبا Привет | Latin, Hebrew, Arabic, Cyrillic |
| frank_ruhl_libre | Good morningשלום | Latin, Hebrew |
| varela_round | Good morningשלום | Latin, Hebrew |
| secular_one | Good morningשלום | Latin, Hebrew |
| playpen_sans | Good morningΓεια Привет שלום | Latin, Cyrillic, Greek, and Hebrew |
fontWeight changes the stroke on Heebo, Rubik, Frank Ruhl Libre, and Playpen Sans. It does not change Varela Round or Secular One. Chinese, Japanese, Korean, Thai, and Hindi are not in these files. Those characters stay on the system font.
Color
- iOS renderer accepts 6-digit hex only (
#RRGGBB) — 8-digit alpha hex is ignored - Primary text:
#000000or omit for system primary - Secondary labels:
#8E8E93 - One accent hue per widget unless the user requests a branded look
- Color,
opacity, andvisiblemay 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.
| Intent | Mechanism | Golden |
|---|---|---|
| Tap shows/hides content on the same screen | toggle_flag + visibleFlag. No views map. | v2-vocab-flip |
| Tap goes to another screen | set_view + views | v2-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. An extra-large widget or layout is also Pro and Power to create. Dropping to Free locks the extra-large widgets that account owns. People who already follow one keep the last content.
Next steps
- Component reference — bindings and style fields per type
- Golden examples
- Create a layout