# DreamStack: Reinventing the UI from First Principles
> *What if we threw away every assumption about web UI frameworks and started over — with the sole goal of creating ultra-reactive, dynamic interfaces?*
React was revolutionary in 2013. But it carries a decade of compromises: the virtual DOM, hooks with manual dependency arrays, re-rendering entire subtrees, CSS from 1996, animations bolted on as an afterthought. DreamStack asks: **what would we build today if none of that existed?**
The answer is a unified system where **UI is data, reactivity is automatic, effects are composable values, layout is constraint-based, animation is physics-native, and the editor and runtime are one.**
---
## The Language
Not Clojure. Not TypeScript. A new language that steals the best ideas from everywhere.
| **Dependent types** | Idris, Agda | Types that express "this button is disabled *when* the form is invalid" at the type level |
| **Algebraic effects** | Eff, Koka, OCaml 5 | Side effects as first-class, composable, interceptable values |
| **Reactive by default** | Svelte, Solid, Excel | No `useState`, no subscriptions. Values *are* reactive. Assignment *is* the API |
| **Structural typing** | TypeScript, Go | Flexible composition without class hierarchies |
| **Compiled to native + WASM** | Rust, Zig | Near-zero runtime overhead. No GC pauses during animations |
### Syntax
```
-- Signals are the primitive. Assignment propagates automatically.
let count = 0
let doubled = count * 2 -- derived, auto-tracked
let label = "Count: {doubled}" -- derived, auto-tracked
-- UI is data. No JSX, no templates, no virtual DOM.
view counter =
column [
text label -- auto-updates when count changes
button "+" { click: count += 1 }
-- Conditional UI is just pattern matching on signals
when count > 10 ->
text "🔥 On fire!" | animate fade-in 200ms
]
```
No hooks. No dependency arrays. No re-renders. **The compiler builds a fine-grained reactive graph at compile time.**
---
## Reactivity: Compile-Time Signal Graph
This is the biggest departure from React. React's model is fundamentally **pull-based** — re-render the tree, diff it, patch the DOM. That's backwards.
### Push-Based with Compile-Time Analysis
```
Signal: count
├──► Derived: doubled
│ └──► Derived: label
│ └──► [direct DOM binding] TextNode #47
└──► Condition: count > 10
└──► [mount/unmount] text "🔥 On fire!"
```
**Key principles:**
- **No virtual DOM.** The compiler knows at build time exactly which DOM nodes depend on which signals. When `count` changes, it updates *only* the specific text node and evaluates the condition. Nothing else runs.
- **No re-rendering.** Components don't re-execute. They execute *once* and set up reactive bindings.
- **No dependency arrays.** The compiler infers all dependencies from the code. You literally cannot forget one.
- **No stale closures.** Since there are no closures over render cycles, the entire class of bugs vanishes.
This extends Solid.js's approach with full compile-time analysis in a purpose-built language.
---
## Effect System: Algebraic Effects for Everything
Every side-effect — HTTP, animations, time, user input, clipboard, drag-and-drop — is an **algebraic effect**. Effects are values you can compose, intercept, retry, and test.
| Drag events | Complex event handler state machines | Stream of positions |
One abstraction. One composition model. Everything snaps together.
---
## Layout: Constraint-Based, Not Box-Based
CSS's box model is from 1996. Flexbox and Grid are patches on a fundamentally limited system. DreamStack starts over with a **constraint solver**.
```
-- Declare relationships, not boxes
layout dashboard =
let sidebar.width = clamp(200px, 20vw, 350px)
let main.width = viewport.width - sidebar.width
let header.height = 64px
let content.height = viewport.height - header.height
-- Constraints, not nesting
sidebar.left = 0
sidebar.top = header.height
sidebar.height = content.height
main.left = sidebar.right
main.top = header.height
main.right = viewport.right
-- Responsive is just different constraints
when viewport.width <768px->
sidebar.width = 0 -- collapses
main.left = 0 -- takes full width
```
Inspired by Apple's **Auto Layout** (Cassowary constraint solver), but made reactive. When `viewport.width` changes, the constraint solver re-solves and updates positions in a single pass. No layout thrashing. No "CSS specificity wars."
### Advantages Over CSS
- **No cascade conflicts** — constraints are explicit and local
- **No z-index hell** — layering is declarative
- **No media query breakpoints** — responsiveness emerges from constraints
- **Animations are free** — animating a constraint target is the same as setting it
Animations aren't CSS transitions bolted on after the fact. They're part of the reactive graph.
```
-- A spring is a signal that animates toward its target
let panel_x = spring(target: 0, stiffness: 300, damping: 30)
-- Change the target → the spring animates automatically
on toggle_sidebar ->
panel_x.target = if open then 250 else 0
-- Gestures feed directly into springs
on drag(event) ->
panel_x.target = event.x -- spring follows finger
on drag-end(event) ->
panel_x.target = snap-to-nearest [0, 250] event.x
-- UI just reads the spring's current value
view sidebar =
panel { x: panel_x } [
nav-items
]
```
### Design Principles
- **Interruptible:** Start a new animation mid-flight. The spring handles the physics — no jarring jumps, no "wait for the current animation to finish."
- **Gesture-driven:** Touch/mouse input feeds directly into the animation model. No separate "gesture handler" → "state update" → "CSS transition" pipeline.
- **60fps guaranteed:** Springs resolve on the GPU. The main thread never blocks.
- **Composable:** Combine springs, easing curves, and physics simulations using the same stream operators as everything else.
---
## Runtime: Tiny, Compiled, No GC Pauses
```
┌──────────────────────────────────────────┐
│ Compiled Output │
├──────────────────────────────────────────┤
│ Signal Graph (static DAG) ~2KB │
│ Constraint Solver (layout) ~4KB │
│ Spring Physics (animations) ~1KB │
│ Effect Runtime (handlers) ~2KB │
│ DOM Patcher (surgical updates) ~3KB │
├──────────────────────────────────────────┤
│ Total Runtime: ~12KB │
│ (vs React ~45KB + ReactDOM ~130KB) │
└──────────────────────────────────────────┘
```
The compiler does the heavy lifting. The runtime is tiny because there is:
- No virtual DOM diffing algorithm
- No fiber scheduler
- No hook state management system
- No reconciliation algorithm
- No garbage collector pauses during animation frames
---
## The Killer Feature: Live Structural Editing
Because the language is homoiconic (code = data), the **editor IS the runtime:**
```
┌─────────────────────────────────┐
│ Live Editor │
│ │
│ view counter = │ ← Edit this...
│ column [ │
│ text "Count: {count}" │
│ button "+" { ... } │
│ ] │
│ │
│ ───────────────────────────── │
│ │
│ ┌─────────────┐ │ ← ...see this update
│ │ Count: 42 │ │ instantly, with state
│ │ [ + ] │ │ preserved.
│ └─────────────┘ │
│ │
└─────────────────────────────────┘
```
- Drag and drop UI elements in the preview → the **code updates**.
- Edit the code → the **preview updates**.
- Both directions, simultaneously, with state preserved.
- Not a design tool that generates code — **the code IS the design tool**.
This is possible because:
1.**Homoiconicity** means UI structure is inspectable and modifiable data
2.**Immutable signals** mean state survives code changes
3.**Compile-time signal graph** means changes are surgical, not full-page reloads