AppSPHERE
One engine for any application you can describe
AppSPHERE reads an AppSPEC document and runs it: it parses the XML, builds a graph of states joined by labelled wires, and renders each state from a registry of general-purpose components. It runs in any modern browser.
Parse
The spec is plain XML. The engine reads APP, DATA, DEFINES, the states and the wires, and expands any components you defined from other components.
Graph
States are nodes and each WIRE is an edge named by its label. Any button, card or row that fires the label follows that edge.
Render
Each tag maps to one component in the registry. Components are written against theme tokens, so any theme renders any app.
React
Components bound to a collection redraw when it changes. Save a comment and every view of that collection updates.
Why AppSPHERE is still ahead
A design from 2001 that the web is still catching up with
Many of its ideas have since been adopted piecemeal by JavaScript frameworks. The complete model, an entire application specified as one declarative, loosely coupled state machine in a single document, remains a couple of generations ahead of today's web stack.
01The entire app is one spec
Interface, data, states and transitions are written in one declarative document, with no build step, bundler or glue code between them.
A typical stack spreads the same app across components, a router, a store, API clients and build configuration.
02The state machine is explicit
Every screen and every transition is declared, so an app can be visualised, validated and reasoned about. The Studio draws it as a graph.
Elsewhere, flow tends to be implicit, spread across hooks, effects and route files.
03Wiring is by label
An action is a name. A WIRE with the same label connects it to a state, and can save a record on the way.
Typical stacks connect the same pieces with imports, props passed through layers, or an event bus.
04Components bind by identity
Comments, likes and recommendations attach to any record with one tag. The engine finds the data through the record's GUID.
Typical stacks write an integration, with its own API calls, for every place such a feature appears.
05One data contract
A key-value pipe flows from state to state, so any component can read any state's output.
Typical stacks define a separate data shape between each pair of components.
06Integration lives in the engine
The intelligence that connects components is written once, in AppSPHERE, and every app inherits it.
In most codebases that logic is rewritten, slightly differently, in each application.
07Specs are data
An AppSPEC document can be generated, diffed, validated and transformed by tools. This makes AppSPEC well suited to AI-generated applications, a modern benefit of the 2001 design.
Generated code must be reviewed line by line; a generated spec can be checked against the schema.
08Beautiful by default
A theme is one attribute, and every component follows it.
Typical stacks connect a design system to each screen by hand.
The five-step guide demonstrates these points live: one spec, an explicit graph, a label wire, the key-value pipe, a theme change and components that bind themselves.
The pipe
What moves between states is a key-value bag
When an action fires, the engine gathers every field on the screen under its ID, adds the record that was clicked and a few system keys (the user, the state it came from, the time) and carries that bag to the next state. Any attribute can read it with a placeholder such as {title}, {record.author} or {products.price|money}.
Writes are declared on wires as well: SAVE, UPDATE and DELETE name a collection, and SET adds key-value pairs. None of the create, update or delete operations in the gallery use code.
<INPUT ID="title" LABEL="Title" />
<BUTTON LABEL="Save" ACTION="save" />
<!-- pipe: { title, _user, _state, _time } -->
<WIRE LABEL="save" SAVE="notes"
SET="author={user}" TO="notes" />
<DEFINES>
<STAT VALUE="" LABEL="">
<CARD STYLE="flat">
<TEXT STYLE="h1" TEXT="{value}" />
<TEXT STYLE="muted" TEXT="{label}" />
</CARD>
</STAT>
</DEFINES>
<ROW>
<STAT VALUE="42" LABEL="Threads" />
<STAT VALUE="318" LABEL="Posts" />
</ROW>
DEFINES
Components made of components
Like a Lisp macro, a definition is a small tree of existing components with named parameters. Use it like any built-in tag; the engine expands it. The Bulletin Board's post card and section header are defined this way.
Binding by GUID
Loose coupling, integrated by the engine
Every record has an identity: its collection and id (videos/v2, products/mug), or an explicit GUID. COMMENT-THREAD, LIKES, RATING, ACTION-BAR and RELATED ask the engine which asset they belong to, and it answers with the record in scope or the one on screen.
The comments in the video app, the reviews in the store and the responses on the blog are the same component, placed three times without configuration.
<!-- video app -->
<COMMENT-THREAD />
<!-- store -->
<COMMENT-THREAD RATING="true" TITLE="Reviews" />
<!-- or bind explicitly -->
<LIKES GUID="products/mug" />
Themes
Thirty-one themes, one attribute
Each theme sets the same small set of tokens: four surfaces, three text steps, an accent, a border, three status colours, a radius and three typefaces. Fonts and icons are served from this site.
Safe to run anything
Every app runs in a sandbox
An AppSPEC document may include JavaScript in an ACTION with CODE. For that reason every app on this site, including the Studio preview and anything you paste in, runs in an iframe with an opaque origin. It has no cookies, no storage of its own, no access to the surrounding page and no network access.
The host page provides three services: a storage namespace for the app, read-only access to the demo data, and privacy-enhanced YouTube players placed over its video placeholders.
Read-only by design
A static API with local writes
On this site the backend is a fixed snapshot of JSON files, and the server accepts no writes. When you post or edit, the engine keeps the change in your browser as an overlay on the snapshot; Reset demo data removes it.
A deployment with its own server registers a read/write backend and points DATA at it with one attribute, while the specs stay the same.