# 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?*

---

## Implementation Status ✅

DreamStack is **real and running** — 8 Rust crates, 205 tests, 51 compilable examples, 14 registry components, ~7KB runtime.

```
.ds source → ds-parser → ds-analyzer → ds-codegen → JavaScript
                ↓              ↓
            ds-types       ds-layout
          (type checker)  (Cassowary solver)
```

### What Works Today

| Feature | Syntax | Status |
|---------|--------|--------|
| Signals | `let count = 0` | ✅ Fine-grained, auto-tracked |
| Derived | `let doubled = count * 2` | ✅ `DS.derived()`, lazy evaluation |
| Interpolation | `"Count: {count}"` | ✅ Reactive `DS.effect()` |
| Conditional | `when count > 5 -> text "hi"` | ✅ Mount/unmount |
| If/else | `if x then a else b` | ✅ |
| Match | `match state \| Loading -> ...` | ✅ |
| List rendering | `for item in items -> text item` | ✅ Reactive, keyed |
| Components | `component Card(title) = ...` | ✅ Reactive props (getter fns) |
| Component import | `import { Badge } from "./badge"` | ✅ Recursive resolution |
| Effects | `effect fetch(id): Result` / `perform` | ✅ Algebraic |
| Springs | `spring(target: 0, stiffness: 300)` | ✅ RK4 physics |
| Layout | `layout { sidebar.width == 250 }` | ✅ Cassowary solver |
| Types | `type PositiveInt = Int where x > 0` | ✅ Refinement types |
| Router | `route "/path" -> body` / `navigate` | ✅ Hash-based |
| Two-way binding | `input { bind: name }` | ✅ Signal ↔ input |
| Async resources | `DS.resource()` / `DS.fetchJSON()` | ✅ Loading/Ok/Err |
| Physics scene | `scene { gravity_y: g } [ circle {...} ]` | ✅ Rapier2D WASM |
| Constraints | `constrain el.width = expr` | ✅ Reactive solver |
| Streaming (signal) | `stream on "ws://..." { mode: signal }` | ✅ Bidirectional, versioned diffs |
| Streaming (receiver) | `stream from "ws://..."` | ✅ Auto-reconnect, field select |
| Streaming (WebRTC) | `transport: webrtc` | ✅ P2P data channel + WS fallback |
| Stream output filter | `output: paddleX, ballY, score` | ✅ Skip internal signals |
| Dev server | `dreamstack dev app.ds` | ✅ File watcher + HMR polling |
| Playground | `dreamstack playground` | ✅ Monaco editor + live preview |
| CLI check | `dreamstack check app.ds` | ✅ Signal graph visualization |
| TSX converter | `dreamstack convert component.tsx` | ✅ React → DreamStack |
| Component registry | `dreamstack add badge` | ✅ 14 components |
| Timer merging | `every 33 -> ...` (multiple) | ✅ Single `setInterval` per interval |
| Sound | `play_tone(440, 60)` | ✅ Built-in oscillator |

### CLI Commands

```bash
dreamstack build app.ds              # Compile to HTML+JS
dreamstack dev app.ds                # Dev server with hot reload (port 3000)
dreamstack check app.ds              # Analyze signal graph, type check
dreamstack stream app.ds             # Compile + serve with streaming
dreamstack playground                # Monaco editor playground (port 4000)
dreamstack add badge                 # Add a registry component
dreamstack add --list                # List all available components
dreamstack convert file.tsx          # Convert React/TSX → DreamStack
dreamstack convert button --shadcn   # Convert from shadcn/ui registry
dreamstack init my-app               # Initialize new project
```

### Registry Components (14)

| Component | File | Description |
|-----------|------|-------------|
| Alert | `alert.ds` | Status messages with variants |
| Avatar | `avatar.ds` | Profile images with sizes |
| Badge | `badge.ds` | Status indicators (success/warning/error/info) |
| Button | `button.ds` | Click actions with variants |
| Card | `card.ds` | Content containers |
| Dialog | `dialog.ds` | Modal overlays |
| Input | `input.ds` | Text inputs with binding |
| Progress | `progress.ds` | Progress bars |
| Select | `select.ds` | Dropdown selects |
| Separator | `separator.ds` | Visual dividers |
| Stat | `stat.ds` | Statistic displays (value, label, trend) |
| Tabs | `tabs.ds` | Tabbed navigation |
| Toast | `toast.ds` | Notification toasts |
| Toggle | `toggle.ds` | On/off switches |

### Examples (48 compilable .ds files)

**Games:**
- `game-pong.ds` — Multiplayer Pong with keyboard, sound, streaming
- `game-breakout.ds` — Breakout with 5 rows, collision, score, streaming
- `game-snake.ds` — Snake game
- `game-reaction.ds` — Reaction time test

