programmati.ca Open Studio

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.

How the AppSPHERE engine works An AppSPEC document is parsed into a graph of states joined by labelled wires. The renderer turns the current state into components from the registry. Components read a data layer that merges a read-only snapshot with the visitor's local writes. Everything runs inside a sandboxed frame. sandboxed iframe · opaque origin app.appspec <APP THEME><DATA/> <DEFINES/><STATE/> ×n <WIRE LABEL/></APP> parse Graph states are nodes, labels are edges home detail edit open back render Component registry one definition per tag, themed by tokens CARDS TABLE CHART VIDEO FORM BOARD COMMENT-THREAD LIKES RELATED orange: bound by GUID to the record on screen Data layer records by collection Snapshot api/*.json · read-only + Local overlay your browser only = whatyou see The pipe title: "Heron nest" record: {…} _user · _state · _time
The engine parses the spec, builds the graph and renders components, which read from one data layer. On this site the engine runs inside a sandboxed frame.

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.

claude
spotify
miro
pinterest
ferrari
figma
pastel
neon-grid
airbnb
atelier
heritage
bold-tech
modern-minimal
classic
workshop
fintech
ocean
sunset
lavender
forest
solar
cobalt
rose
teal
ember
iris
meadow
github
linear
notion
stripe

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.