The JSON language

Every surface you can design in Kaizendex — a card, a widget, an automation — is one JSON document in one small, closed language borrowed from the web.


Kaizendex is web technology under JSON. When you design a card, a dashboard widget or an automation, what you are really doing is writing a small document: a tree of elements, what data each one shows, what happens when you tap it, and how it looks. The app renders that document as real UI — the same document, on the web and on your phone.

The language is deliberately not invented. If you have written HTML and CSS, you already know most of it, and so does any assistant that has read the web. That is the whole design goal: the right guess on the first try.

The five blocks

Every authored document is made of the same five kinds of thing.

BlockAnswersBorrowed fromThe words
Elementswhat is on the surfaceHTMLfield, button, text, icon, image, group
Bindingswhat data it showsyour own Collectionsproperty, entry, collection, view, preset, widget
Eventswhen it reactsDOM eventson.click, on.longPress
Commandswhat it doesthe app's own verbs, written as callssetValue, toggleValue, openEntry, createEntry, …
Stylehow it looksCSS, in React's spellingfontSize, color, background, borderRadius, padding, gap

Plus one expression language for anything computed or conditional — a formula field, a dynamic default, a rule that only fires on a good day. One syntax, everywhere.

Here is a whole small document, so the shape is concrete:

{
  "version": 2,
  "style": { "gap": 6, "borderRadius": 12, "padding": { "x": 14, "y": 10 } },
  "on": { "click": [ { "command": "openPeek" } ] },
  "elements": [
    { "type": "text", "text": "How do I feel today?", "style": { "textAlign": "center" } },
    { "type": "field", "property": "mood", "control": "radio",
      "style": { "columns": 5, "gap": 8, "borderRadius": "full" } },
    { "type": "button", "label": "Log it",
      "style": { "background": "var(--color-primary)" },
      "on": { "click": [
        { "command": "setValue", "property": "logged", "value": true },
        { "command": "effect", "name": "celebrate" }
      ] } }
  ]
}

The naming rules

These seven are not house style. A validator enforces each one, and a document that breaks one is rejected with a message telling you what was expected.

  1. Keys are camelCase. borderRadius, never border_radius. The one exception is names you mint — a property's binding key, a tag's id, a widget's id. Those are your data, not the language's vocabulary.

  2. Style keys are the React / React Native shared style names, from a closed list. Values are numbers, per-side objects, or named tokens — never a CSS shorthand string. "padding": "2px 14px" is rejected on purpose: a phone cannot parse it, so it can never be part of a language both renderers speak. Write "padding": { "y": 2, "x": 14 } instead.

  3. Colours and fonts are CSS variables. "color": "var(--color-foreground)", "fontFamily": "var(--font-heading)" — the exact strings your theme already defines. A plain hex like "#16a34a" is legal too, but a variable follows the theme you switch to; a hex does not.

  4. Layout stays abstract. span, rowSpan, order, columns, gap. The web paints them as CSS Grid and the phone works out the same geometry by arithmetic. There is no raw gridColumn string, because a string only one renderer understands is not a language, it is a leak.

  5. Events are DOM event names. click, not tap. longPress is ours only because the DOM has no word for it.

  6. A token means the same thing everywhere. "boxShadow": "md" is the same depth on a card, a widget and a chip — one table for the whole app, never a second one.

  7. No free-form CSS, class names, URLs or code. The language borrows CSS's words, not its parser. Every value reaches the screen as a checked number, a token from a closed list, a strict hex, or a theme variable.

Why borrowed, not invented

Because you should be able to guess. A design language nobody has seen before has to be learned from a manual; a design language spelled like the web is one you — or your assistant — can write correctly the first time, from memory. Everything closed here is closed for two reasons: it can be checked before it is saved, and it can be painted identically on two very different renderers.

Closed does not mean frozen. Every list on these pages grows on demand: when something reasonable cannot be said, the language gains a word, checked and painted on both platforms. That is the normal path, and it is meant to be cheap.

Versions and errors

Every document carries a version number, and every reader upgrades an older document as it loads. A card you designed a year ago never breaks because the language moved on.

When something is wrong, you get the location, the problem and what was expected, rather than a stack trace:

{ "path": "elements[2].style.span", "problem": "99 is above the maximum", "expected": "integer 1–12" }

Next

  • Style — every visual key, what it accepts, and how to write a value
  • Events — when a surface reacts
  • Commands — what it can do when it does
  • Expressions — anything computed or conditional
  • Cards — the card document, block by block