Introduction
Constela is a UI language that describes UI in JSON instead of JavaScript.
All UI elements—headings, text, buttons, state, and events—are defined as structured JSON and compiled into web pages.
Developers don't need to write JavaScript to create UI.
JavaScript is the execution target, not the description language for UI.
Constela treats UI as verifiable data rather than "code."
This allows detecting structural inconsistencies, undefined state references, and invalid update operations before execution.
The constrained JSON format means UI expression surface area is finite and statically analyzable.
This design is suitable not only for humans but also for generative AI workflows that create and modify UI.
Why Write UI in JSON?
1. Errors Are Detected at Compile Time
With React/TypeScript, type errors are caught by TypeScript, but logical UI errors (references to non-existent state, invalid event handlers, etc.) aren't discovered until runtime.
With Constela, all errors are detected at compile time:
{
code: 'UNDEFINED_STATE',
message: 'State "count" is not defined',
path: '/view/children/0/props/onClick' // Exact error location
}
2. State Management is Declarative and Predictable
React approach:
const [count, setCount] = useState(0);
const [loading, setLoading] = useState(false);
const handleClick = async () => {
setLoading(true);
// Where setCount gets called is unclear
// Multiple useEffects can interleave
setCount(prev => prev + 1);
setLoading(false);
};
Constela approach:
{
"state": {
"count": { "type": "number", "initial": 0 },
"loading": { "type": "boolean", "initial": false }
},
"actions": [
{
"name": "increment",
"steps": [
{ "do": "set", "target": "loading", "value": { "expr": "lit", "value": true } },
{ "do": "update", "target": "count", "operation": "increment" },
{ "do": "set", "target": "loading", "value": { "expr": "lit", "value": false } }
]
}
]
}
In Constela, state types and initial values are explicitly declared, and actions are arrays of "what to do" steps. The execution path is crystal clear.
3. Constrained DSL Suitable for AI Generation
React's JSX allows embedding arbitrary JavaScript. This poses a security risk when AI generates UI.
Constela is a constrained DSL:
- 13 expression types (
lit,state,var,bin,not,param,cond,get,route,import,data,ref,index) - Only safe operators (
+,-,*,/,==,!=,<,<=,>,>=,&&,||) - Arbitrary JavaScript execution is impossible
This constraint allows AI to safely generate structurally correct UI.
Code Examples
Counter App
{
"version": "1.0",
"state": {
"count": { "type": "number", "initial": 0 }
},
"actions": [
{
"name": "increment",
"steps": [
{ "do": "update", "target": "count", "operation": "increment" }
]
},
{
"name": "decrement",
"steps": [
{ "do": "update", "target": "count", "operation": "decrement" }
]
}
],
"view": {
"kind": "element",
"tag": "div",
"children": [
{
"kind": "element",
"tag": "h1",
"children": [
{ "kind": "text", "value": { "expr": "lit", "value": "Constela Counter" } }
]
},
{
"kind": "element",
"tag": "div",
"children": [
{ "kind": "text", "value": { "expr": "state", "name": "count" } }
]
},
{
"kind": "element",
"tag": "div",
"children": [
{
"kind": "element",
"tag": "button",
"props": { "onClick": { "event": "click", "action": "decrement" } },
"children": [
{ "kind": "text", "value": { "expr": "lit", "value": "-" } }
]
},
{
"kind": "element",
"tag": "button",
"props": { "onClick": { "event": "click", "action": "increment" } },
"children": [
{ "kind": "text", "value": { "expr": "lit", "value": "+" } }
]
}
]
}
]
}
}
Todo List with Loops
{
"version": "1.0",
"state": {
"todos": { "type": "list", "initial": [] },
"newTodo": { "type": "string", "initial": "" }
},
"actions": [
{
"name": "addTodo",
"steps": [
{
"do": "update",
"target": "todos",
"operation": "push",
"value": { "expr": "state", "name": "newTodo" }
},
{ "do": "set", "target": "newTodo", "value": { "expr": "lit", "value": "" } }
]
}
],
"view": {
"kind": "element",
"tag": "ul",
"children": [
{
"kind": "each",
"items": { "expr": "state", "name": "todos" },
"as": "item",
"body": {
"kind": "element",
"tag": "li",
"children": [
{ "kind": "text", "value": { "expr": "var", "name": "item" } }
]
}
}
]
}
}
Async Data Fetching
{
"version": "1.0",
"state": {
"users": { "type": "list", "initial": [] },
"loading": { "type": "string", "initial": "idle" },
"error": { "type": "string", "initial": "" }
},
"actions": [
{
"name": "fetchUsers",
"steps": [
{ "do": "set", "target": "loading", "value": { "expr": "lit", "value": "loading" } },
{
"do": "fetch",
"url": { "expr": "lit", "value": "https://api.example.com/users" },
"method": "GET",
"result": "data",
"onSuccess": [
{ "do": "set", "target": "users", "value": { "expr": "var", "name": "data" } },
{ "do": "set", "target": "loading", "value": { "expr": "lit", "value": "done" } }
],
"onError": [
{ "do": "set", "target": "error", "value": { "expr": "var", "name": "error" } },
{ "do": "set", "target": "loading", "value": { "expr": "lit", "value": "error" } }
]
}
]
}
],
"view": {
"kind": "element",
"tag": "div",
"children": []
}
}
Comparison with React/Next.js
| Aspect | React/TypeScript | Constela |
|---|---|---|
| Language | JavaScript/JSX | JSON DSL |
| Execution Model | Runtime-driven | Compiler-driven |
| Type Safety | TypeScript (erased at runtime) | JSON Schema (compile-time validation) |
| State Updates | Arbitrary functions | Declarative actions |
| Errors | Runtime exceptions | Structured errors (with location info) |
| AI Generation | Unsafe (arbitrary JS possible) | Safe (constrained DSL) |
| Debugging | Inspect closures | Read action steps |
| Markdown/Code | Requires dependencies | Built-in (Shiki support) |
| SSR | Complex (Next.js setup) | First-class support |
| Determinism | Complex (re-rendering issues) | Guaranteed (compiler-validated) |
Built-in Features
Constela includes the following features out of the box:
-
Markdown Rendering:
{ "kind": "markdown", "content": ... } - Syntax Highlighting: Dual-theme support via Shiki
-
File-based Routing:
index.json,users/[id].json,docs/[...slug].json - SSR/SSG: Server-side rendering and hydration
- Data Loading: Fetch data from files, APIs, and MDX at build time
Getting Started
# Create project
mkdir my-app && cd my-app
npm init -y
npm install @constela/start
mkdir -p src/routes
# After creating a page at src/routes/index.json...
# Start dev server
npx constela dev
# Production build
npx constela build
Conclusion
Constela is a new approach that treats UI as "data" rather than "programs."
- Compile-time Validation: Discover errors before execution
- Declarative State Management: Predictable and traceable
- AI Affinity: Safe UI generation with constrained DSL
- Simple Mental Model: Write JSON, compile, it works
This project has just started, and we've finally reached the point where the official Constela website can be built with Constela instead of React/Next.js. We would appreciate your feedback for improvement.
Official Site: https://constela-dev.vercel.app/
Repository: https://github.com/yuuichieguchi/constela
Top comments (0)