Hello, JsonUI — your first screen in five minutesInstall the CLI, scaffold a project, `jui init`, author one JSON, `jui build` + `jui verify`, then wire a platform-specific ViewModel and run. Five cross-platform steps + three per-platform — Swift, Kotlin, and React share the same foundation.
Before you startThree small requirements. The installer handles the `jui` CLI, MCP server, agents, and the per-platform CLIs (sjui / kjui / rjui) that `jui` delegates to internally.
Node 20+Node.js 20 or newerNode 20+ (LTS) drives the MCP server and the web-platform build that `jui build` delegates to. Older versions are untested. `nvm install 20` is the fastest path.
git + curlgit and curlThe bootstrap script curls the installer and uses git to fetch the CLI + MCP + agent bundle. Both are preinstalled on macOS and most Linux distros.
POSIXA POSIX shellmacOS zsh or Linux bash. Windows users: run everything inside WSL 2 (Ubuntu 22.04 is the most-tested target).
Your first screenFive cross-platform steps run the same regardless of stack; the last three (wire the ViewModel, run the app, live-reload) pick up once you choose Swift, Kotlin, or React. Switch tabs anytime — your progress stays in sync.COMMON — works for any platformPLATFORM-SPECIFIC — pick your stack
1Install JsonUI
Run the one-liner below. It installs jsonui-cli, the MCP server, and the Claude Code agent bundle into your home directory, prints six PATH lines to add (jui / docs / tests + sjui / kjui / rjui), and registers the MCP with Claude Code. Paste the PATH block into your shell rc file and reload so the new entries take effect.shell
curl -fsSL https://raw.githubusercontent.com/Tai-Kimura/JsonUI-Agents-for-claude/main/installer/bootstrap.sh | bash2Create your platform project(s)
Make a workspace directory, then scaffold one or more platform projects inside it: `./ios/` via Xcode (File > New > Project > iOS > App, SwiftUI + Swift, Product Name `MyApp`), `./android/` via Android Studio (New Project > Empty Activity, Kotlin + Compose, package `com.example.myapp`), or `./web/` via `npx create-next-app@latest web --ts --tailwind --app --eslint --src-dir`. Pick whichever platforms you'll be targeting — you can add more later by re-running `jui init`.3Run `jui init`
From the workspace root, run `jui init` with the flag(s) for the platform(s) you created. This writes `jui.config.json`, seeds `docs/screens/{json,layouts,styles}/` and `docs/screens/layouts/Resources/`, and delegates per-platform init to `sjui init` / `kjui init` / `rjui init` under the hood. You never call those tools directly — `jui` is the only CLI you need to remember.shell
# Run from your workspace root after creating the platform project(s).# Pass only the flag(s) for the platform(s) you're targeting.jui init \ --project-name my-app \ --ios ios --ios-mode swiftui \ --android android --package-name com.example.myapp --android-mode compose \ --web web4Author home.json
This one JSON is the whole UI — it compiles to SwiftUI (or UIKit) on iOS, Compose (or XML) on Android, and React on web. The `data` block at the top declares what the ViewModel must expose: `message` (bound to a Label), `tapCount` (bound inside another Label via string interpolation), and `onTap` (bound to the Button's onClick).docs/screens/layouts/home.json
{ "type": "View", "id": "home_root", "orientation": "vertical", "width": "matchParent", "height": "matchParent", "gravity": "center", "paddings": [24, 24, 24, 24], "child": [ { "data": [ { "name": "message", "class": "String", "defaultValue": "Hello, JsonUI!" }, { "name": "tapCount", "class": "Int", "defaultValue": 0 }, { "name": "onTap", "class": "() -> Void" } ] }, { "type": "Label", "text": "@{message}", "fontSize": 32, "fontWeight": "bold", "fontColor": "#0B1220" }, { "type": "Label", "text": "Tapped @{tapCount} times", "fontSize": 16, "fontColor": "#475467", "topMargin": 8 }, { "type": "Button", "text": "Tap me", "onClick": "@{onTap}", "topMargin": 16, "paddings": [10, 20, 10, 20], "background": "#2563EB", "fontColor": "#FFFFFF", "cornerRadius": 999 } ]}5Build and verify
`jui build` distributes `docs/screens/layouts/` to every configured platform and regenerates the platform-specific sources (Swift Data structs + ViewModel protocols, Kotlin Data classes + ViewModel protocols, TypeScript Data interfaces + generated views / hooks). `jui verify --fail-on-diff` then confirms the generated output matches the spec with no drift — for the screens it compared. Read the denominator it prints (`verified N of M screen(s)`, since jsonui-cli 1.8.5): a screen whose layout is authored by hand rather than generated is skipped, and a project where every screen is skipped reports `verified 0 of M` and still exits 0.shell
jui buildjui verify --fail-on-diff6Wire the ViewModel (Swift)
Create `HomeViewModel.swift` as an `ObservableObject` that conforms to the generated `HomeViewModelProtocol`. State lives in a single `@Published var data: HomeData` — the generated `HomeData` struct mirrors the layout's `data` block, so `message`, `tapCount`, and `onTap` are already fields on it. Wire `data.onTap` to a closure inside `setupActionHandlers()` (called from `init`) that mutates `data.tapCount`. SwiftJsonUI observes the published `data` struct and re-renders the Label automatically.ios/MyApp/ViewModel/HomeViewModel.swift
import Foundation // HomeData and HomeViewModelProtocol are generated by `jui build`.// HomeData holds message / tapCount / onTap from the layout's data block.class HomeViewModel: ObservableObject, HomeViewModelProtocol { @Published var data = HomeData() init() { setupActionHandlers() } private func setupActionHandlers() { data.onTap = { [weak self] in self?.data.tapCount += 1 } }}7Run the iOS app
Open `ios/MyApp.xcodeproj` in Xcode and press ⌘R to launch the simulator — Xcode compiles the Swift that `jui build` produced. For layout live-reload, run `jui hotload listen` in a separate terminal: it watches `docs/screens/layouts/` and pushes the merged, iOS-filtered JSON over WebSocket to the running app. No rebuild needed for layout-only changes.shell
open ios/MyApp.xcodeproj# In Xcode: ⌘R to run the simulator.# In another terminal, start live-reload for the layout:jui hotload listen8Confirm it works
You should see a centered "Hello, JsonUI!" with "Tapped 0 times" below it and a blue "Tap me" button. Each tap increments the counter. If the button does nothing: check the `onTap` binding and verify the ViewModel method name matches the `data` block entry exactly.Next stepsKeep going. Each tutorial adds one concept on top of Hello World — data binding, custom screens, and syntax reference in order.
Data binding basicsGo beyond `message` and `tapCount`. Learn how `@{identifier}` works for both value bindings and event bindings, one-way vs two-way binding, computed properties, and conditional visibility — with runnable examples./learn/data-binding-basics
Build your first screenBuild a real login + profile screen from a blank spec. Uses the define and implement agents end-to-end, with a Repository + UseCase layer and proper navigation./learn/first-screen
JsonUI syntax referenceEvery JsonUI component, every attribute, every binding rule on one searchable page. Look up `paddings`, `cornerRadius`, or `@{binding}` semantics in seconds./reference/attributes