82 lines
2.7 KiB
Text
82 lines
2.7 KiB
Text
|
|
-- DreamStack Reaction Game (Streamed)
|
||
|
|
-- Whack-a-mole style: click the target before it moves!
|
||
|
|
-- State is streamed so viewers can watch live.
|
||
|
|
--
|
||
|
|
-- Run with:
|
||
|
|
-- Tab 1: cargo run -p ds-stream (relay)
|
||
|
|
-- Tab 2: dreamstack stream examples/game-reaction.ds (source/player)
|
||
|
|
-- Tab 3: open game-viewer build in browser (viewer)
|
||
|
|
|
||
|
|
import { Card } from "../registry/components/card"
|
||
|
|
import { Badge } from "../registry/components/badge"
|
||
|
|
|
||
|
|
-- Game state
|
||
|
|
let score = 0
|
||
|
|
let misses = 0
|
||
|
|
let target = 5
|
||
|
|
let round = 0
|
||
|
|
|
||
|
|
-- Timer: move target every 2 seconds
|
||
|
|
every 2000 -> round += 1
|
||
|
|
|
||
|
|
-- Derived: target position follows round
|
||
|
|
let pos = round % 9 + 1
|
||
|
|
|
||
|
|
-- Stream game state
|
||
|
|
stream reaction_game on "ws://localhost:9100/peer/game" {
|
||
|
|
mode: signal,
|
||
|
|
output: score, misses, round, pos
|
||
|
|
}
|
||
|
|
|
||
|
|
view game = column [
|
||
|
|
text "🎯 Reaction Game" { variant: "title" }
|
||
|
|
text "Click the lit cell before it moves!" { variant: "subtitle" }
|
||
|
|
|
||
|
|
-- Score bar
|
||
|
|
row [
|
||
|
|
Badge { label: "Score: {score}", variant: "success" }
|
||
|
|
Badge { label: "Misses: {misses}", variant: "error" }
|
||
|
|
Badge { label: "Round: {round}", variant: "info" }
|
||
|
|
]
|
||
|
|
|
||
|
|
-- 3x3 Grid
|
||
|
|
Card { title: "Game Board" } [
|
||
|
|
row [
|
||
|
|
match pos
|
||
|
|
1 -> button "🎯" { click: score += 1, variant: "primary" }
|
||
|
|
_ -> button "·" { click: misses += 1, variant: "secondary" }
|
||
|
|
match pos
|
||
|
|
2 -> button "🎯" { click: score += 1, variant: "primary" }
|
||
|
|
_ -> button "·" { click: misses += 1, variant: "secondary" }
|
||
|
|
match pos
|
||
|
|
3 -> button "🎯" { click: score += 1, variant: "primary" }
|
||
|
|
_ -> button "·" { click: misses += 1, variant: "secondary" }
|
||
|
|
]
|
||
|
|
row [
|
||
|
|
match pos
|
||
|
|
4 -> button "🎯" { click: score += 1, variant: "primary" }
|
||
|
|
_ -> button "·" { click: misses += 1, variant: "secondary" }
|
||
|
|
match pos
|
||
|
|
5 -> button "🎯" { click: score += 1, variant: "primary" }
|
||
|
|
_ -> button "·" { click: misses += 1, variant: "secondary" }
|
||
|
|
match pos
|
||
|
|
6 -> button "🎯" { click: score += 1, variant: "primary" }
|
||
|
|
_ -> button "·" { click: misses += 1, variant: "secondary" }
|
||
|
|
]
|
||
|
|
row [
|
||
|
|
match pos
|
||
|
|
7 -> button "🎯" { click: score += 1, variant: "primary" }
|
||
|
|
_ -> button "·" { click: misses += 1, variant: "secondary" }
|
||
|
|
match pos
|
||
|
|
8 -> button "🎯" { click: score += 1, variant: "primary" }
|
||
|
|
_ -> button "·" { click: misses += 1, variant: "secondary" }
|
||
|
|
match pos
|
||
|
|
9 -> button "🎯" { click: score += 1, variant: "primary" }
|
||
|
|
_ -> button "·" { click: misses += 1, variant: "secondary" }
|
||
|
|
]
|
||
|
|
]
|
||
|
|
|
||
|
|
-- Reset
|
||
|
|
button "🔄 Reset Game" { click: score = 0; misses = 0, variant: "ghost" }
|
||
|
|
]
|