Commit graph

17 commits

Author SHA1 Message Date
enzotar
8c9f5e8bfb fix: add _streamDiff to push/pop/reverse built-ins
Array-mutating built-in functions now emit DS._streamDiff() for
streaming sync. Previously only signal assignments emitted diffs.
2026-02-25 21:47:50 -08:00
enzotar
a943d2e2e9 feat: peer mode relay + self-echo filtering for true bidirectional sync
- 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
2026-02-25 21:37:17 -08:00
enzotar
5f09886c3c fix: bidirectional streaming sync — phone→laptop now works
- Fix URL routing: /source/default and /stream/default paths
- _streamDiff sends via both source WS and receiver WS (INPUT flag)
- Source rebroadcasts 0x31 diffs from receivers to all other receivers
- Echo loop guard prevents infinite rebroadcast
2026-02-25 21:11:12 -08:00
enzotar
69c7ff1e22 feat: bidirectional signal streaming sync
- _signalRegistry: maps signal names → signal objects
- _registerSignal: called after each DS.signal() declaration
- _applyRemoteDiff: JSON diff → update local signals + flush
- _initStreamReceiver: parallel receiver WS for incoming diffs
- Echo loop guard: _applyingRemoteDiff prevents re-broadcasting
- 0x31 handler in _handleRemoteInput for signal diff frames

Changes sync both directions: laptop → phone, phone → laptop.
2026-02-25 21:00:57 -08:00
enzotar
55ec9353ae feat: v2 codegen hardening — scoped local variables
Replace flat HashSet<String> local_vars with Vec<HashSet<String>> scope
stack. For-in loops push/pop scopes for loop variables. Nested loops
no longer clobber outer loop variable visibility.

Methods: push_scope(), pop_scope(), is_local_var()
110 tests, 0 failures.
2026-02-25 20:39:41 -08:00
enzotar
26d6c4f17a feat: v2 built-in functions — 90+ native functions
Array: len, push, pop, filter, map, concat, contains, reverse, slice,
  indexOf, find, some, every, flat, sort (mutating ops re-trigger signal)
Math: abs, min, max, floor, ceil, round, random, sqrt, pow, sin, cos,
  tan, atan2, clamp, lerp
String: split, join, trim, upper, lower, replace, starts_with, ends_with,
  char_at, substring
Conversion: int, float, string, bool
Console: log, debug, warn
Timer: delay

Also adds ExprStatement support for top-level expressions (log, push, etc).
110 tests, 0 failures.
2026-02-25 20:30:08 -08:00
enzotar
2aa2c7ad8e feat: step sequencer demo — reactive pads, playhead, BPM
Step sequencer: 4 instruments × 8 steps, timer-driven playhead,
toggleable pads, BPM controls with streaming. 75 lines of .ds code.

Parser fixes:
- UI elements checked before LParen (button (if ...) is element, not call)
- Element args support parenthesized expressions: button (if cond ...)
- StringInterp recognized as valid string start in parse_primary/parse_element

Codegen fixes:
- emit_expr checks local_vars: loop var i emits 'i' not 'i.value'
- Array index mutations re-trigger signal: pads.value = [...pads.value]

110 tests, 0 failures.
2026-02-25 19:33:12 -08:00
enzotar
2d07b1652a feat: v2 phase 1 — array access, timer, string interpolation
Array access: Expr::Index in AST, [expr] postfix parsing, codegen for
reads (grid.value[i.value]) and writes (event handler assignments with
root signal extraction for stream diff broadcasting).

Timer: 'every N -> expr' declaration. Every keyword in lexer. EveryDecl
in AST. parse_every_decl in parser. setInterval codegen with DS.flush.

String interpolation: already committed separately.

Type checker: handles Expr::Index (infers array element type).
110 tests, 0 failures.
2026-02-25 19:20:20 -08:00
enzotar
cde84ae270 feat: production hardening — relay v1.0.0, receiver protocol completeness
Relay v1.0.0:
- Max receivers per channel (default: 64) with rejection counting
- Max channels limit (default: 256) with over-limit rejection
- Channel GC: periodic scan removes idle channels after grace period (30s)
- Source reconnection: cache preserved on disconnect, new input channels
- Stats: peak_receivers, total_connections, rejected_connections, uptime
- ChannelState::is_idle(), grace_period_expired() for lifecycle mgmt
- StateCache::clear(), has_state() for cache introspection
- Banner shows config: max receivers, max channels, grace period
- 54 tests (+8 new: channel_max_limit, idle detection, grace period, cache ops)

Receiver (_connectStream):
- Complete frame type handling: SignalSync (full replace), SignalDiff (merge),
  Pixels/Keyframe (emit stream_frame), DeltaPixels (XOR + RLE decode),
  Ping (keepalive), StreamEnd (emit stream_end)