**Streaming:**
- `streaming-counter.ds` — Counter synced across tabs
- `streaming-clock.ds` — Clock streamed to viewers
- `streaming-dashboard.ds` — Real-time dashboard via relay
- `streaming-stats.ds` — Signal stats viewer
- `streaming-mood.ds` — Collaborative mood board
- `streaming-physics.ds` — Physics scene streaming
- `streaming-webrtc.ds` — P2P WebRTC streaming
- `streaming-receiver.ds` — Generic stream receiver
- `pong-viewer.ds` — Spectator view for Pong
- `game-viewer.ds` — Generic game viewer

**Audio:**
- `step-sequencer.ds` — 16-step drum machine with Web Audio API
- `beats-viewer.ds` — Spectator view for step sequencer

**UI Patterns:**
- `counter.ds` — 3-line counter
- `list.ds` — Dynamic list with add/remove
- `todo.ds` / `todomvc.ds` — TodoMVC
- `form.ds` — Form with validation
- `router-demo.ds` — Multi-page routing
- `dashboard.ds` — Dashboard layout
- `component-gallery.ds` — Component showcase
- `showcase.ds` — Full feature showcase
- `project-manager.ds` — Kanban-style project tracker
- `springs.ds` — Spring physics animations

**Language Features:**
- `language-features.ds` — Comprehensive syntax demo
- `refined-types.ds` — Refinement type guards
- `import-demo.ds` — Component imports
- `slot-demo.ds` — Component children/slots
- `each-demo.ds` — `each` loop rendering
- `when-else-demo.ds` — Conditional rendering
- `multi-action.ds` / `timer-multi-action.ds` — Multi-statement handlers
- `callback-demo.ds` — Callback props
- `physics.ds` — Rapier2D physics scene
- `bench-signals.ds` — Signal performance benchmarks

### DreamStack vs React

| | **DreamStack** | **React** |
|---|---|---|
| Reactivity | Fine-grained signals, surgical DOM | VDOM diff, re-render subtrees |
| State | `count += 1` direct | `setState(c => c+1)` immutable |
| Derived | `let d = count * 2` auto | `useMemo(() => ..., [deps])` manual |
| Effects | Auto-tracked, algebraic | `useEffect(..., [deps])` manual |
| Conditional | `when x -> text "y"` | `{x && <span>y</span>}` |
| Lists | `for item in items -> ...` | `{items.map(i => ...)}` |
| Router | `route "/path" -> body` | `react-router` (external) |
| Forms | `input { bind: name }` | `useState` + `onChange` (manual) |
| Animation | Built-in springs | framer-motion (external) |
| Physics | Built-in Rapier2D scene | matter.js (external) |
| Layout | Built-in Cassowary | CSS only |
| Streaming | Built-in bidirectional | WebSocket libraries (external) |
| Types | Native refinement types | TypeScript (external) |
| Bundle | **~7KB** | **~175KB** |
| Ecosystem | 48 examples, 14 components | Massive |

### Benchmarks (signal propagation)

| Benchmark | Ops/sec | Signals |
|-----------|---------|---------|
| Wide Fan-Out (1→1000) | 46K | 1,001 |
| Deep Chain (100 deep) | 399K | 100 |
| Diamond Dependency | 189K | 4 |
| Batch Update (50) | 61K | 50 |
| Mixed Read/Write | 242K | 10 |

---

## Quick Start

### Counter (3 lines of logic)

```
let count = 0

view counter =
  column [
    text "Count: {count}"
    button "+" { click: count += 1 }
  ]
```

### Multiplayer Pong (40 lines)

```
let ballX = 300
let ballY = 200
let bvx = 4
let bvy = 3
let p1y = 180

on keydown(ev) -> p1y = if ev.key == "ArrowUp" then p1y - 30 else p1y

every 33 -> ballX = ballX + bvx
every 33 -> ballY = ballY + bvy
every 33 -> bvx = if ballX > 590 then -4 else bvx
every 33 -> bvy = if ballY < 5 then 3 else bvy

stream pong on "ws://localhost:9100/peer/pong" {
  mode: signal,
  output: ballX, ballY, p1y
}

view pong =
  stack { style: "position:relative; width:600px; height:400px; background:#1a1a2e" } [
    column { style: "...ball styles...", top: ballY, left: ballX } []
    column { style: "...paddle...", top: p1y } []
  ]
```

### Spectator View (5 lines)

```
let game = stream from "ws://localhost:9100/peer/pong"
  select [ballX, ballY, p1y]

view viewer =
  stack { style: "..." } [
    column { style: "...ball...", top: game.ballY, left: game.ballX } []
    column { style: "...paddle...", top: game.p1y } []
  ]
```

### Run It

