Architecture

A whole program is just a sequence of calls on one object, Reactive. Every call forwards to the current interpreter; swapping the interpreter reinterprets the very same program: run it, type-check it, or generate code from it. Keep the calls pure and the meaning is decided entirely by which interpreter is installed. That is the whole design.

Reactive is the substrate

Every other module, Content, Layout, Button, and the rest, is a reified module: it registers itself by calling Reactive.Module / Function / Type. Reactive gives reified code its meaning, so reifying it through itself would be circular; it is hand-written and special by design. It still swaps its own behaviour directly, by flipping the current interpreter.

Reactive._core     // the interpreters, keyed by name (define, run, …)
Reactive._mode     // the active interpreter's name
Reactive._current  // the active interpreter object
The fields holding the interpreter registry and active mode

One op, one forwarder

Each reified operation is a one-line forwarder to the current interpreter, so an interpreter only implements what it supports and an unsupported call fails loudly rather than doing the wrong thing silently:

Reactive.State = function () {
  return Reactive._current.State.apply(Reactive._current, arguments);
};
An op forwarding to the current interpreter

The one primitive: save · swap · restore

Switching interpreter, replacing a module for a subtree (the WITH idea), setting the current context, and the lock-discovery pass are all the same move: temporarily change what's installed, run a callback, put it back. The update loop is fully synchronous, so nothing can interleave and a plain save/restore is enough:

Reactive._inMode("run", () => { /* … executes under the run interpreter … */ });
Save, swap and restore the interpreter around a callback

The interpreters

ModeWhat it does
defineInclude-time. Module/Function/Type register structure; function bodies are stored, not run.
runExecution. The real value/lock/gather machinery, and the update loop that drives the DOM.
discoverA dry pass for a locked If/Each: records which contexts a callback could reach, all branches, no side effects.
typecheckWalks types and inputs and asserts; executes nothing. Runs before mount. (planned)
codegenEach op emits target source rather than executing it: JavaScript, a shader, a document. (planned)
Built today: define and run, the full runtime behind every live example, including the scope tree, If/Each, locks, loading and gather. The remaining interpreters (typecheck, codegen) are still scaffolded; the point of the architecture is that they are additive, never a rewrite.

Why this shape

This is the tagless-final pattern: a language expressed as calls on an interface rather than as a data structure to walk. It gives the same multi-target power a compiler's AST would (run / check / generate) while the program is the calls, sparing you an AST to build. Small runtime, high ceiling.