2026-02-27 16:40:12 -08:00
-- DreamStack Tetris
-- Blocks fall. They collide. They freeze. Lines clear.
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
--
-- Run:
-- Tab 1: cargo run -p ds-stream (relay)
-- Tab 2: dreamstack dev examples/game-tetris.ds (player)
import { Badge } from "../registry/components/badge"
-- ================================================================
2026-02-27 16:40:12 -08:00
-- GRID: flat 200-element array (20 rows × 10 cols)
-- grid[row * 10 + col] = 0 (empty) or 1-7 (piece color)
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
-- ================================================================
2026-02-27 16:40:12 -08:00
let grid = [0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0]
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
-- Active piece: 1=I, 2=J, 3=L, 4=O, 5=S, 6=T, 7=Z
let piece = 6
let rotation = 0
let px = 3
let py = 0
let nextPiece = 1
2026-02-27 16:40:12 -08:00
-- Game state
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
let score = 0
let lines = 0
let level = 1
let gameOver = 0
let paused = 0
let gravityTick = 0
let dropInterval = 24
let lockTick = 0
2026-02-27 16:40:12 -08:00
let clearDelay = 0
let ghostY = 0
let showGhost = 1
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
-- ================================================================
2026-02-27 16:40:12 -08:00
-- PIECE SHAPES: array lookup — sd[cell][x/y][shapeIndex]
-- Index = (piece - 1) * 4 + rotation (28 entries, pieces 1-7 × rot 0-3)
-- SRS standard rotations for all 7 tetrominoes
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
-- ================================================================
2026-02-27 16:40:12 -08:00
-- Cell 0 offsets (dx, dy)
let sd0x = [0, 2, 0, 1, 0, 1, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 2, 0, 1]
let sd0y = [1, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0]
-- Cell 1 offsets
let sd1x = [1, 2, 1, 1, 0, 2, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 0, 0, 1, 1, 0, 1, 1, 1, 0]
let sd1y = [1, 1, 2, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1]
-- Cell 2 offsets
let sd2x = [2, 2, 2, 1, 1, 1, 2, 0, 1, 1, 2, 1, 0, 0, 0, 0, 0, 2, 0, 1, 1, 2, 2, 1, 1, 2, 1, 1]
let sd2y = [1, 2, 2, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1]
-- Cell 3 offsets
let sd3x = [3, 2, 3, 1, 2, 1, 2, 1, 2, 2, 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 2, 0]
let sd3y = [1, 3, 2, 3, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2]
-- Color arrays for piece-type rendering (index 0=empty, 1-7=piece)
let colorL = ["#171717", "#22d3ee", "#60a5fa", "#fb923c", "#facc15", "#4ade80", "#c084fc", "#f87171"]
let colorD = ["#171717", "#06b6d4", "#3b82f6", "#f97316", "#eab308", "#22c55e", "#a855f7", "#ef4444"]
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
-- ================================================================
2026-02-27 16:40:12 -08:00
-- DERIVED: cell offsets from shape arrays
-- ================================================================
let si = 0
let c0dx = 0
let c0dy = 0
let c1dx = 0
let c1dy = 0
let c2dx = 0
let c2dy = 0
let c3dx = 0
let c3dy = 0
every 33 -> si = (piece - 1) * 4 + rotation
every 33 -> c0dx = sd0x[si]
every 33 -> c0dy = sd0y[si]
every 33 -> c1dx = sd1x[si]
every 33 -> c1dy = sd1y[si]
every 33 -> c2dx = sd2x[si]
every 33 -> c2dy = sd2y[si]
every 33 -> c3dx = sd3x[si]
every 33 -> c3dy = sd3y[si]
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
-- ================================================================
2026-02-27 16:40:12 -08:00
-- COLLISION: can the piece move down?
-- Check floor bounds + grid occupancy for all 4 cells
2026-02-27 13:57:51 -08:00
-- ================================================================
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
2026-02-27 16:40:12 -08:00
let blocked = 0
every 33 -> blocked = if py + c0dy + 1 >= 20 then 1 else (if py + c1dy + 1 >= 20 then 1 else (if py + c2dy + 1 >= 20 then 1 else (if py + c3dy + 1 >= 20 then 1 else (if grid[(py + c0dy + 1) * 10 + px + c0dx] > 0 then 1 else (if grid[(py + c1dy + 1) * 10 + px + c1dx] > 0 then 1 else (if grid[(py + c2dy + 1) * 10 + px + c2dx] > 0 then 1 else (if grid[(py + c3dy + 1) * 10 + px + c3dx] > 0 then 1 else 0)))))))
-- Left collision: wall + grid
let leftOk = 0
every 33 -> leftOk = if px + c0dx - 1 < 0 then 0 else (if px + c1dx - 1 < 0 then 0 else (if px + c2dx - 1 < 0 then 0 else (if px + c3dx - 1 < 0 then 0 else (if grid[(py + c0dy) * 10 + px + c0dx - 1] > 0 then 0 else (if grid[(py + c1dy) * 10 + px + c1dx - 1] > 0 then 0 else (if grid[(py + c2dy) * 10 + px + c2dx - 1] > 0 then 0 else (if grid[(py + c3dy) * 10 + px + c3dx - 1] > 0 then 0 else 1)))))))
-- Right collision: wall + grid
let rightOk = 0
every 33 -> rightOk = if px + c0dx + 1 >= 10 then 0 else (if px + c1dx + 1 >= 10 then 0 else (if px + c2dx + 1 >= 10 then 0 else (if px + c3dx + 1 >= 10 then 0 else (if grid[(py + c0dy) * 10 + px + c0dx + 1] > 0 then 0 else (if grid[(py + c1dy) * 10 + px + c1dx + 1] > 0 then 0 else (if grid[(py + c2dy) * 10 + px + c2dx + 1] > 0 then 0 else (if grid[(py + c3dy) * 10 + px + c3dx + 1] > 0 then 0 else 1)))))))
-- Rotation collision: check if next rotation fits
let nrot = 0
let nsi = 0
let nc0dx = 0
let nc0dy = 0
let nc1dx = 0
let nc1dy = 0
let nc2dx = 0
let nc2dy = 0
let nc3dx = 0
let nc3dy = 0
let rotOk = 0
every 33 -> nrot = (rotation + 1) % 4
every 33 -> nsi = (piece - 1) * 4 + nrot
every 33 -> nc0dx = sd0x[nsi]
every 33 -> nc0dy = sd0y[nsi]
every 33 -> nc1dx = sd1x[nsi]
every 33 -> nc1dy = sd1y[nsi]
every 33 -> nc2dx = sd2x[nsi]
every 33 -> nc2dy = sd2y[nsi]
every 33 -> nc3dx = sd3x[nsi]
every 33 -> nc3dy = sd3y[nsi]
every 33 -> rotOk = if px + nc0dx < 0 then 0 else (if px + nc0dx >= 10 then 0 else (if py + nc0dy >= 20 then 0 else (if px + nc1dx < 0 then 0 else (if px + nc1dx >= 10 then 0 else (if py + nc1dy >= 20 then 0 else (if px + nc2dx < 0 then 0 else (if px + nc2dx >= 10 then 0 else (if py + nc2dy >= 20 then 0 else (if px + nc3dx < 0 then 0 else (if px + nc3dx >= 10 then 0 else (if py + nc3dy >= 20 then 0 else (if grid[(py + nc0dy) * 10 + px + nc0dx] > 0 then 0 else (if grid[(py + nc1dy) * 10 + px + nc1dx] > 0 then 0 else (if grid[(py + nc2dy) * 10 + px + nc2dx] > 0 then 0 else (if grid[(py + nc3dy) * 10 + px + nc3dx] > 0 then 0 else 1)))))))))))))))
2026-02-27 13:57:51 -08:00
2026-02-27 16:40:12 -08:00
-- ================================================================
-- GHOST: compute landing position (try to push ghostY down 19 times)
-- ================================================================
2026-02-27 12:20:09 -08:00
2026-02-27 16:40:12 -08:00
every 33 -> ghostY = py
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
-- ================================================================
-- INPUT: keyboard controls
-- ================================================================
2026-02-27 13:57:51 -08:00
2026-02-27 16:40:12 -08:00
on keydown(ev) -> px = if gameOver then px else (if paused then px else (if ev.key == "ArrowLeft" then (if leftOk then px - 1 else px) else px))
on keydown(ev) -> px = if gameOver then px else (if paused then px else (if ev.key == "ArrowRight" then (if rightOk then px + 1 else px) else px))
on keydown(ev) -> rotation = if gameOver then rotation else (if paused then rotation else (if ev.key == "ArrowUp" then (if rotOk then nrot else rotation) else rotation))
on keydown(ev) -> py = if gameOver then py else (if paused then py else (if ev.key == "ArrowDown" then (if blocked then py else py + 1) else (if ev.key == " " then ghostY else py)))
on keydown(ev) -> paused = if ev.key == "p" then (if paused then 0 else 1) else paused
on keydown(ev) -> showGhost = if ev.key == "g" then (if showGhost then 0 else 1) else showGhost
2026-02-27 13:57:51 -08:00
2026-02-27 16:40:12 -08:00
-- ================================================================
-- PHYSICS: gravity pulls pieces down, contact freezes them
-- ================================================================
2026-02-27 12:20:09 -08:00
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
-- Gravity tick
every 33 -> gravityTick = if paused then gravityTick else (if gameOver then gravityTick else gravityTick + 1)
2026-02-27 16:40:12 -08:00
-- Auto-drop: gravity pulls piece down
every 33 -> py = if paused then py else (if gameOver then py else (if blocked then py else (if gravityTick > dropInterval then py + 1 else py)))
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
every 33 -> gravityTick = if gravityTick > dropInterval then 0 else gravityTick
2026-02-27 16:40:12 -08:00
-- Lock: when blocked (contact!), count frames then freeze
2026-02-27 12:20:09 -08:00
every 33 -> lockTick = if blocked then lockTick + 1 else 0
2026-02-27 16:40:12 -08:00
-- ================================================================
-- FREEZE: on contact, write piece cells into grid
-- ================================================================
every 33 -> grid[(py + c0dy) * 10 + px + c0dx] = if lockTick == 3 then piece else grid[(py + c0dy) * 10 + px + c0dx]
every 33 -> grid[(py + c1dy) * 10 + px + c1dx] = if lockTick == 3 then piece else grid[(py + c1dy) * 10 + px + c1dx]
every 33 -> grid[(py + c2dy) * 10 + px + c2dx] = if lockTick == 3 then piece else grid[(py + c2dy) * 10 + px + c2dx]
every 33 -> grid[(py + c3dy) * 10 + px + c3dx] = if lockTick == 3 then piece else grid[(py + c3dy) * 10 + px + c3dx]
-- Spawn new piece after freeze
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
every 33 -> piece = if lockTick == 3 then nextPiece else piece
every 33 -> nextPiece = if lockTick == 3 then (gravityTick % 7 + 1) else nextPiece
every 33 -> py = if lockTick == 3 then 0 else py
every 33 -> px = if lockTick == 3 then 3 else px
every 33 -> rotation = if lockTick == 3 then 0 else rotation
every 33 -> score = if lockTick == 3 then score + 10 else score
2026-02-27 16:40:12 -08:00
-- ================================================================
-- LINE CLEAR: detect full rows, cascade with slice/concat
-- ================================================================
-- Row fullness: check all 10 cells per row
let f0 = 0
let f1 = 0
let f2 = 0
let f3 = 0
let f4 = 0
let f5 = 0
let f6 = 0
let f7 = 0
let f8 = 0
let f9 = 0
let f10 = 0
let f11 = 0
let f12 = 0
let f13 = 0
let f14 = 0
let f15 = 0
let f16 = 0
let f17 = 0
let f18 = 0
let f19 = 0
every 33 -> f0 = if grid[0] > 0 then (if grid[1] > 0 then (if grid[2] > 0 then (if grid[3] > 0 then (if grid[4] > 0 then (if grid[5] > 0 then (if grid[6] > 0 then (if grid[7] > 0 then (if grid[8] > 0 then (if grid[9] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f1 = if grid[10] > 0 then (if grid[11] > 0 then (if grid[12] > 0 then (if grid[13] > 0 then (if grid[14] > 0 then (if grid[15] > 0 then (if grid[16] > 0 then (if grid[17] > 0 then (if grid[18] > 0 then (if grid[19] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f2 = if grid[20] > 0 then (if grid[21] > 0 then (if grid[22] > 0 then (if grid[23] > 0 then (if grid[24] > 0 then (if grid[25] > 0 then (if grid[26] > 0 then (if grid[27] > 0 then (if grid[28] > 0 then (if grid[29] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f3 = if grid[30] > 0 then (if grid[31] > 0 then (if grid[32] > 0 then (if grid[33] > 0 then (if grid[34] > 0 then (if grid[35] > 0 then (if grid[36] > 0 then (if grid[37] > 0 then (if grid[38] > 0 then (if grid[39] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f4 = if grid[40] > 0 then (if grid[41] > 0 then (if grid[42] > 0 then (if grid[43] > 0 then (if grid[44] > 0 then (if grid[45] > 0 then (if grid[46] > 0 then (if grid[47] > 0 then (if grid[48] > 0 then (if grid[49] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f5 = if grid[50] > 0 then (if grid[51] > 0 then (if grid[52] > 0 then (if grid[53] > 0 then (if grid[54] > 0 then (if grid[55] > 0 then (if grid[56] > 0 then (if grid[57] > 0 then (if grid[58] > 0 then (if grid[59] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f6 = if grid[60] > 0 then (if grid[61] > 0 then (if grid[62] > 0 then (if grid[63] > 0 then (if grid[64] > 0 then (if grid[65] > 0 then (if grid[66] > 0 then (if grid[67] > 0 then (if grid[68] > 0 then (if grid[69] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f7 = if grid[70] > 0 then (if grid[71] > 0 then (if grid[72] > 0 then (if grid[73] > 0 then (if grid[74] > 0 then (if grid[75] > 0 then (if grid[76] > 0 then (if grid[77] > 0 then (if grid[78] > 0 then (if grid[79] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f8 = if grid[80] > 0 then (if grid[81] > 0 then (if grid[82] > 0 then (if grid[83] > 0 then (if grid[84] > 0 then (if grid[85] > 0 then (if grid[86] > 0 then (if grid[87] > 0 then (if grid[88] > 0 then (if grid[89] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f9 = if grid[90] > 0 then (if grid[91] > 0 then (if grid[92] > 0 then (if grid[93] > 0 then (if grid[94] > 0 then (if grid[95] > 0 then (if grid[96] > 0 then (if grid[97] > 0 then (if grid[98] > 0 then (if grid[99] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f10 = if grid[100] > 0 then (if grid[101] > 0 then (if grid[102] > 0 then (if grid[103] > 0 then (if grid[104] > 0 then (if grid[105] > 0 then (if grid[106] > 0 then (if grid[107] > 0 then (if grid[108] > 0 then (if grid[109] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f11 = if grid[110] > 0 then (if grid[111] > 0 then (if grid[112] > 0 then (if grid[113] > 0 then (if grid[114] > 0 then (if grid[115] > 0 then (if grid[116] > 0 then (if grid[117] > 0 then (if grid[118] > 0 then (if grid[119] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f12 = if grid[120] > 0 then (if grid[121] > 0 then (if grid[122] > 0 then (if grid[123] > 0 then (if grid[124] > 0 then (if grid[125] > 0 then (if grid[126] > 0 then (if grid[127] > 0 then (if grid[128] > 0 then (if grid[129] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f13 = if grid[130] > 0 then (if grid[131] > 0 then (if grid[132] > 0 then (if grid[133] > 0 then (if grid[134] > 0 then (if grid[135] > 0 then (if grid[136] > 0 then (if grid[137] > 0 then (if grid[138] > 0 then (if grid[139] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f14 = if grid[140] > 0 then (if grid[141] > 0 then (if grid[142] > 0 then (if grid[143] > 0 then (if grid[144] > 0 then (if grid[145] > 0 then (if grid[146] > 0 then (if grid[147] > 0 then (if grid[148] > 0 then (if grid[149] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f15 = if grid[150] > 0 then (if grid[151] > 0 then (if grid[152] > 0 then (if grid[153] > 0 then (if grid[154] > 0 then (if grid[155] > 0 then (if grid[156] > 0 then (if grid[157] > 0 then (if grid[158] > 0 then (if grid[159] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f16 = if grid[160] > 0 then (if grid[161] > 0 then (if grid[162] > 0 then (if grid[163] > 0 then (if grid[164] > 0 then (if grid[165] > 0 then (if grid[166] > 0 then (if grid[167] > 0 then (if grid[168] > 0 then (if grid[169] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f17 = if grid[170] > 0 then (if grid[171] > 0 then (if grid[172] > 0 then (if grid[173] > 0 then (if grid[174] > 0 then (if grid[175] > 0 then (if grid[176] > 0 then (if grid[177] > 0 then (if grid[178] > 0 then (if grid[179] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f18 = if grid[180] > 0 then (if grid[181] > 0 then (if grid[182] > 0 then (if grid[183] > 0 then (if grid[184] > 0 then (if grid[185] > 0 then (if grid[186] > 0 then (if grid[187] > 0 then (if grid[188] > 0 then (if grid[189] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
every 33 -> f19 = if grid[190] > 0 then (if grid[191] > 0 then (if grid[192] > 0 then (if grid[193] > 0 then (if grid[194] > 0 then (if grid[195] > 0 then (if grid[196] > 0 then (if grid[197] > 0 then (if grid[198] > 0 then (if grid[199] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
-- Find bottommost full row
let clearRow = -1
every 33 -> clearRow = if f19 then 19 else (if f18 then 18 else (if f17 then 17 else (if f16 then 16 else (if f15 then 15 else (if f14 then 14 else (if f13 then 13 else (if f12 then 12 else (if f11 then 11 else (if f10 then 10 else (if f9 then 9 else (if f8 then 8 else (if f7 then 7 else (if f6 then 6 else (if f5 then 5 else (if f4 then 4 else (if f3 then 3 else (if f2 then 2 else (if f1 then 1 else (if f0 then 0 else -1)))))))))))))))))))
-- Clear row: slice out the full row, prepend empty row
every 33 -> clearDelay = if clearRow >= 0 then clearDelay + 1 else 0
every 33 -> grid = if clearDelay == 2 then concat([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], concat(slice(grid, 0, clearRow * 10), slice(grid, (clearRow + 1) * 10, 200))) else grid
every 33 -> score = if clearDelay == 2 then score + 100 else score
every 33 -> lines = if clearDelay == 2 then lines + 1 else lines
every 33 -> clearDelay = if clearDelay == 2 then 0 else clearDelay
-- Level and speed
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
every 33 -> level = if lines > 0 then (lines / 10 + 1) else 1
every 33 -> dropInterval = if level > 9 then 3 else (27 - level * 3)
2026-02-27 16:40:12 -08:00
-- Game over: spawn area occupied
every 33 -> gameOver = if grid[3] > 0 then 1 else (if grid[4] > 0 then 1 else (if grid[5] > 0 then 1 else (if grid[6] > 0 then 1 else gameOver)))
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
-- ================================================================
2026-02-27 16:40:12 -08:00
-- SOUND
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
-- ================================================================
every 33 -> play_tone(if lockTick == 3 then 220 else 0, 80)
every 33 -> play_tone(if gameOver then 110 else 0, 500, "sawtooth")
-- ================================================================
2026-02-27 16:40:12 -08:00
-- STREAM: spectator broadcast
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
-- ================================================================
stream tetris on "ws://localhost:9100/peer/tetris" {
mode: signal,
2026-02-27 16:40:12 -08:00
output: piece, rotation, px, py, nextPiece, score, lines, level, gameOver, paused, grid
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
}
-- ================================================================
2026-02-27 16:40:12 -08:00
-- VIEW
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
-- ================================================================
view tetris_game = column [
text "DreamStack Tetris" { variant: "title" }
row [
Badge { label: "Score: {score}", variant: "success" }
Badge { label: "Lines: {lines}", variant: "info" }
Badge { label: "Level: {level}", variant: "warning" }
]
row [
2026-02-27 16:40:12 -08:00
-- Main Board: 300x600
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
stack { style: "position:relative; width:300px; height:600px; background:linear-gradient(180deg,#0a0a1a,#111133); border:2px solid #334155; border-radius:12px; overflow:hidden; box-shadow:0 0 60px rgba(99,102,241,0.15)" } [
2026-02-27 16:40:12 -08:00
-- Grid lines
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
for r in [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19] ->
column { style: "position:absolute; width:300px; height:1px; top:{r * 30}px; background:rgba(99,102,241,0.08)" } []
for k in [0,1,2,3,4,5,6,7,8,9] ->
column { style: "position:absolute; width:1px; height:600px; left:{k * 30}px; background:rgba(99,102,241,0.08)" } []
2026-02-27 16:40:12 -08:00
-- Frozen grid: row 0
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:1px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[c]]}; opacity:{if grid[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 1
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:31px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[10 + c]]}; opacity:{if grid[10 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 2
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:61px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[20 + c]]}; opacity:{if grid[20 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 3
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:91px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[30 + c]]}; opacity:{if grid[30 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 4
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:121px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[40 + c]]}; opacity:{if grid[40 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 5
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:151px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[50 + c]]}; opacity:{if grid[50 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 6
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:181px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[60 + c]]}; opacity:{if grid[60 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 7
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:211px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[70 + c]]}; opacity:{if grid[70 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 8
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:241px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[80 + c]]}; opacity:{if grid[80 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 9
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:271px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[90 + c]]}; opacity:{if grid[90 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 10
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:301px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[100 + c]]}; opacity:{if grid[100 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 11
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:331px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[110 + c]]}; opacity:{if grid[110 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 12
2026-02-27 13:33:30 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:361px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[120 + c]]}; opacity:{if grid[120 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 13
2026-02-27 12:20:09 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:391px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[130 + c]]}; opacity:{if grid[130 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 14
2026-02-27 12:20:09 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:421px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[140 + c]]}; opacity:{if grid[140 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 15
2026-02-27 12:20:09 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:451px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[150 + c]]}; opacity:{if grid[150 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 16
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:481px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[160 + c]]}; opacity:{if grid[160 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 17
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:511px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[170 + c]]}; opacity:{if grid[170 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 18
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:541px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[180 + c]]}; opacity:{if grid[180 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Row 19
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
for c in [0,1,2,3,4,5,6,7,8,9] ->
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:28px; height:28px; top:571px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[190 + c]]}; opacity:{if grid[190 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
-- Ghost piece: shows where piece will land
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; border:2px dashed {colorD[piece]}; opacity:{if showGhost then 0.3 else 0}; top:{(ghostY + c0dy) * 30 + 1}px; left:{(px + c0dx) * 30 + 1}px" } []
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; border:2px dashed {colorD[piece]}; opacity:{if showGhost then 0.3 else 0}; top:{(ghostY + c1dy) * 30 + 1}px; left:{(px + c1dx) * 30 + 1}px" } []
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; border:2px dashed {colorD[piece]}; opacity:{if showGhost then 0.3 else 0}; top:{(ghostY + c2dy) * 30 + 1}px; left:{(px + c2dx) * 30 + 1}px" } []
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; border:2px dashed {colorD[piece]}; opacity:{if showGhost then 0.3 else 0}; top:{(ghostY + c3dy) * 30 + 1}px; left:{(px + c3dx) * 30 + 1}px" } []
-- Active piece: 4 cells positioned by offsets
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; background:{colorL[piece]}; box-shadow:0 0 12px rgba(168,85,247,0.5); transition:left 0.05s,top 0.05s; top:{(py + c0dy) * 30 + 1}px; left:{(px + c0dx) * 30 + 1}px" } []
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; background:{colorL[piece]}; box-shadow:0 0 12px rgba(168,85,247,0.5); transition:left 0.05s,top 0.05s; top:{(py + c1dy) * 30 + 1}px; left:{(px + c1dx) * 30 + 1}px" } []
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; background:{colorL[piece]}; box-shadow:0 0 12px rgba(168,85,247,0.5); transition:left 0.05s,top 0.05s; top:{(py + c2dy) * 30 + 1}px; left:{(px + c2dx) * 30 + 1}px" } []
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; background:{colorL[piece]}; box-shadow:0 0 12px rgba(168,85,247,0.5); transition:left 0.05s,top 0.05s; top:{(py + c3dy) * 30 + 1}px; left:{(px + c3dx) * 30 + 1}px" } []
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
]
-- Side panel
column [
text "NEXT" { variant: "subtitle" }
stack { style: "position:relative; width:120px; height:90px; background:#0f0f23; border-radius:8px; border:1px solid #334155" } [
2026-02-27 16:40:12 -08:00
column { style: "position:absolute; width:24px; height:24px; border-radius:3px; top:{sd0y[(nextPiece - 1) * 4] * 26 + 10}px; left:{sd0x[(nextPiece - 1) * 4] * 26 + 10}px; background:{colorL[nextPiece]}" } []
column { style: "position:absolute; width:24px; height:24px; border-radius:3px; top:{sd1y[(nextPiece - 1) * 4] * 26 + 10}px; left:{sd1x[(nextPiece - 1) * 4] * 26 + 10}px; background:{colorL[nextPiece]}" } []
column { style: "position:absolute; width:24px; height:24px; border-radius:3px; top:{sd2y[(nextPiece - 1) * 4] * 26 + 10}px; left:{sd2x[(nextPiece - 1) * 4] * 26 + 10}px; background:{colorL[nextPiece]}" } []
column { style: "position:absolute; width:24px; height:24px; border-radius:3px; top:{sd3y[(nextPiece - 1) * 4] * 26 + 10}px; left:{sd3x[(nextPiece - 1) * 4] * 26 + 10}px; background:{colorL[nextPiece]}" } []
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
]
text "STATS" { variant: "subtitle" }
text "Score: {score}"
text "Lines: {lines}"
text "Level: {level}"
text "Speed: {dropInterval}" { variant: "muted" }
2026-02-27 16:40:12 -08:00
text "DEBUG" { variant: "subtitle" }
text "piece:{piece} rot:{rotation}" { variant: "muted" }
text "px:{px} py:{py}" { variant: "muted" }
text "blk:{blocked} lock:{lockTick}" { variant: "muted" }
text "si:{si} clr:{clearRow}" { variant: "muted" }
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
]
]
2026-02-27 16:40:12 -08:00
-- Controls
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
row [
button (if paused then "Resume" else "Pause") {
click: paused = if paused then 0 else 1,
variant: "primary"
}
2026-02-27 16:40:12 -08:00
button "Left" { click: px = if leftOk then px - 1 else px, variant: "secondary" }
button "Right" { click: px = if rightOk then px + 1 else px, variant: "secondary" }
button "Rotate" { click: rotation = if rotOk then nrot else rotation, variant: "secondary" }
button "Drop" { click: py = ghostY, variant: "secondary" }
button (if showGhost then "Ghost: ON" else "Ghost: OFF") { click: showGhost = if showGhost then 0 else 1, variant: "outline" }
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
button "Reset" {
2026-02-27 16:40:12 -08:00
click: score = 0; lines = 0; level = 1; gameOver = 0; paused = 0; piece = 6; nextPiece = 1; px = 3; py = 0; rotation = 0; grid = [0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0],
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
variant: "destructive"
}
]
2026-02-27 16:40:12 -08:00
when gameOver > 0 -> text "GAME OVER — Score: {score}" { variant: "title" }
feat: tetris — signal composition showcase with 6 reactive layers
game-tetris.ds demonstrates DreamStack signal composition:
- Layer 1: Data signals (20 grid rows, piece state, next piece)
- Layer 2: Physics signals (gravity tick, drop speed, level scaling)
- Layer 3: Input signals (keyboard events -> movement commands)
- Layer 4: Derived signals (lock detection, line clear, game over)
- Layer 5: Sound signals (lock, clear, game over tones)
- Layer 6: Stream signals (30+ signals broadcast for spectators)
Board: 10x20 grid, 7 piece types, ghost piece indicator
Controls: Arrow keys, space (hard drop), P (pause)
Side panel: next piece preview, stats, signal layer key
Compiles to 76KB HTML+JS
2026-02-27 12:13:22 -08:00
]