```bash
# Install
cargo install --path compiler/ds-cli

# Build
dreamstack build examples/counter.ds -o dist

# Dev server (with hot reload)
dreamstack dev examples/game-pong.ds

# With streaming
cargo run -p ds-stream             # Tab 1: start relay
dreamstack dev examples/game-pong.ds  # Tab 2: play
open dist/index.html               # Tab 3: spectate (pong-viewer.ds)
```

---

## Architecture

### Compiler Pipeline

```
                     ┌─────────────┐
  .ds source ───────►│  ds-parser   │──► AST (Program)
                     └──────┬──────┘
                            │
                     ┌──────▼──────┐
                     │ ds-analyzer  │──► SignalGraph (DAG)
                     └──────┬──────┘       + DomBindings
                            │              + SignalManifest
                     ┌──────▼──────┐
                     │  ds-codegen  │──► Single-file HTML+JS
                     └──────┬──────┘       (~7KB runtime)
                            │
                     ┌──────▼──────┐
                     │   ds-cli    │──► dev/build/stream/check
                     └─────────────┘
```

### Signal Graph (Compile-Time)

```
Signal: count (Source)
  ├──► Derived: doubled (DS.derived)
  │       └──► [DOM] TextNode "Doubled: {doubled}"
  ├──► [DOM] TextNode "Count: {count}"
  └──► [Stream] _streamDiff("count", count.value)
```

- **No virtual DOM.** Compiler maps signals → specific DOM nodes at build time
- **No re-rendering.** Components execute once, set up reactive bindings
- **No dependency arrays.** Compiler infers all dependencies from code
- **Timer merging.** All `every 33` statements share one `setInterval`

### Reactive Runtime

```javascript
// Source signal
const count = DS.signal(0);

// Derived signal (auto-updates)
const doubled = DS.derived(() => count.value * 2);

// Effect (auto-tracked, re-runs on dependency change)
DS.effect(() => { el.textContent = `Count: ${count.value}`; });

// Component props: getter functions for live reactivity
DS_Badge({ label: () => `Score: ${score.value}` });
```

### Stream Protocol (16-byte binary header)

```
┌────────┬─────────┬──────────┬────────────┬───────┬────────┬────────┐
│ type   │ flags   │ seq      │ timestamp  │ width │ height │ length │
│ u8     │ u8      │ u16      │ u32        │ u16   │ u16    │ u32    │
└────────┴─────────┴──────────┴────────────┴───────┴────────┴────────┘
```

| Mode | What's Sent | Bandwidth |
|------|-------------|-----------|
| `signal` (default) | JSON diffs of changed signals | ~2 KB/s |
| `delta` | XOR + RLE compressed pixel deltas | ~50 KB/s |
| `pixel` | Raw RGBA framebuffer | ~30 MB/s |

Features:
- **Bidirectional sync** with per-signal version counters
- **Output filtering** — only listed signals are broadcast
- **Exponential reconnect** — 2s → 4s → 8s, max 30s, reset on success
- **WebRTC data channel** with WebSocket fallback
- **Deduplication** — skip unchanged values

---

## Vision

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.

### Core Properties

| Property | Inspiration | Why |
|---|---|---|
| **Homoiconic** | Clojure, Lisp | UI = data. Code = data. Everything is transformable |
| **Refinement types** | Liquid Haskell | `type Percent = Int where value >= 0 and value <= 100` |
| **Algebraic effects** | Eff, Koka, OCaml 5 | Side effects as first-class, composable, interceptable values |
| **Reactive by default** | Svelte, Solid, Excel | No `useState`, no subscriptions. Assignment *is* the API |
| **Structural typing** | TypeScript, Go | Flexible composition without class hierarchies |
| **Compiled to JS** | Svelte, Solid | Near-zero runtime overhead |

### Syntax Reference

```
-- Signals (mutable state)
let count = 0
let name = "world"
let items = [1, 2, 3]

-- Derived signals (auto-updated)
let doubled = count * 2
let greeting = "Hello, {name}!"

-- Refinement types
type PositiveInt = Int where value > 0
let score: PositiveInt = 10

-- Event handlers
on keydown(ev) -> count = if ev.key == "ArrowUp" then count + 1 else count

-- Timers
every 33 -> ballX = ballX + velocity

-- Conditional rendering
when count > 10 -> text "High!"

-- Pattern matching
match state
  "loading" -> spinner
  "error" -> text "Failed"
  _ -> text "Ready"

-- For loops
for item, i in items -> text "{i}: {item}"

-- Components
component Card(title, children) =
  column { variant: "card" } [
    text title { variant: "card-title" }
    slot
  ]

-- Imports
import { Badge, Card } from "../registry/components/badge"

-- Routes
route "/" -> text "Home"
route "/about" -> text "About"

-- Springs
let x = spring(target: 0, stiffness: 300, damping: 30)

-- Streaming
stream app on "ws://localhost:9100/peer/app" {
  mode: signal,
  output: count, name
}

-- Receiving streams
let remote = stream from "ws://localhost:9100/peer/app"
  select [count, name]

-- Views
view main =
  column [
    text "Hello {name}"
    button "Click" { click: count += 1 }
  ]
```

