Building charts and dashboards
Create multiple dashboards as tabs, build charts from any Collection, Property, or Tag, reuse a chart on several dashboards, and control the layout per chart.
Your Dashboards live at /dashboard. You can have several — Overview, Health, Training — shown as tabs across the top. Each dashboard is a grid of charts, and every chart lives in your chart library, so the same chart can appear on more than one dashboard.
Dashboards as tabs
- Press + at the end of the tab strip to add a dashboard, then type its name (pick an emoji from the icon button while renaming).
- Drag tabs to reorder them; double-click (or use the open tab's menu) to rename.
- Deleting a dashboard never deletes charts — they stay in your library, ready to place elsewhere.
Adding a chart or widget
Open the active tab's menu (click the selected dashboard tab) and choose:
- New chart — opens the builder.
- Add existing chart… — pick any chart from your library. Charts already on this dashboard show as Added; others show which dashboards they're on.
- Under Add widget: Heading, Text, Image, Note, Panel or Divider — the pieces that make a board read like a page instead of a wall of cards. They land immediately, with nothing to fill in.
An empty dashboard also shows an Add chart button front and center.
Headings, text and dividers
Not everything on a dashboard is a chart.
- Heading — a section title, so Sleep and Training stop running into each other.
- Text — a line of your own words. It can also show live values: anything you put in curly braces is worked out for you, using the same formula language as everywhere else in Kaizendex.
- Divider — a quiet line between sections.
A text widget starts life showing today's date, so you can see the idea working:
Today is {formatDate(today(), "weekday")} · week {isoWeek(today())}
You can also drop a link into text, written like [Food log](kzx://collection/abc) for somewhere inside Kaizendex, or [The docs](https://example.com) for anywhere else. External links show a short "You're leaving Kaizendex" note first, naming the site you're about to visit — with a Don't warn me again tick if you'd rather skip it. You can turn that warning back on any time in Settings → Security.
If something in the braces doesn't make sense, that bit turns red and tells you why, right where it is — the rest of the line still reads normally.
Headings, text and dividers take their own colour in the widget's Settings, using the same colour grammar as charts (a palette slot, one of your named colours, an app role, or a colour written out; see Any colour, and patterns). Leave it off and the text follows the card it sits in.
Text can say more than one thing at a time. A second line under the words — smaller, in its own colour, in the same alignment — turns a big clock and its "I keep going gently ✨" into one widget. And the values those curly braces read are declared right there under Values it reads: name one streak, point it at a Collection and one of its properties, and {prop("streak")} in the text above shows your live number.
Which entry a value reads
Every value also says which entry it comes from — the Entry row, right under the property. Left alone it reads your newest entry, which is what you want for "my current weight". The other three are what turn a widget into something that changes on its own:
| Entry | Reads | Good for |
|---|---|---|
| Newest entry | the latest one you logged | current weight, today's mood, last night's sleep |
| By position (rotates) | counts through the collection to a position you write as a formula | a quote of the day: order by a Number property, position dayOfYear(today()) |
| Where a property equals… | the entry whose property matches a value | "the entry whose Number is today's day of the year", said literally |
| Random, held for a period | one picked at random and then kept for the hour, day, week, month or year | a random encouragement each morning that doesn't flicker as you scroll |
By position counts from 1 and wraps, so you never run out: 30 quotes happily cover 365 days — day 31 comes back round to the first. (A negative position counts from the end, so -1 is the oldest.) Ordered by decides what "position 1" means — pick a Number property and they go 1, 2, 3; leave it empty and they're newest-first.
Building a quote of the day, start to finish: make a Collection with your quotes (the quote itself as the entry title, plus an Author and a Number), add a text widget whose words are {prop("quote")} and — {prop("author")}, then declare two values — one on the title, one on Author — both set to By position, ordered by Number, position dayOfYear(today()). It changes by itself every morning.
Sections — grouping tiles under one frame
A dashboard can say these tiles belong together. A section draws one frame around a group of widgets and puts a title on it — DAILY QUESTS, ma semaine, Sleep — so a board reads as a page with parts instead of a wall of separate cards.
You set sections up in the dashboard's JSON (the active tab's menu → Edit dashboard (JSON)): name each section and give it a look, then say which section each widget joins. After that, every widget's menu grows a Section block, so moving a tile in or out is one click.
"sections": {
"sleep": { "title": "SLEEP", "chrome": { "border": "top",
"title": { "plate": true, "scale": "heading" } } }
}
A few things worth knowing:
- The frame is drawn around wherever its widgets happen to be — it has no size of its own. Move the widgets, the frame follows.
- Widgets inside a section drop their own card by default, because the section is the card. Any widget can ask for its card back.
- On a phone there's no grid to draw a box around, so the section becomes a titled band just above its widgets.
- Keep a section's widgets together on the grid. If two sections' widgets are interleaved, their frames will cross each other.
Titles, plates and tile colours
Every widget's title is yours to style, in the widget's or the dashboard's JSON:
"chrome": { "title": { "align": "center", "scale": "heading",
"color": "role:accent", "plate": true } }
- align —
leftorcenter. - scale —
caption(the ordinary card heading),body, orheading. - color — the same colour grammar charts use.
- plate — draws the title on a small chip straddling the top edge of the frame, the way a poster labels a panel.
A Text widget keeps its title hidden unless you turn it on — its words are already its content.
Two more looks live in the same place: "background_color" paints a tile in any colour
you can name (it wins over the plain surface/tinted/filled choice), and
"background_image" puts one of your uploaded pictures behind a tile, with
"background_fit" set to cover, contain or tile.
Frames grew too: "border" can be double, bracket (corners only) or top (a single
rule above the content), and "texture" gained hex, a honeycomb mesh.
Goal bars on one line
A Progress widget normally fills a card. Add "style": { "arrange": "inline" } and
it collapses to a single line — 🍖 Rations ▓▓▓▓▓▒▒ 1,750 / 2,400 kcal — with no
heading above it.
This is the simplest way to make a dashboard compact: six targets become six lines instead of six cards. There's no "compact mode" to switch on; a board is dense because you composed it dense.
A week of habits at a glance
A Habit chart normally shows one habit on a month calendar. Point it at several Collections instead and it becomes a matrix: one row per habit, one column per day, a tappable box at every crossing — and tapping still ticks the real entry, exactly like the calendar.
For this to work each habit Collection needs to share the same Yes/No property, so one chart can reach them all. Ranges wider than about a month stay on the calendar, which is the right shape for them.
The builder
The builder shows a live preview built from your real data — every change updates it instantly.
It's the same form in both places you meet it: New chart opens it as its own dialog, and once a chart is on a board, ⋯ → Edit widget → Settings shows you exactly those controls again — no second dialog, no shorter list of options. There you get the widget's Size, On phones, Duplicate and Delete underneath, its Style tab beside, and its whole JSON one tab over.
A chart is built from data sources you add one at a time. Press + Add data source, pick a Collection, then choose what to take from it:
- one of its properties (e.g. Calories, Time asleep, Reps) — added with its own Sum / Average / Min / Max,
- or Count entries — how many were logged.
If you use automatic screen-time tracking, the Activity breakdown property is chartable too — pick it and a Site or app picker appears, so you can chart your time on one specific site or app ("time on my-project.com today" as a Stat card). It counts as a time metric, so it renders as hours and minutes automatically.
You can also pick a Tag (count entries carrying it, across every Collection) or All entries. Press add and the source appears in the list — add another to combine, or remove any with ✕. Options that can't be combined are greyed out with a short explanation (text properties can't be charted as numbers; counts and properties can't stack; a Tag source stands alone).
Combining sources does the natural thing:
- several properties → they stack as colored segments in one chart (protein + carbs + fat),
- several Collections counted → one combined count (great for an exercise heatmap across Running + Gym + Stretching — split it by Collection to see each).
Then calibrate what happens to your sources:
- Filter — narrow the entries: only ones carrying certain tags, only values above a threshold, only entries matching one or several names or text values (entries called "my-project.com" or "my-other-site.com" — type a name and press Enter to add each; handy for charting one or two projects inside a shared time-log Collection), only entries where a property is set.
- Split by — break the chart into colored segments by a tag or select property (work vs leisure time as a stacked bar) or by Collection.
- Group by — day, week, or month buckets.
- Range — Today, This week, This month, or the last 7/30/90 days, 6 or 12 months.
- Goal — a target per day, week, or month (2,000 kcal per day, 1,000 push-ups per week). Goal charts track the current period automatically.
Chart types
-
Stat — one big number with a subtle sparkline and a change-vs-last-period chip.
-
Line / Area / Bar — trends over time; the current day/week is highlighted.
-
Heatmap — a GitHub-style year grid; perfect for "how often do I…?".
-
Habit — a crossed-out habit calendar; perfect for "did I do this today?" streaks.
-
Progress — a segmented bar toward your goal (1,240 / 2,000 kcal today).
-
Gauge — the same goal as a ticked ring.
-
Ring — a smooth goal ring that fills as you log, with what's left as the big number (757 kcal left today) and an icon in the middle. You can switch the center to the raw value or a percent, and pick any emoji or icon, in the Style tab.
-
Donut — composition with a legend (needs a Split by).
-
Stats — several numbers in one card, split by thin lines. Use it for a "today at a glance" row instead of four separate widgets. Each cell can carry its own icon, its own change chip, and even its own filter, so Orders and Orders shipped can sit side by side reading from the same collection.
-
Distribution — one wide bar split into coloured shares, with a legend showing each share's value and percent. Best for "where did it all go?" — spending by category, time by project.
-
Scatter — one dot per day (or week) plotted against two measures, so you can see whether two things move together. This is the one to reach for when the question is "does my sleep affect my mood?" — no other chart type answers it.
If you don't pick a type we suggest one from your data — a goal becomes Progress, a plain count becomes a Heatmap, a single checkbox becomes Habit — and you can pin any type from the Style tab.
Two numbers above one chart
Any Line, Area or Bar chart can show more than one headline number above its plot — Total Sales $22,560 and Orders 1,540 side by side over a single trend. It uses the same cells a Stats card does, so anything you can do in one you can do in the other.
Radar, Pixels and Calendar
- Radar — the "attributes" chart: one spoke per group, so you can see a shape at a glance. Add a breakdown so it has at least three things to compare.
- Pixels — one small square per day, shaded by how big that day was. Great for a year at a time. If one enormous day makes everything else look flat, switch it to rank-based shading with
"waffle_scale": "quantile"in the JSON — then your ordinary days still separate. - Calendar — a month laid out as a month, each day shaded by its number. Turn on Value labels to print the numbers in the squares.
And a Progress bar can show the numbers XP-style — "progress_label": true puts 695 / 2000 above the bar.
Habit charts
A Habit chart is a real calendar — check off a day and it crosses out with an X in your chart's accent color, so a broken streak jumps out at you. It's built for "don't break the chain" tracking: did I skip sugar today?, did I meditate?, did I floss?
It shows the full month by default. Pick This week as the Range and it collapses to a single row.
To make a Habit chart tappable, build it from exactly one Collection and one True/false property — a "Habits" Collection with a "Done" checkbox, say. Tap any day (today or earlier — future days are locked) and it toggles right away:
- No entry yet for that day → one is created, checked.
- Already checked → tapping again unchecks it. The entry stays (it isn't deleted), so your history isn't erased.
A caption under the calendar reads "N of M days" — how many days you've checked off out of the days elapsed so far in the current range.
Several habits in one Collection
You don't need a Collection per habit. Keep every habit in one Habits Collection, tell them apart with a Category tag, and give each habit its own calendar by adding a Filter for its tag.
A filtered calendar stays fully tappable, and it aims properly:
- Tapping a day ticks that habit — the other habits logged that day are untouched.
- If the day was empty, the entry it creates is stamped with the filter — so it's born carrying the right Category tag, and the chart counts it straight away instead of creating something it then hides.
That's the recommended way to track habits; the full shape is in Tracking habits.
Restyling the cells
Open the widget's Edit widget dialog and scroll past the chart's own settings: a habit or calendar chart also carries a Mark section (which mark a counted day draws — tick, cross, dot, ring or fill — and in which colour) and a Cell section for the day box itself: its shape (rounded, square, circle, or pill), whether a checked day is just an outline or filled solid in your chart's accent colour, whether day numbers show on every cell, only on unchecked ones, or never, plus the cell's size and the gap between cells. Filled pills with hidden numbers is the compact, streak-band look; the defaults match the classic cross-out calendar.
Below those, Week header controls the row of weekday names across the top: M (one letter) or Mon, and a Language box if a board written in one language is read in another — leave it empty and the names follow your app's language.
Add a single True/false property as your only data source and the builder suggests Habit automatically.
Style
The Style tab controls the look of each chart:
- Accent — pick one of six palette slots, or leave Auto to vary by position. The palette is derived from your theme's accent color, so charts recolor with your theme — and you can customize each slot in Settings → Themes → Charts.
- Colour — any colour at all, when six slots aren't the one you want. Pick a palette slot, one of the app's own roles, one of your named colours, or type a colour out. It beats Accent, and leaving it on Default hands the card back to the accent.
- Card — Plain, Tint (a soft wash), or Filled (a bold solid-color card).
- Format — plain numbers, durations (7h 32m), or percentages.
Any colour, and patterns
The Colour picker above and the chart JSON speak the same grammar,
and neither is limited to the six slots. A colour anywhere — a series, a timeline lane, or the
whole card via "color" — can be:
- one of the six slots,
"chart-1"…"chart-6"; - one of the app's own roles, like
"role:destructive"for its red; - one of your own named colours, like
"hp-red"— see Your own named colours; - or a colour written out, like
"#ff2d55".
The first three follow your theme when you change it. A written-out colour stays exactly as you set it — which is sometimes the whole point.
Bars and areas can also be filled with a pattern instead of a flat colour: "fill" takes "solid", "gradient", "stripes", "dots", "hatch" or "pixel".
Shaping the line, the bars and the rings
A few more words in "style" change the shape of what's drawn:
"curve"—"monotone"(the smooth default),"linear"for straight segments, or"step"for a staircase, which is the honest shape for something that only changes when you log it."lineDash"—"solid","dashed"or"dotted". Put it on one series to draw last year dashed behind a solid this year."dots"—trueputs a mark at every point."sweep"—"full","threeQuarter"or"half": how much of a circle a ring or gauge covers."stack": "expand"— every bar fills the full height, so you read share instead of amount ("what portion of my day went where")."yAxis"— show or hide the numbers down the left side on their own."axis": falsestill hides both sides at once.
Rings can stack. Give a ring chart several series and you get one ring per series, outermost first — the Apple Watch shape. Give each series its own "goal" and each ring fills against its own target, with a legend naming them:
{
"kind": "ring",
"series": [
{ "property_id": "…move", "agg": "sum", "label": "Move", "goal": { "target": 600, "per": "day" } },
{ "property_id": "…exercise", "agg": "sum", "label": "Exercise", "goal": { "target": 30, "per": "day" } }
]
}
Doing maths on the way in
Normally a chart sums or averages a field. Sometimes the number you want doesn't exist as a field — calories from macros, say. Give the measure a formula instead of a field:
"measure": { "agg": "sum", "expr": "prop(\"@…protein\") * 4 + prop(\"@…fat\") * 9" }
It's the same formula language as a Formula field, worked out for each entry and then added up like anything else. Easiest way in: ask the assistant for it.
Streaks
Set the measure to streak and a Stat card counts your current run of days:
"measure": { "agg": "streak" }
There's also longest_streak (your best run) and total_days (how many days you managed at all).
Reading a chart differently
transform changes how the same numbers are read, without changing the chart:
- delta_prev — each bar is the change from the one before. (Day one shows 0; there's nothing to compare it to.)
- cumulative — a running total, for "how far this year so far".
- vs_average — each bar is above or below your typical, so the line crosses at normal.
Live numbers in text
A Text widget can show live values too. Name them, then use the names in the text:
{
"kind": "text",
"bindings": { "reps": { "collection_id": "…", "key": "reps" } },
"text": "You've done {prop(\"reps\")} push-ups today"
}
Each name reads one field from your newest entry in that Collection.
Colour that reacts to your numbers
A chart can change colour based on what it's showing — "bars over my goal go red" — without making a second chart. In the chart JSON:
"rules": [
{ "when": { "all": [{ "key": "goal_pct", "op": "gte", "value": 100 }] }, "color": "role:destructive" },
{ "when": { "all": [{ "key": "is_last", "op": "eq", "value": true }] }, "color": "chart-1" }
]
Read top to bottom, first match wins. Each bar (or point) can be asked about five things: its value, your goal, goal_pct (how far along it is, as a percentage), its index, and is_last (is this the newest one).
You can also draw reference lines across a chart to read against:
"overlays": [{ "kind": "average" }, { "kind": "goal", "label": "Target" }]
Available: goal, average, median, max, min.
Fine-tuning how a chart is drawn
The Body section of the builder — and style in the JSON — controls the details:
- fill — solid, a fade, or a pattern (stripes, dots, hatch, pixel).
- opacity — 25%, 50%, 75% or 100%.
- bar_width — thin, regular or thick; bar_radius — square, soft, round or pill.
- line_width — hairline, regular or bold.
- grid, axis, labels — hide the grid, hide the axis numbers, or print each value on the chart.
Turning the grid and axis off and the values on is what turns a chart into a clean HUD panel.
Want even less on the card? "style": { "chrome": "quiet" } drops the small caption line and the ‹ period › arrows, so it's just the plot and its title. "chrome": "bare" goes further and drops the legend and goal caption too — for a wall-sized board where the picture is the whole statement. Titles you've turned on stay, since a poster usually still wants those.
A goal or progress bar can also trade its 24 little pill segments for one smooth, rounded fill — "style": { "track": "solid" } — and fade from one colour into another along the way with "style": { "color_end": "hp-red" }.
The New chart dialog's preview has a Desktop / Phone switch, so you can see how a card lands on a small screen before you save it. Editing a chart already on a board shows you something better: its preview draws the widget at that board's real size and theme.
Glow, shadow, corners, texture
The same chrome block that decides card-or-flat also carries a few surface effects, on one widget or on the whole board:
"chrome": { "glow": "strong", "shadow": "md", "radius": "none", "texture": "scanlines" }
- glow —
none,soft,strong: a halo in the widget's own colour (the neon-HUD look). - shadow —
none,sm,md,lg: how far the card lifts off the page. - radius —
none,sm,md,lg,pill: from hard-edged panels to fully rounded. - texture —
none,grid,dots,scanlines,hatch: a faint pattern over the card.
Look back in time
Every chart can travel. Under the title, the time range is a little control: ‹ 7d ›, ‹ this week ›, ‹ today ›.
- The arrows step the chart back and forward one period at a time — a daily chart moves a day, a weekly chart a whole week, a monthly chart a whole month. The forward arrow greys out once you're back on the latest window, because there's nothing to see in the future yet.
- Tap the range itself to open a calendar and jump straight to any date. The chart lands on the week, month, or day that contains it — and Jump to now brings you back.
Nothing is saved when you time-travel: the card snaps back to the live window next time you open the dashboard.
Pictures — including ones that change
An Image widget puts a picture on the board: hero art at the top, a badge beside a streak, an avatar.
The interesting part is that a picture can change with your data. In the widget's Settings you pick the Collection it watches under Which data, then add rules under When it changes — each one a property, a test, a value and the picture to show. They're read top to bottom and the first one that fits wins, so put the rarest first and finish with an Always row. (A rule that tests more than one thing at once stays in the chart JSON; the form shows it, says so, and leaves it exactly as written.)
The same thing in JSON:
{
"kind": "image",
"source": { "mode": "collection", "collection_id": "…" },
"image": { "media_id": "…novice" },
"rules": [
{ "when": { "all": [{ "key": "level", "op": "gte", "value": 10 }] }, "media_id": "…monarch" },
{ "when": true, "media_id": "…novice" }
]
}
That's an avatar that levels up as you do. The rules use the same conditions as automations and card rules, and they read your newest entry in that Collection — so "my current level" is just a field on the latest log. Ask the assistant to set it up and it will.
You can also point the widget at an image field on that entry instead of a fixed file — switch Picture to From entry and pick the field from a list of that Collection's picture properties — so the picture is whatever you last uploaded there.
Notes, entries and views on the board
Not everything on a dashboard has to be a chart or a picture.
Note drops a real entry onto the board — kept in a Collection called Notes, created for you the first time. It's an ordinary entry, so it shows up in search, syncs, keeps its history, and can be edited from anywhere. That's the point: it isn't a special "dashboard note" that only lives here.
You can also pin any entry you already have — a recipe, a checklist, this morning's briefing — either by name, or as "whatever the newest entry in this Collection is". The second one is what you want for anything that gets re-created: a daily briefing is a new entry every morning, so pinning a specific one would leave you looking at yesterday's. Ask the assistant: "put my latest daily briefing on the dashboard".
Views can be embedded too. A view on a dashboard is the view — same filters, same sorting, same rows, just windowed to fit, with an Open full view link. It isn't a cut-down copy with its own settings, so there's nothing to keep in sync: change the view and the board changes with it.
A view embed can also change shape, in its JSON: "chrome": { "density": "line" } shrinks each row to a slim checklist line instead of a full feed card ("compact" sits in between), and "presentation": "table" swaps the feed for a real table with a column per property — the same columns you've picked for that view. "max_rows" (1–24) sets how many rows show before you scroll.
"presentation": "gallery" shows the view's entries as pictures instead of rows — it reads the first photo on each entry and lays them out in a grid you size with "gallery": { "cols": 1–6, "gap", "radius", "aspect", "fit", "caption": "none" | "title" }. That is how artwork gets onto a board: the picture is an ordinary entry in one of your Collections, so it is searchable, it syncs, and deleting it tells you what it was used in — none of which a loose image is.
If a collection holds several saved views, "view_key" picks which one an embed draws, so one collection can feed many spots on the same board.
Panels — build your own thing
A Panel is a blank poster on the dashboard. Inside it you place numbers, labels, bars and pictures wherever you want them, layered — that's how you build a character card with an avatar and an HP bar over it, a trophy shelf, or a stat poster.
It uses the same designer as your Collection cards, so anything a card can do a panel can do. The only difference is where the numbers come from: a panel names them itself.
{
"kind": "panel",
"bindings": {
"level": { "collection_id": "…", "key": "level" },
"hp": { "collection_id": "…", "key": "hp", "label": "HP" }
},
"body": { "version": 1, "fields": { "level": {}, "hp": {} } }
}
Each name in bindings points at one field on your most recent entry in that Collection. The body is an ordinary card layout that refers to those names. Ask the assistant for "a character card with my level and an HP bar" and it can write the whole thing.
The board's own look
The dashboard page itself can have a background, in the dashboard JSON:
"skin": { "background": "#101014", "texture": "scanlines", "font": "heading" }
- background — a colour, in any of the forms above (including one of your own named colours).
- background_image — a picture behind the whole board, with background_fit of
cover,containortile. - texture — the same faint patterns widgets can use.
- font — which of your theme's fonts the board's headings wear.
- row_unit — how tall one grid row is:
"regular"(the default),"compact", or"tight", for a board whose tiles want to sit closer together than the usual rhythm.
A dashboard can also wear one of your own saved themes — not just its background, but its whole colour palette and fonts — while that tab is open, with the rest of the app staying on your own theme. See Your dashboard's own theme.
Layout
A dashboard is a grid of widgets you arrange by hand — drag anything anywhere by its ⋮⋮ handle, or resize by its bottom-right corner, and everything else slides out of the way to make room. There's nothing to tidy afterwards: gaps close themselves. Handles, resize corners and every widget's ⋯ menu only show up once you turn on Edit board (the pencil button by the tabs); reading the dashboard, none of it's there. See Designing boards and Editing widgets for the full drag-and-resize picture.
For a quick width change without dragging, open the card's ⋯ menu → Size and pick Quarter, Third, Half, Wide, or Full width — it resizes the card in place and everything else reflows around it. On phones the grid keeps real columns, so a row of goal rings can still sit side by side on a narrow screen.
Cards automatically compact themselves to fit their width: a Third-width card shows just the title, the big number, and a smaller chart, while wider cards keep the full detail. Goal-ring cards on a Half-width slot or wider put the number beside the ring, Cal AI-style.
Letting cards touch
By default every card sits in its own frame with a gap around it. If you'd rather have them touch — one thin line between neighbours, like a table, the way most admin dashboards look — set the board's seams to "shared":
{ "seams": "shared" }
The board then draws the lines itself and the cards drop their own borders, so two neighbours never end up with a double edge. Turning it back to "open" puts every card's own border back exactly as you set it — nothing is overwritten, it's just ignored while sharing is on.
One card can opt out with "chrome": { "seams": "open" }, and a container opts out its children the same way.
Pinning a widget to an exact spot
Behind the sizes, a dashboard is graph paper twenty-four columns wide. If dragging isn't precise enough — you want a small number tucked in the top-right corner, with a big chart beside it and empty space between — you can set a widget's exact spot in the dashboard JSON (or just ask the assistant to do it):
{ "chart_id": "…", "x": 18, "y": 0, "w": 6, "h": 8 }
- x is where it starts (0–23) and w is how wide it is, in the twenty-four-column grid. Half the board is 12, a third is 8, a quarter is 6.
- y and h are how far down it sits and how tall it is.
- Gaps are allowed. Empty columns stay empty — that's a layout, not a mistake.
- These are treated as a HINT, not a hard pin: the board still packs everything so nothing overlaps and nothing floats over a hole, in the reading order the
x/yvalues suggest.
On a phone, the board doesn't try to squeeze twenty-four columns onto a small screen: it restacks into a clean column, reading top-left to bottom-right. If one widget wants to behave differently there, add a phone patch to it — the phone's own grid is twelve columns, so "phone": { "span": 12, "order": 1 } makes it full-width and first ("span": 6 is half), or "phone": { "hide": true } to leave it off phones entirely.
The look of each widget
The same menu has a Look section: In a card or Flat (no card) (older, still-pinned boards also show Unpin from grid here). For the full styling toolkit — margin, padding, background, border, radius, shadow, glow, accent, Content scale, and the title bar — open Edit widget → Style; see Editing widgets. In JSON you get the full set on any widget, and on the dashboard as a whole via default_chrome:
"chrome": { "frame": "flat", "border": "none", "background": "tint", "title": "hide", "padding": "roomy" }
Put it on the dashboard and every widget starts there; put it on one widget and only that one changes.
Skins
The active tab's menu has a Skin section with four ready-made looks: Neon HUD, Terminal, Cozy and Mono. Picking one changes the whole app's theme and gives this dashboard a matching default look — a Terminal board is all text on black, a Neon HUD board is bright panels with strong edges. Each one is an ordinary theme underneath, so you can keep tweaking it in Settings → Themes.
Edit a chart as JSON
Every chart's settings are a small JSON document, and you can edit it directly: open the card's ⋯ menu → Edit chart (JSON) (it's also in the builder). Change anything, hit Apply, and the chart updates instantly — a typo gets you a clear list of what's wrong and where instead of a broken chart.
The JSON can do a few things the visual builder doesn't expose yet — like stacking several measured properties as series, or fine-tuning filters on your phone — so it's the power-user escape hatch when the buttons run out.
Edit a whole dashboard as JSON
The dashboard itself has the same escape hatch: click the active dashboard tab and pick Edit dashboard (JSON). You get one document with the dashboard's name, icon, an optional default_chrome, and its widgets in order — each a chart_id plus a size, and optionally col / row / span / row_span, its own chrome, and a phone patch. The order of the list is the flow order for anything you haven't pinned. Reorder, resize, add, or remove charts in one edit and hit Apply; the editor lists your charts by name next to their ids so you never have to guess, and it checks everything (including that each id is really one of your charts) before saving.
Remove vs delete
From the card's ⋯ menu:
- Remove from dashboard — takes the chart off this dashboard only. It stays in your library and on any other dashboard.
- Delete chart… — removes it everywhere, permanently. We'll tell you how many dashboards it's on before you confirm.
Next
- Reading your Dashboard — how the numbers stay fast
- The expression language — the formula syntax behind calculated values and statistics
- Function reference — every function, its scope and an example
- Tag properties — set up the tags a Tag chart reads
- Tracking habits — one Habits Collection, a streak calendar per habit