JsonUI
/
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 platform
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 | bash
2Create 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 web
4Author 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 build
jui verify --fail-on-diff
PLATFORM-SPECIFIC — pick your stack
6Wire 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 listen
8Confirm 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