Views
view.json: the components, bindings, and sizes that draw a widget.
A widget's view.json says how the phone draws it: one tree of ShiftPane's components per size. It's declarative, not code. That makes it safe by construction, keeps every widget in the app's look, and lets the gallery check it against sample.json before anything runs.
{
"small": {
"type": "stack",
"children": [
{ "type": "label", "text": "GPU" },
{ "type": "ring", "bind": "@gpu/percent" },
{ "type": "history-bars", "bind": "@gpu/history" }
]
}
}Bindings
| Write | It reads |
|---|---|
"bind": "@gpu/percent" | A system source: the source's name, then a path into it |
"bind": "/repos/0/name" | The collector's output, as a JSON Pointer |
"text": "Over {config.threshold}%" | A config value, inside text |
"text": "Playing on {@media/app}" | A bound value, inside text: {@source/path} or {/pointer} |
Every @ binding has to name a source the manifest declares, and every / binding has to resolve in sample.json, whether it's in a bind field or inside text. The gallery checks both.
Components
| Component | What it draws |
|---|---|
stack, row, grid | Layout: a column, a row, or columns columns. A row can be inset from the card's edges |
label | A small muted caption |
text | Text, from text or bind. size: xs, sm, md, lg; muted for the quiet gray |
value | A big number with a small unit. format: percent, number, compact, bytes, rate, celsius, duration. size: sm, md, lg, xl |
ring | A circular gauge, 0 to 100. size: "sm" is the small gauge beside a figure; color: "ink" draws it in the card's own text color; unit: false drops the % sign |
battery-gauge | Purple battery card; bind to { percent, charging, minutesLeft }, usually @battery. Requires ShiftPane 0.7.0 |
meter | A row of blocks filling up, 0 to 100 |
progress | A thin bar, 0 to 100 |
history-bars | Recent values as thin bars around a middle line, newest on the right. max is what a full bar means; count keeps only the newest values |
sparkline | Recent values as a line |
contribution-calendar | Green activity squares. weeks: 1–54; split stacks two grids; boxesOnly hides all visible text. Requires ShiftPane 0.6.0 |
list | Rows of title, subtitle and value |
icon | An icon by name; optional bind selects a registered icon from collector output, falling back to name |
button | Fires one of the manifest's actions |
divider | A hairline across the card |
cover | A gradient tile with an icon on it, colored from the text it's bound to, so each track gets its own |
equalizer | Three small bars bouncing, for "playing" |
glow | A soft colored light behind the content, bleeding off a corner (corner: top-right or bottom-right) |
Accent colors (color) are flame, lime, mint, sky and ink. Type, rings, covers and buttons are sized the way the ShiftPane app sizes them: they scale with the card, within limits, so a widget reads the same on a small tile and on a phone held up to the screen.
There are no images from the web: an image URL would make the phone call out and give away its address.
Sizes
Contribution calendar data
Bind a contribution-calendar to an object with startDate, endDate, and days. Dates are real YYYY-MM-DD dates, displayed without timezone conversion. Each day has date, a nonnegative integer count, and a level from 0 to 4. The renderer uses five fixed green shades, starts weeks on Sunday, leaves missing and future days blank, and ignores invalid entries. Input is capped at 378 entries and 54 weeks. The total counts only days shown by that node.
{
"calendar": {
"startDate": "2026-10-01",
"endDate": "2026-10-23",
"days": [{ "date": "2026-10-23", "count": 6, "level": 2 }]
}
}Use { "type": "contribution-calendar", "bind": "/calendar", "weeks": 8 } for a recent grid. Use split: true for a full year on a large square tile.
Board sizes
A widget lists its sizes in the manifest, and gives each a tree: small is one cell of the board, medium two cells wide, large two by two. A size without its own tree uses the nearest one that has one.
The previews on this site are drawn from view.json and sample.json in your browser, the way the phone draws them.
Contribution calendar data
Bind to { startDate, endDate, days }, using real ISO YYYY-MM-DD dates. Each day is { date, count, level }, with a nonnegative integer count and level 0–4. Weeks run Sunday–Saturday. Missing and future dates stay blank; invalid entries are ignored. Input is capped at 378 entries and 54 weeks. boxesOnly: true fills the card with squares without labels or totals; dates and counts remain accessible.
Bound icons require ShiftPane 0.6.0. Weather names include sun, moon, cloud, cloud-sun, cloud-moon, rain, snow, fog, and storm; calendar is also available. Unknown or missing bound names use the static fallback.
For a minimal card with one oversized number, use "size": "hero" on a value node. It scales with the card and fits longer values; its smaller unit is raised beside the number. A value’s unit may contain placeholders, such as "{/temperatureUnit}".
A root stack or row can set surface to blue or violet for a full-card gradient and light text.