- RLE decoder for delta pixel frames
- Exponential backoff reconnect (1s → capped at 10s)
- Connection stats: frames, bytes, reconnects
- Event emissions: stream_frame, stream_end for app-level handling

105 tests, 0 failures across workspace
2026-02-25 18:30:40 -08:00
enzotar
392e478351 feat: WebRTC transport — peer-to-peer data channels with auto-fallback
Relay:
- /signal/{channel} path for SDP/ICE exchange via WebSocket
- handle_signaling broadcasts text messages between signaling peers
- signaling_tx broadcast channel in ChannelState
- 46 ds-stream tests (+2 signaling path tests)

JS Runtime:
- _initWebRTC(signalingUrl, streamUrl, mode) with RTCPeerConnection
- Unordered DataChannel (ordered:false, maxRetransmits:0) for low latency
- Auto-fallback: WebSocket starts immediately, WebRTC upgrades in ≤5s
- Data channel override of _streamSend for transparent binary protocol

Parser/AST:
- StreamTransport enum (WebSocket, WebRTC)
- transport field in StreamDecl
- Parses: stream x on url { mode: signal, transport: webrtc }

Codegen:
- WebRTC: emits DS._initWebRTC(sigUrl, streamUrl, mode)
- WebSocket: emits DS._initStream(url, mode) (unchanged)

97 tests, 0 failures
2026-02-25 15:02:31 -08:00
enzotar
439a775dec feat(compiler): complete bitstream integration — all 9 changes
- AST: StreamDecl, StreamMode, Declaration::Stream, StreamFrom struct variant
- Lexer: Pixel, Delta, Signals keywords
- Parser: parse_stream_decl with mode block, fixed TokenKind::On match
- Signal graph: streamable flag, SignalManifest, Declaration::Stream detection
- Checker: StreamFrom { source, .. } pattern
- Codegen: DS._initStream(), DS._connectStream(), DS._streamDiff() hooks
- Runtime JS: full streaming layer with binary protocol encoding
- Layout: to_bytes/from_bytes on LayoutRect

82 tests pass (5 new: 3 parser stream + 2 analyzer streamable)
2026-02-25 13:26:59 -08:00
enzotar
d86818ca6a feat(compiler): full bitstream integration across 7 pipeline stages
AST: StreamDecl, StreamMode, Expr::StreamFrom { source, mode }
Lexer: Pixel, Delta, Signals keywords
Parser: parse_stream_decl() with mode parsing, StreamFrom expression
Signal Graph: streamable flag on SignalNode, auto-detect stream decls
Type Checker: StreamFrom returns Type::Stream
Codegen: emit_stream_init phase, StreamFrom → DS.streamConnect(),
  streaming runtime JS (WebSocket relay, binary protocol, signal frames,
  remote input handler, auto-reconnect)
CLI: 'dreamstack stream' command — compile+serve with streaming enabled,
  auto-inject stream declaration for the first view

All 77 workspace tests pass, 0 failures.
2026-02-25 13:13:21 -08:00
enzotar
ea64617569 feat: physics language integration — scene container with Rapier2D WASM
- 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
2026-02-25 10:58:43 -08:00
enzotar
a35d44bd59 feat: two-way binding, form props, and async resources
Phase 8 features:
- bind prop: two-way signal <-> input sync
- placeholder, value, style, disabled props
- DS.resource() for reactive async data fetching
- DS.fetchJSON() convenience wrapper
- Props-only element parsing: input { bind: x }
- examples/form.ds: contact form with validation

Fixed: double .value.value bug in bind codegen.
2026-02-25 08:08:37 -08:00
enzotar
adff40d47f feat: hash-based router + keyed list reconciliation
Phase 7 features:
- route "/path" -> body declarations with hash-based routing
- navigate "/path" built-in function
- DS.route signal tracks current hash path
- DS.matchRoute() with :param pattern matching
- DS.keyedList() for keyed DOM reconciliation
- Route-aware mounting: views + routes compose
- examples/router.ds: 3-page app (home/about/counter)
- State persists across route changes (10818 bytes)
2026-02-25 07:54:00 -08:00
enzotar
ca45c688df feat: for-in list rendering + component system
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.
2026-02-25 01:33:28 -08:00
enzotar
a634152318 feat: DreamStack compiler foundation — Phase 0/1
Complete compiler pipeline from .ds source to reactive browser apps:

- ds-parser: lexer (string interpolation, operators, keywords) + recursive
  descent parser with operator precedence + full AST types
- ds-analyzer: signal graph extraction (source/derived classification),
  topological sort for glitch-free propagation, DOM binding analysis
- ds-codegen: JavaScript emitter with embedded reactive runtime (~3KB
  signal/derived/effect system) and dark-theme CSS design system
- ds-cli: build (compile to HTML+JS), dev (live server), check (analyze)

Verified working: source signals, derived signals, event handlers,
conditional rendering (when), 12 unit tests passing, 6.8KB output.
2026-02-25 00:03:06 -08:00