- Added can_be_pattern() with look-ahead disambiguation
- Ident only treated as pattern if followed by -> or (
- Keywords (row/column/when/each) correctly terminate match
- Match arms now support: "active" -> row [ Badge + text ]
- Siblings after match (text, button, row) no longer consumed
- Project Manager updated with rich row/Badge match arms
- All 6 existing examples pass regression
- Dashboard with metrics, match status, progress bars
- Task Manager with dynamic add/remove via push/remove
- Team directory with member cards and status badges
- Settings with toggle and about section
- 64,622 bytes, zero console errors, all 11 components used
- Home/Counter/Todos/About with hash navigation
- State persists across route changes
- Uses existing router infrastructure (no compiler changes)
- navigate keyword, matchRoute, _route signal
- When/else inside slots: anchor parentNode is null during initial effect
Fixed with named effect function + requestAnimationFrame retry
- Match parser now terminates on ] } else tokens (works inside containers)
- Updated Progress/Badge components
- Added examples/showcase.ds: 5-section demo exercising all features
- AST: When(cond, body) -> When(cond, body, Option<else_body>)
- Parser: optional 'else -> expr' after when body
- Codegen: reactive DOM swap with anchor comments
- Signal graph + type checker updated for 3-arg When
- Component prop signal wrapping: .value compatible accessors
- Added examples/when-else-demo.ds
Codegen: BinOp::Div now emits Math.trunc(l / r)
- Clock displays 0:1:30 instead of 0.016:1.5:30
- Affects both emit_expr and predicate_to_js
Lexer: removed duplicate 'in' keyword mapping
- InKw at line 312 is canonical, removed old In at line 338
Examples: added project-tracker.ds (each loops + cards)
Add compose-metrics.ds (Layer 1): receives counter+clock+stats,
derives uptime/events/status, re-streams on /peer/metrics. This app
is BOTH a receiver and a source.
Add compose-master.ds (Layer 2): receives chained metrics from
Layer 1 + mood direct from Layer 0. Demonstrates multi-layer
signal composition with independent stream mixing.
Verified: Uptime: 51s, Total Events: 9 flowing through the full
three-layer chain to the master dashboard.
The 'default' relay channel accumulated stale Source connections from
previous sessions, causing frame delivery issues to Receivers on
/stream/default. Moving counter to an explicit /peer/counter channel
(matching clock, stats, mood pattern) fixes the composition dashboard.
All 4 streams now show live data: Count: 3, Doubled: 6.
Add 3 new streaming apps with explicit output declarations:
- streaming-clock.ds: output hours, minutes, seconds (tick private)
- streaming-stats.ds: output total, average, max (sum private)
- streaming-mood.ds: output mood, energy, color (clicks private)
Add compose-dashboard.ds that receives all 4 streams via unique
relay channels (/stream/default, /stream/clock, /stream/stats,
/stream/mood) into a single dashboard view.
Each app demonstrates selective signal registration — only declared
outputs are streamed, internal state remains private.
Add 'output: field1, field2' syntax to stream declarations to control
which signals are exposed over the relay. Only listed signals are
registered in _signalRegistry (and thus streamed). Omitting output
streams all signals (backwards-compatible).
Also strips internal sync metadata (_pid, _v) from receiver state
so composition consumers only see clean signal values.
Parser: parse comma-separated idents after 'output:' key
AST: Vec<String> output field on StreamDecl
Codegen: conditional _registerSignal, delete _pid/_v on receive
Example: stream counter on 'ws://...' { mode: signal, output: count, doubled }
- Register derived signals in _signalRegistry so _streamSync includes them
- Auto-sync all signals (source + derived) after flush() recomputes effects
- Fix Object.assign identity check: create new object so signal setter detects changes
- Change _connectStream receiver path from /signal/main to /stream/default
- Initialize stream state with {} instead of null to prevent crashes
- Emit StreamFrom bindings directly without double-wrapping in signal()
Verified: static build shows Count: 9, Doubled: 18 on composition page.
HMR interference with WebSocket connections is a separate issue.
- Added /peer/{name} route to relay: all clients are equal peers
- handle_peer: binary broadcast to all other peers, catchup for late joiners
- Simplified runtime: single /peer/ WS replaces dual source+receiver
- _peerId: random 8-char ID prevents self-echo from broadcast
- _pid in each diff JSON, filtered in _applyRemoteDiff
- streaming-counter.ds: reactive counter with 'stream counter on ws://...'
- streaming-receiver.ds: remote receiver with 'stream from ws://...'
- E2E verified: compiles to streaming JS, connects to relay, sends signal diffs
- Add scene container to AST, lexer, parser, analyzer, and codegen
- Add circle/rect/line as UI elements for physics body declaration
- Compile scene {} to canvas + async WASM init + Rapier2D PhysicsWorld
- Reactive gravity via DS.effect() — bodies wake on gravity change
- Mouse drag interaction with impulse-based body movement
- Compile-time hex color parsing for body colors
- Fix is_signal_ref matching numeric literals (700.value bug)
- Fix body variable uniqueness (next_node_id per body)
- Fix gravity signal detection (check AST Ident before emit_expr)
- Add physics.ds example with 5 bodies + 4 gravity control buttons
- Update DREAMSTACK.md and IMPLEMENTATION_PLAN.md with Phase 10-11
- 39 tests pass across all crates, 22KB output
Phase 6 features:
- ForIn reactive list rendering: for item in items -> body
- Optional index binding: for item, idx in items -> body
- Component declarations: component Name(props) = body
- Component instantiation: ComponentUse { name, props }
Added across 5 crates:
- ds-parser: For/In/Component tokens, ForIn/ComponentDecl AST nodes
- ds-codegen: reactive list effect, component function emission
- ds-types: ForIn/ComponentUse type inference
- local_vars tracking for non-reactive for-in loop vars
Includes examples/list.ds showcasing for-in + when + signals.
Interactive page comparing 5 unique DreamStack capabilities vs React/Svelte/Solid/Vue:
1. Reactivity as a type (Signal<T> in the type system)
2. Algebraic effects (swappable side-effect handlers)
3. Springs are signals (physics auto-propagates through reactive graph)
4. Compile-time dependency graph (static analysis, dead signal elimination)
5. Constraint-based layout (Cassowary solver, not CSS hacks)
Includes live spring physics demo, interactive constraint layout toggle,
side-by-side code comparisons, Elm-style error previews, and comparison table.
Full todo app using DreamStack's signal runtime:
- Add/toggle/remove individual todos
- Filter by all/active/completed
- Clear completed batch action
- Derived reactive stats (total, active, done counts)
- Premium dark theme with glassmorphism, slide-in animations
- No VDOM, no re-renders — pure signal propagation