12 KiB
DreamStack Implementation Plan
Build a working prototype of the DreamStack vision — a new UI framework with compile-time reactivity, algebraic effects, constraint layout, and physics animation. The strategy is to bootstrap pragmatically: use Rust for the compiler/runtime core, target WASM + DOM, and prove each pillar with working demos before unifying them.
Phase 0 — Foundation (Weeks 1–3)
Goal: A working compiler that turns DreamStack syntax into executable WASM + JS glue.
Compiler Pipeline (Rust)
[NEW] compiler/crates/ds-parser/
- Hand-written recursive descent parser for DreamStack syntax
- Produces an AST of
view,let,when,match,effect,on,stream,layoutconstructs - Homoiconic representation: AST nodes are also the runtime data structure (tagged vectors/maps)
[NEW] compiler/crates/ds-analyzer/
- Signal graph extraction: Static analysis pass that identifies signals, derived values, and their dependencies → builds a DAG
- Effect collection: Catalogs all
performsites and their expected effect signatures - Type inference: Hindley-Milner base with structural typing; dependent types deferred to Phase 4
[NEW] compiler/crates/ds-codegen/
- Emits Rust → WASM for:
- Signal graph runtime (push-based notification)
- Constraint solver (Cassowary algorithm)
- Spring physics engine
- Emits JS glue for DOM bindings — surgical
textContent,setAttribute,insertBefore,removeChildcalls (no VDOM) - Output format: single
.wasm+ single.jsmodule
[NEW] compiler/crates/ds-cli/
dreamstack build <file.ds>→ produces.wasm+.js+.htmldreamstack dev <file.ds>→ dev server with file watching + hot-reloaddreamstack check <file.ds>→ type check + signal graph validation
Deliverable
A counter app (examples/counter.ds) compiles and runs in the browser with reactive signal updates, no VDOM.
Phase 1 — Reactive Core (Weeks 4–6)
Goal: Fine-grained reactivity with compile-time dependency tracking, proving the "no re-render" model.
Signal Runtime (Rust → WASM)
[NEW] runtime/crates/ds-signals/
Signal<T>— mutable source, notifies dependents on writeDerived<T>— computed from signals, lazy + cached, auto-invalidatedEffect— runs side-effect when dependencies change (for DOM updates only — user-facing effects use algebraic effects)- Batching: multiple signal writes in one tick coalesce into a single propagation pass
- Topological sort of the DAG ensures glitch-free propagation (no intermediate states visible)
DOM Binding Layer (JS)
[NEW] runtime/js/dom-bindings.js
- Minimal JS layer (~3KB) that the codegen targets
- Functions:
bindText(nodeId, signalId),bindAttr(nodeId, attr, signalId),bindVisible(nodeId, signalId),mountChildren(parentId, listSignalId, templateFn) - Each binding registers itself as an effect on the signal graph
- No framework runtime — just a bag of DOM mutation functions
Benchmark Suite
[NEW] bench/
- Signal propagation: 1K / 10K / 100K signals, measure update latency
- DOM updates: compare against Solid.js, Svelte 5, vanilla JS
- Target: <1ms for 1K signal cascade, <16ms for 10K
Deliverable
A TodoMVC app (examples/todomvc.ds) with add/remove/toggle/filter — all reactive, no VDOM, benchmarked against Solid.js.
Phase 2 — Effect System & Streams (Weeks 7–10)
Goal: Algebraic effects for side-effects, stream primitives for temporal data.
Algebraic Effects (Rust → WASM)
[NEW] runtime/crates/ds-effects/
- Effect declarations:
effect fetchUser(id: UserId): Result<User, ApiError> performkeyword: suspends the current continuation, delegates to the nearest handlerhandle ... withblocks: install effect handlers at any level of the component tree- Continuation-based: handlers receive a
resumefunction to continue execution - Built-in effects:
Http,Time,Random,Storage,Console
Stream Engine
[NEW] runtime/crates/ds-streams/
Stream<T>— push-based async sequence- Core operators:
map,filter,flatmap,merge,combine,debounce,throttle,distinct,take,skip,scan stream from <event>— creates a stream from DOM events- Streams integrate with the signal graph: a stream's latest value is a signal
- Backpressure: drop or buffer strategies, configurable per stream
Deliverable
A search-with-autocomplete app (examples/search.ds) using debounce, flatmap over an HTTP effect, with the effect handler swappable for testing.
Phase 3 — Layout & Animation (Weeks 11–14)
Goal: Constraint-based layout engine and physics-based animation, both running in WASM.
Constraint Solver
[NEW] runtime/crates/ds-layout/
- Implement the Cassowary simplex-based constraint solving algorithm in Rust
- Constraint types:
eq,gte,lte,clamp,ratio - Reactive integration: constraints reference signals → solver re-runs when inputs change
- Output: absolute
(x, y, width, height)for each element, applied directly to DOM viatransform: translate()(avoids reflow) - Performance target: solve 500 constraints in <2ms
Spring Physics
[NEW] runtime/crates/ds-springs/
Spring { value, velocity, target, stiffness, damping, mass }- RK4 integrator, fixed timestep (1/120s), interpolated for display
spring.target = xtriggers animation to new target (interruptible by default)- Springs are signals — anything that reads
spring.valueauto-updates - Gesture integration: direct-manipulation by setting
spring.targetto pointer position
Animation Scheduler
[NEW] runtime/js/raf-scheduler.js
- Drives springs via
requestAnimationFrame - When no springs are active, scheduler sleeps (zero CPU when idle)
- Coordinates with signal graph: spring value changes go through normal propagation
Deliverable
A draggable panel layout (examples/dashboard.ds) with resizable sidebar (constraints) and spring-animated panel transitions.
Phase 4 — Type System (Weeks 15–18)
Goal: Dependent types for UI correctness guarantees.
Type Checker
[NEW] compiler/crates/ds-types/
- Base: Hindley-Milner with let-generalization, structural records
- Refinement types:
type PositiveInt = { n: Int | n > 0 }— checked at compile time where possible, runtime where not - Signal-aware types:
Signal<T>is a first-class type; the compiler tracks which values are reactive - Effect types: functions declare which effects they may perform → compiler verifies all effects are handled
- UI types:
Viewtype ensures only valid UI expressions appear inviewblocks
Error Messages
- Inspired by Elm: suggest fixes, show the specific constraint that failed, include code context
- Signal graph visualization in error output for dependency-related errors
Deliverable
The compiler catches: unhandled effects, type mismatches in signal derivations, invalid UI expressions — all with helpful error messages.
Phase 5 — Live Editor (Weeks 19–24)
Goal: Bidirectional structural editing — the killer feature.
Incremental Compiler
[NEW] compiler/crates/ds-incremental/
- Tracks which AST nodes changed between edits
- Re-analyzes only affected signal subgraph
- Re-generates only changed DOM bindings
- Target: <50ms from keystroke to live update
Editor Integration
[NEW] editor/
- Web-based editor (Monaco or CodeMirror 6 with custom language mode)
- Split pane: code ↔ live preview
- Code → Preview: incremental compile on every keystroke
- Preview → Code: click an element in preview → highlights source; drag to reorder → AST rewrite → code updates
- State preservation: signals retain their current values across edits
Visual Inspector
- Overlay on the live preview showing signal dependencies, constraint wires, spring states
- Click a DOM element → see its signal bindings, constraint relationships, effect dependencies
Deliverable
A working playground at dreamstack.dev where users can write DreamStack code and see live results with bidirectional editing.
Phase 6 — Production Readiness (Weeks 25–30)
Goal: SSR, ecosystem tooling, documentation, and real-world validation.
Server-Side Rendering
- Compile DreamStack to static HTML + hydration script
- Streaming SSR: emit HTML as constraint solver resolves layout
- Effect handlers for server context (no DOM, no springs)
Package System
dreamstack add <package>— package registry for reusable views and effect handlers- Standard library: common UI patterns (buttons, inputs, lists, modals, toasts)
- Interop: import/export with JavaScript modules
Documentation & Examples
- Language reference
- Tutorial: "Build a real app in 30 minutes"
- Cookbook: common patterns (forms, routing, data fetching, auth)
- Migration guide: "Coming from React" / "Coming from Svelte"
Implementation Language Choices
| Component | Language | Rationale |
|---|---|---|
| Parser, Analyzer, Codegen, Type Checker | Rust | Performance, WASM target, memory safety without GC |
| Signal Runtime, Constraint Solver, Springs | Rust → WASM | Must run at 60fps, no GC pauses |
| DOM Bindings, RAF Scheduler | JavaScript | Must interact with browser APIs directly |
| CLI | Rust (clap) | Fast startup, single binary distribution |
| Editor | TypeScript | CodeMirror/Monaco ecosystem, web-native |
| Dev Server | Rust (axum) | Fast file watching, WebSocket HMR |
Key Technical Risks
| Risk | Mitigation |
|---|---|
| Compile-time signal analysis is undecidable in general | Restrict to analyzable patterns; fall back to runtime tracking for dynamic cases |
| Cassowary solver is O(n²) worst case | Incremental solving; partition independent constraint groups |
| WASM ↔ JS boundary overhead for DOM updates | Batch mutations; use FinalizationRegistry for memory management |
| Algebraic effects require delimited continuations | Use CPS transform in codegen; or one-shot continuations via WASM stack switching (Stage 3 proposal) |
| Homoiconic representation vs performance | Two representations: rich AST for editor, optimized IR for runtime |
Verification Plan
Since this is a greenfield language/framework, verification is demo-driven:
Phase 0–1: Reactive Core
# Build the compiler and run the counter example
cargo build --release -p ds-cli
./target/release/dreamstack build examples/counter.ds
# Serve and verify in browser
./target/release/dreamstack dev examples/counter.ds
# Run signal propagation benchmarks
cargo bench -p ds-signals
Phase 2: Effects & Streams
# Run effect system unit tests
cargo test -p ds-effects
# Run the search example with mock handler (automated test)
./target/release/dreamstack test examples/search.ds
Phase 3: Layout & Animation
# Constraint solver correctness tests
cargo test -p ds-layout
# Visual regression: screenshot comparison of dashboard example
./target/release/dreamstack screenshot examples/dashboard.ds --compare snapshots/
Phase 5: Live Editor
- Manual verification: Open the playground, type code, verify preview updates <50ms
- Bidirectional test: Drag an element in preview, verify code updates correspondingly
Important
The user should weigh in on which phase to prioritize first. The plan assumes linear progression, but Phases 1–3 could be parallelized if multiple contributors are involved. Phase 4 (dependent types) is the highest-risk and could be deferred to a v2.