One core, two platforms

Bring it to life: behavior & motion

In preview

Give a component state and motion that behaves identically on web and Flutter — from one source. You author a behavior contract and a motion contract; a single shared core evaluates both, so the same press, open, or transition produces the same values everywhere.

In preview

The capability envelope is now decided — deliberately high-ceiling ("custom, not minimal") — and the schema and authoring surface are being formalized. What's below is the intended v1 shape; author against it knowing the edges may still move before it's marked available.

How it stays identical across platforms

Instead of writing one state machine for web and another for Flutter — and watching them slowly diverge — you write one behavior contract. A single evaluation core computes the states, transitions and motion values, and both platforms read the same answers out of it. Parity isn't something you maintain; it's mechanical.

Localization coverage

The published catalog carries 41 English messages, translated for ja, pl, ru, with en-XA and en-XB pseudo-locales for layout and bidirectional stress testing.

The authoring artifacts

You author two contracts that join by id: a behavior contract describing states and transitions, and a motion contract describing how things move. A transition names the motions it triggers.

Behavior contract
{
  "schemaVersion": 1,
  "id": "dialog",
  "initial": "closed",
  "states": {
    "closed": {
      "on": {
        "OPEN": { "target": "open", "motions": ["dialog.panel.enter"] }
      }
    },
    "open": {
      "on": {
        "CLOSE": { "target": "closed", "motions": ["dialog.panel.exit"] }
      }
    }
  }
}
Motion contract (joined by id)
{
  "schemaVersion": 1,
  "motions": {
    "dialog.panel.enter": {
      "tracks": {
        "opacity": { "from": 0, "to": 1, "driver": "tween" },
        "scale": { "from": 0.96, "to": 1, "driver": "spring" }
      }
    }
  }
}

What you can express (v1)

  • Nested states, and independent regions that run in parallel — a combobox that is open-or-closed and focused-or-blurred at the same time, without a combinatorial tangle of states.
  • Guards that gate transitions on typed inputs and your own context (booleans, numbers, values you track).
  • Transitions fired by events you send in (press, open, dismiss) — or automatically, the moment a condition becomes true, with no event needed.
  • Actions on entering and leaving a state, updates to your own context, and a state knowing when its work is complete.
  • Motion attached to a transition by id, including staggering a parent's children into place.
  • Reduced-motion honored automatically — the state graph runs unchanged while motion collapses to its end values.
  • One source driving your web and Flutter component identically.

Coming later

Some capabilities are intentionally deferred to keep the v1 shape tractable, and they're planned as additive — adopting them later won't break what you've already authored: remembering a state's previously-active sub-state (history), a cross-component event bus, and richer motion timelines and path animation.