Spaces:
Sleeping
Sleeping
A newer version of the Streamlit SDK is available:
1.54.0
Devil's Dozen - Technical Architecture
1. System Overview
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CLIENT (Browser) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Streamlit Frontend β β
β β βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββ β β
β β β Dice Tray β β Scoreboard β β Turn Controls β β β
β β βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Game Engine β β
β β ββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β β
β β β PeasantsGamble β β AlchemistsAscent β β β
β β β Engine β β Engine β β β
β β ββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SUPABASE β
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ β
β β Lobbies β β Players β β Game State β β
β β Table β β Table β β Table β β
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Realtime Channels β β
β β (WebSocket Push Notifications) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2. Module Dependency Graph
βββββββββββββ
β config β
βββββββ¬ββββββ
β
βββββββββββββββββΌββββββββββββββββ
β β β
βΌ βΌ βΌ
ββββββββββββ ββββββββββββ ββββββββββββ
β engine β β database β β realtime β
ββββββββββββ ββββββ¬ββββββ ββββββ¬ββββββ
β β β
β ββββββββ¬ββββββββ
β β
βΌ βΌ
βββββββββββββββββββββββββββββββββββββββ
β ui β
β (imports engine, database, realtime)β
βββββββββββββββββββββββββββββββββββββββ
Dependency Rules:
enginehas ZERO external dependencies (pure Python)databasedepends only onconfigfor settingsrealtimedepends ondatabasefor client accessuiimports from all other modules- No circular dependencies allowed
3. Data Flow
3.1 Turn Flow (Happy Path)
Player A Supabase Player B
β β β
βββββ Click "Roll" ββββββββββΊ β
β β β
β [Engine calculates β β
β scoring locally] β β
β β β
βββββ UPDATE game_state βββββΊ β
β (dice, turn_score) β β
β βββ Realtime broadcast βββββΊβ
β β β
βββββ Confirmation ββββββββββ β
β β β
βββββ Click "Bank" ββββββββββΊ β
β β β
βββββ UPDATE players ββββββββΊ β
β (add turn_score) β β
β β β
βββββ UPDATE lobbies ββββββββΊ β
β (next turn_index) β β
β βββ Realtime broadcast βββββΊβ
3.2 Bust Flow
Player A Supabase Player B
β β β
βββββ Click "Roll" ββββββββββΊ β
β β β
β [Engine: no scoring β β
β dice = BUST] β β
β β β
βββββ UPDATE game_state βββββΊ β
β (bust: true) β β
β βββ Realtime broadcast βββββΊβ
β β (bust event) β
β β β
βββββ UPDATE lobbies ββββββββΊ β
β (next turn_index) β β
β β β
βββββ Now it's Player B ββββββββ Player B's turn now βββ
4. Database Schema
4.1 Tables
-- Lobby: Game room containing players
CREATE TABLE lobbies (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
code VARCHAR(6) UNIQUE NOT NULL, -- Shareable join code
game_mode VARCHAR(20) NOT NULL, -- 'peasants_gamble' | 'alchemists_ascent'
win_condition INT NOT NULL, -- Target score to win
current_turn_index INT DEFAULT 0, -- Index into player turn order
status VARCHAR(20) DEFAULT 'waiting', -- waiting | active | finished
winner_id UUID REFERENCES players(id), -- Set when game ends
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Player: Participant in a game
CREATE TABLE players (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
lobby_id UUID REFERENCES lobbies(id) ON DELETE CASCADE,
username VARCHAR(30) NOT NULL,
total_score INT DEFAULT 0,
turn_order INT NOT NULL, -- 0, 1, 2, or 3
is_connected BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(lobby_id, username), -- No duplicate names in lobby
UNIQUE(lobby_id, turn_order) -- No duplicate turn orders
);
-- Game State: Current turn state (transient)
CREATE TABLE game_state (
lobby_id UUID PRIMARY KEY REFERENCES lobbies(id) ON DELETE CASCADE,
active_dice JSONB DEFAULT '[]', -- Current dice values [1,4,5,2,3,6]
held_indices JSONB DEFAULT '[]', -- Indices of held dice [0, 2]
turn_score INT DEFAULT 0, -- Points accumulated this turn
is_bust BOOLEAN DEFAULT false, -- Did player bust?
roll_count INT DEFAULT 0, -- Number of rolls this turn
tier INT DEFAULT 1, -- For Alchemist's Ascent
previous_dice JSONB DEFAULT '[]', -- For Tier 2 reroll comparison
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Indexes for performance
CREATE INDEX idx_players_lobby ON players(lobby_id);
CREATE INDEX idx_lobbies_code ON lobbies(code);
CREATE INDEX idx_lobbies_status ON lobbies(status);
4.2 Row Level Security
-- Lobbies: Anyone can read, only creator can update
ALTER TABLE lobbies ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Lobbies are publicly readable"
ON lobbies FOR SELECT
USING (true);
CREATE POLICY "Anyone can create lobbies"
ON lobbies FOR INSERT
WITH CHECK (true);
CREATE POLICY "Lobby members can update"
ON lobbies FOR UPDATE
USING (true); -- Simplified for MVP
-- Similar policies for players and game_state tables
5. State Management
5.1 Streamlit Session State
# Session state structure
st.session_state = {
# Identity
"player_id": "uuid",
"player_name": "string",
# Lobby
"lobby_id": "uuid",
"lobby_code": "ABC123",
"game_mode": "peasants_gamble",
# Turn state
"is_my_turn": bool,
"current_dice": [1, 4, 5, 2, 3, 6],
"held_indices": {0, 2},
"turn_score": 0,
# UI state
"sound_enabled": True,
"show_rules": False,
}
5.2 Optimistic Updates
To reduce perceived latency:
- Update local state immediately on user action
- Send update to Supabase
- If Supabase update fails, rollback local state
- Other players receive update via Realtime subscription
6. Error Handling Strategy
| Error Type | Response |
|---|---|
| Network failure | Retry 3x with backoff, then show error |
| Supabase error | Log, show user-friendly message |
| Invalid game state | Reset to last known good state |
| Concurrent modification | Last write wins (simplified) |
| Player disconnect | Mark as disconnected, allow rejoin |
7. Deployment Architecture
ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
β GitHub (source) β β Hugging Face Spaces β
β origin/master β β hf/main (live app) β
ββββββββββββ¬ββββββββββββββββ ββββββββββββ¬ββββββββββββββββ
β git push origin master β git push hf master:main
βββββββββββββββββ¬ββββββββββββββββββββ
β
ββββββββββββββΌβββββββββββββββββββββ
β Streamlit Application β
β - Serves UI + game engine β
β - JS-cached audio system β
β - Connects to Supabase (HTTPS) β
ββββββββββββββ¬βββββββββββββββββββββ
β
ββββββββββββββΌβββββββββββββββββββββ
β Supabase β
β - PostgreSQL database β
β - Realtime WebSocket channels β
β - Row Level Security β
βββββββββββββββββββββββββββββββββββ
Remotes
| Remote | URL | Branch |
|---|---|---|
origin |
https://github.com/legomaheggoz-source/DevilsDozen.git |
master |
hf |
https://huggingface.co/spaces/legomaheggo/DevilsDozen |
push master:main |
Environment Variables (HF Spaces Secrets / .env locally)
SUPABASE_URL=https://xxx.supabase.co
SUPABASE_ANON_KEY=sb_publishable_xxx...
8. Performance Considerations
Bottlenecks & Mitigations
| Bottleneck | Mitigation |
|---|---|
| Streamlit rerun on state change | Use st.fragment for isolated updates |
| Database round-trips | Batch updates where possible |
| Realtime subscription limits | One channel per lobby |
| Animation performance | CSS animations over JS |
| Audio data re-send on rerun | JS Audio caching in window.parent β base64 sent once, then tiny control commands |
Widget prefs lost on st.rerun() |
Non-widget session state keys (_sfx_pref, _music_pref, etc.) |
Scaling Limits (Free Tier)
- Supabase: 500MB database, 2GB bandwidth/month
- HF Spaces: 2 vCPU, 16GB RAM
- Concurrent games: ~50 lobbies estimated