---

## Effect System: Algebraic Effects

```
effect fetchUser(id: UserId): Result<User, ApiError>

view profile(id: UserId) =
  let user = perform fetchUser(id)
  match user
    Loading -> skeleton-loader
    Ok(u)   -> column [ avatar u.photo, text u.name ]
    Err(e)  -> error-card e | with retry: perform fetchUser(id)
```

---

## Layout: Constraint-Based

```
layout dashboard {
  sidebar.width == 250
  main.x == sidebar.x + sidebar.width
  main.width == parent.width - sidebar.width [strong]
}
```

Uses a Cassowary constraint solver. Constraints are reactive — when viewport changes, layout re-solves in a single pass.

---

## Animation: Physics-Based Springs

```
let panel_x = spring(target: 0, stiffness: 300, damping: 30)

on toggle_sidebar ->
  panel_x.target = if open then 250 else 0

view sidebar =
  panel { x: panel_x } [ nav-items ]
```

Springs are interruptible, gesture-driven, and composable through the same signal system.

---

## Physics: Rapier2D WASM

```
let gravity_y = 980

view main =
  scene { width: 700, height: 450, gravity_y: gravity_y } [
    circle { x: 200, y: 80, radius: 35, color: "#8b5cf6" }
    rect   { x: 500, y: 100, width: 80, height: 50, color: "#10b981" }
  ]

  button "Anti-Gravity" { click: gravity_y = -500 }
```

---

## Streaming: Built-In Multiplayer

Any DreamStack app becomes multiplayer with one declaration:

```
stream pong on "ws://localhost:9100/peer/pong" {
  mode: signal,
  output: ballX, ballY, paddleY, score
}
```

The compiler automatically:
1. Connects to the relay via WebSocket
2. Wraps signal mutations with `_streamDiff()` calls
3. Sends versioned JSON diffs (conflict resolution via version counters)
4. Filters to only broadcast `output` signals (skips internals like velocity)
5. Reconnects with exponential backoff on disconnect

Viewers connect with `stream from`:
```
let game = stream from "ws://localhost:9100/peer/pong"
  select [ballX, ballY, paddleY, score]
```

---

## Comparison

| Capability | React | Svelte 5 | Solid.js | Flutter | **DreamStack** |
|---|---|---|---|---|---|
| Reactivity | Pull (VDOM diff) | Runes | Signals | Rebuild | **Compile-time DAG** |
| Side effects | `useEffect` + deps | `$effect` | `createEffect` | Lifecycle | **Algebraic effects** |
| Layout | CSS (external) | CSS (scoped) | CSS (external) | Constraints | **Cassowary (native)** |
| Animation | 3rd party | 3rd party | 3rd party | Physics (native) | **Springs (native)** |
| Streaming | WebSocket libs | WebSocket libs | WebSocket libs | None | **Built-in bidirectional** |
| Runtime | ~175KB | ~2KB | ~7KB | ~2MB | **~7KB** |
| Type safety | TypeScript | TypeScript | TypeScript | Dart | **Refinement types** |
| UI = Data | No (JSX) | No (templates) | No (JSX) | No (widgets) | **Yes (homoiconic)** |

---

## Design Philosophy

1. **The compiler is the framework.** Move work from runtime to compile time
2. **Reactivity is the default.** Every value is live. You opt *out*, not *in*
3. **Effects are values.** First-class, composable, interceptable
4. **Layout and animation are core.** Not CSS bolt-ons or third-party libraries
5. **The editor and runtime are one.** Bidirectional structural editing
6. **UI is data, all the way down.** If you can't `map` over your UI, your abstraction is wrong
7. **Any bitstream in → any bitstream out.** The UI is just one codec

---

## Next Steps

### Phase 1: Polish (estimated ~2h)
- [ ] **Better error messages** — source context with line + caret in parser errors
- [ ] **Route integration test** — multi-page example exercising `route` + `navigate`
- [ ] **WebRTC integration test** — verify P2P data channel transport
- [ ] **Layout constraint test** — example using Cassowary solver

### Phase 2: New Examples (estimated ~2h)
- [ ] **Tetris** — stress-test grid, timers, collision, streaming
- [ ] **Todo with sync** — CRUD + bidirectional streaming sync
- [ ] **Snake polish** — cleanup existing game, add streaming

### Phase 3: Ecosystem (estimated ~1.5h)
- [ ] **Component gallery** — live showcase of all 14 components
- [ ] **Crates.io publish** — `cargo install dreamstack`
- [ ] **Self-hosted playground** — deploy playground as web app
