Skip to content

Tom1tk/fishspin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

221 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Lucky Wheel 🎰

A casino-style spinning wheel game with a fish mascot, streaks, and a full upgrade shop β€” running on a Python/Flask backend with PostgreSQL persistence and user authentication.

πŸ“‹ Patch Notes

Overview

Lucky Wheel is a browser-based gambling wheel built with a Python/Flask backend and a React frontend. Spin the wheel, rack up wins, collect fish clicks, and spend them in the shop on cosmetic upgrades and gameplay boosts.

All game state is stored server-side in PostgreSQL β€” progress persists across devices and sessions, and client-side cheating is prevented.

Features

Core Gameplay

  • Spinning wheel β€” WIN or LOSE, styled as a neon casino wheel with smooth CSS rotation
  • Win/loss counter β€” persisted in PostgreSQL across sessions and devices
  • Win-streak multiplier β€” 3+ consecutive wins or losses triggers a scaling bonus. Exponential (Γ—2 per step) up to streak 15, then buffed cubic and linear growth, with a hard cap at streak 150 (~113,096 raw bonus)
  • Streak panel β€” appears in the left sidebar only when a streak is active (fire emoji for wins, skull for losses)
  • Streak persistence β€” streak is saved server-side (refresh-to-reset exploit patched)
  • Stats popup β€” πŸ“Š button shows total spins, wins, losses, win rate, season fish bucks, fastest catch percentage, and complete Season History
  • Community Pot β€” All players can contribute Fish Bucks to a global pot. When the target is reached, a 30-minute win rate boost activates for all players. Each fill permanently stacks +0.5% onto the boost rate (capped at 75%), so every window is stronger than the last. Between fills the game returns to 50/50. After the window expires, the pot resets with a 25%-higher target (Γ—1.25). Target decays 20% every 12 hours if unfilled.
  • Dice Roll β€” A charge-based high-risk mechanic between the wheel and shop. Roll two dice (or three with the Extra Die upgrade) to add the sum (2–18) to your current win streak. Requires a win streak of 3+. Snake eyes halves your streak; a pair of sixes doubles it. With three dice: triple 1s Γ·3, triple 6s Γ—3. Charges recharge every 10 minutes (max 1–4, upgradeable in the shop).

Authentication

  • Register with a username (3–32 alphanumeric) and password (6+ chars)
  • One account per device (enforced via a long-lived device_id cookie; multiple users on the same IP are fine)
  • Strict single-session enforcement β€” logging in on a new device boots the previous session
  • 30-day persistent login sessions (signed HTTP-only cookies)
  • Brute-force protection: escalating lockouts after 5/10/20 failed attempts per username (1min/5min/1hr)
  • All login and registration attempts are logged with IP, normalised username, User-Agent, and rejection reason

Fish Mascot & Cast & Reel Fishing

  • A fish lives on the left side of the screen, centred vertically (desktop); accessible via the 🐟 toolbar button on mobile
  • Reacts to spin results (happy on win, sad on loss, idle otherwise)
  • Shows a fire aura when wins are ahead, a gloom aura when losses are ahead β€” aura size and intensity scale with the net gap (tight drop-shadow glow on the fish + large ambient blur halo behind it)
  • Trail effects (sparkle/fire/rainbow/frost/thunder/galaxy) and the aura glow coexist independently
  • The equipped fish emoji acts as your fisher β€” holds a rod and stands at the water's edge

Cast & Reel (Season 6) β€” replaces passive fish clicking with an active timing minigame:

  • Click 🎣 CAST to drop your line. Shadow fish drift near the bobber while you wait.
  • When the fish bites, a bite bar begins depleting β€” click to reel before it empties.
  • Click too early (before the bite indicator) and it's an instant miss.
  • Catch one of 13 species across Common, Uncommon, Rare, and Legendary tiers. Each awards Fish Bucks scaled by your Lure level.
  • Lucky Fish (⭐) β€” a rare Legendary catch that doubles the value of your next successful reel.
  • Auto-Cast β€” re-casts automatically; you still handle the bite window.
  • Auto-Fish β€” fully automated; catches Common and Uncommon species (Rare unlocked by Master Auto-Fisher). Never catches Legendary fish.
  • Fish Encyclopaedia (πŸ“– top-left) β€” tracks all 13 species. Completing it unlocks Master Lure and Master Auto-Fisher.
  • All timing is server-authoritative β€” the bite window and catch validation cannot be spoofed client-side.

Auto-Spin

  • Checkbox to enable automatic spinning on a configurable delay
  • While active, manual spinning is locked out to prevent stacking
  • The wheel can begin spinning while the previous result banner is still fading out

Seasons

  • Seasons track per-user win/loss history and freeze a top-5 leaderboard snapshot at end-of-season
  • Season History β€” users can view their final wins and finishing positions for all past seasons in the stats popup
  • Season info shown in the UI; transitions announced via toast
  • The active leaderboard (bottom-left) displays the top 10 players, including their current and all-time best streaks
  • Season 7 is open-ended β€” no automatic reset. The "Season ends in" countdown shows ∞? and seasons are advanced manually.

Rising Fire Effect

  • A full-viewport canvas fire effect rises behind all game UI, scaling with win streak intensity
  • Mix mode (default) β€” embers and a cellular automaton inferno layered with additive blending
  • Embers appear from streak 3; inferno ignites from streak 10; screen fills around streak 30
  • Intensity lerps smoothly β€” wins cause the fire to grow, a loss makes it fall gradually rather than cutting out
  • Suppressed automatically in Low-Spec Mode and when OS prefers-reduced-motion is set

Mobile Support

  • Fully playable on phones and tablets (≀ 768 px breakpoint); desktop layout is completely unchanged
  • Bottom toolbar β€” five icon buttons toggle panels: Shop πŸͺ, Leaderboard πŸ†, Fish+Community Pot 🐟, Season Winners πŸ…, Stats πŸ“Š
  • Slide-in drawers β€” the shop/sidebar panel slides in from the right; leaderboard, season winners, and fish panels open as overlays
  • Tap-to-dismiss backdrop β€” tapping outside any open panel closes it
  • Community Pot moved into the fish panel on mobile to avoid crowding the top bar

Performance

  • Low-Spec Mode (⚑ button in the top bar) β€” disables infinite CSS animations, GPU-heavy drop-shadows, confetti, fish aura, and fire effect; respects OS prefers-reduced-motion
  • Preference is saved per user in the database and synced across devices

Anti-Cheat

  • All game logic runs server-side; clients cannot submit win/loss outcomes
  • Fish-click API capped at 10 clicks per request
  • Per-user click budget enforced in PostgreSQL: 75 raw clicks per 5-second rolling window, enforced atomically with FOR UPDATE across all workers (prevents per-worker rate-limit bypass)
  • Rate limiter keys on user account rather than IP (prevents shared-network collisions)

Shop System

The shop is always visible as a two-column panel on the right side of the screen (cosmetics on the left, functional upgrades on the right). Locked tiers are hidden until the prerequisite is owned β€” items unlock progressively. All purchases persist server-side. Hover over any item description to see the full tooltip.

Currencies

  • Wins: Used for all functional upgrades and gameplay boosts.
  • Losses: Used for all cosmetic items (skins, trails, themes, backgrounds).
  • Fish Bucks: Used for Lure Mastery (infinite upgrade) and The Singularity. Can be converted to Wins via the Fish Exchange.

Tier Gating (Season 5)

Functional upgrades are gated behind total win milestones. Locked items appear greyed out with the required win count shown.

Tier Unlocks at Example items
Tier 1 Always available Speed upgrades, Guard, Click Frenzy I–IV, Win/Bonus/Click Power
Tier 2 1,000 total wins Regenerating Shield, Auto-Guard, Final Frenzy, Extra Dice Charge
Tier 3 5,000 total wins Fortune Charm, Lucky Seven, Win Echo, Jackpot, Resilience, Max Dice Charge, Overcharge, Extra Die

Fish Skins (Costs Losses)

Skin Cost Emoji
Tropical Fish 25 🐠
Pufferfish 50 🐑
Octopus 75 πŸ™
Shark 100 🦈
Dolphin 150 🐬
Squid 200 πŸ¦‘
Turtle 350 🐒
Crab 600 πŸ¦€
Lobster 1,000 🦞
Whale 2,000 🐳
Seal 3,500 🦭
Shrimp 6,000 🦐
Coral 10,000 πŸͺΈ
Mermaid 17,500 🧜
Crocodile 30,000 🐊

Each skin has custom idle/win/loss speech. Buy and equip to change the fish.

Spin Speed (Costs Wins)

Upgrade Cost Spin Duration
Speed Boost 100 4.5s β†’ 3s
Turbo Spin 1,000 3s β†’ 1.5s
Hyper Spin 10,000 1.5s β†’ 1s
Ultra Spin 100,000 1s β†’ 0.75s
Max Spin 1,000,000 0.75s β†’ 0.5s

Auto Speed (Costs Wins)

Upgrade Cost Auto-Spin Delay
Quick Auto 200 1500ms β†’ 1000ms
Rapid Auto 10,000 1000ms β†’ 500ms
Instant Auto 1,000,000 500ms β†’ 0ms

Win Power (Costs Wins)

Multiplies each win's score contribution. Single item purchased repeatedly β€” no tier cap.

Level range Cost per level Multiplier
Lv 1–7 200 / 600 / 2,000 / 6,400 / 20,000 / 64,000 / 200,000 Γ—2 β†’ Γ—128
Lv 8+ 400,000 Γ— 1.18^(levelβˆ’8) +16 per level (Γ—144, Γ—160, …)

The shop card shows current level and next multiplier: Lv3 Β· Γ—8 β†’ Γ—16.

Bonus Power (Costs Wins)

Multiplies streak bonus payouts β€” for both win streaks and loss streaks. ⚠️ Higher levels also amplify loss streak penalties.

Level range Cost per level Multiplier
Lv 1–6 300 / 900 / 2,800 / 8,500 / 26,000 / 80,000 Γ—2 β†’ Γ—70
Lv 7–30 200,000 Γ— 1.18^(levelβˆ’7) +8 per level (Γ—78, Γ—86, … Γ—262)
Lv 31+ continues at same scaling +5 per level (Γ—267, Γ—272, …)

Season 7: level 6 cap reduced from Γ—100 β†’ Γ—70; post-tier scaling reduced from +10/level to +8/level (levels 7–30) then +5/level (levels 31+).

Fish Size (Costs Losses)

Tier Cost Fish Size
Big Fish 50 20rem
Giant Fish 200 28rem
Colossal 800 40rem

Fish Trail (Costs Losses)

Visual trail effect on the fish. Trail and streak aura effects coexist independently.

Tier Cost Effect
Sparkle Trail 125 ✨ Gold shimmer
Fire Trail 500 πŸ”₯ Flame glow
Rainbow Trail 2,000 🌈 Rainbow hue
Frost Trail 7,000 ❄️ Ice crystal aura
Thunder Trail 22,000 ⚑ Electric sparks
Galaxy Trail 70,000 🌌 Cosmic swirl

Click Power (Costs Wins)

Each fish click counts as more clicks server-side. Also scales all Frenzy passive tick amounts. Single item purchased repeatedly β€” no tier cap.

Level range Cost per level Multiplier
Lv 1–5 75 / 250 / 600 / 1,400 / 3,000 Γ—1.25 β†’ Γ—2.25
Lv 6+ 10,000 Γ— 1.5^(levelβˆ’6) +0.25 per level (Γ—2.5, Γ—2.75, …)

Click Frenzy (Costs Wins)

Passive income β€” server ticks fish clicks automatically. All Frenzy amounts are multiplied by your Click Power level.

Tier Cost Base clicks per 5s
Frenzy I 300 +1
Frenzy II 3,000 +5
Frenzy III 30,000 +20
Frenzy IV 300,000 +50
Frenzy V 3,000,000 +100
Final Frenzy 30,000,000 +500 (requires Frenzy V; toggleable; disables manual clicking while active)

🎣 Fishing Gear (Costs Wins)

Lure Upgrades β€” reduce bite wait time and multiply catch value. Both manual and Auto-Fish benefit.

Upgrade Cost Bite Speed Value Multiplier
Lure I 100 10% faster 1.5Γ—
Lure II 500 20% faster 2Γ—
Lure III 2,500 35% faster 5Γ—
Lure IV 15,000 50% faster 10Γ—
⭐ Master Lure 500,000 65% faster 20Γ— + +1% per legendary

Master Lure requires completing the Fish Encyclopaedia (all 13 species caught).

Auto-Cast (1,000 wins) β€” automatically re-casts the line when idle. You still handle the bite window.

Auto-Fisher β€” unlock and improve the Auto-Fish tickbox. Auto-Fish fires every 6s, is rate-limited server-side, and never catches Legendary fish at any level.

Upgrade Cost Catch Rate Species Pool
Auto-Fisher I 300 45% Common + Uncommon
Auto-Fisher II 2,000 55% Common + Uncommon
Auto-Fisher III 12,000 65% Common + Uncommon
πŸ€– Master Auto-Fisher 500,000 75% Common + Uncommon + Rare

Master Auto-Fisher requires completing the Fish Encyclopaedia.

Precise Angler (Tier 2, 1,000 wins) β€” rewards fast reflexes. Multipliers are exclusive; highest gate hit wins.

Upgrade Cost Threshold Multiplier
Precise Angler 50,000 ≀ 50% through bar 1.2Γ—
Precise Angler II 100,000 ≀ 20% through bar 1.5Γ—
🎯 Master Angler 500,000 ≀ 15% through bar 2Γ—

Master Angler requires completing the Fish Encyclopaedia. Precise Angler multipliers stack with Lure and Lucky Fish multipliers independently.

Protection (Costs Wins)

Item Cost Behaviour
πŸ›‘οΈ Guard 500 50% chance to block any loss. Breaks on success, survives on failure.
πŸ” Auto-Guard 50,000 Requires Guard. Toggleable. When enabled and Guard breaks, automatically re-buys Guard for 500 Wins before the next spin. Disables itself if you can't afford the 500 Wins cost.
πŸ”„ Regenerating Shield 1,500 Blocks any loss when charged. Recharges after 5 wins. Never breaks.
  • Guard β€” activates on any loss. A mini-wheel spins (50/50). If it lands on the win segment, the loss is fully blocked and the guard is consumed. If it fails, the guard survives and you take the loss as normal.
  • Auto-Guard β€” toggle on/off via the shop like Final Frenzy. When Guard breaks, the replacement is purchased silently before your next spin for a flat 500 Wins (unaffected by Click Power).
  • Regenerating Shield β€” blocks the next loss with 100% certainty while charged. After triggering, it recharges automatically after 5 consecutive wins.

Wheel Theme (Costs Losses)

Changes the canvas colour palette of the wheel.

Theme Cost Look
Fire Theme 250 πŸ”₯ Red/orange
Ice Theme 1,000 ❄️ Blue/cyan
Neon Theme 4,000 πŸ’œ Purple/neon
Void Theme 12,000 πŸŒ‘ Deep void
Gold Theme 40,000 ✨ Pure gold
Golden Wheel 300 ✨ Radiant glow ring (independent of theme)

Atmosphere (Costs Losses)

Background Theme

Ocean Casino is the default background for all players in Season 6 (animated seabed scene; static fallback in Low-Spec Mode). Purchasing and equipping a different background overrides it.

Theme Cost Look
Ocean Casino 100 Deep sea blue (Season 5 default β€” animated seabed)
Royal Casino 400 Rich purple
Inferno Casino 1,600 Blazing red
Forest 5,000 🌲 Lush green
Abyss 15,000 🌊 Deep dark ocean
Cosmic 50,000 🌌 Space nebula

Page Theme

Theme Cost Look
Season 1 1,000 Classic gold & orange
Season 2 1,000 Green & red
Season 3 1,000 Purple & orange
Season 4 1,000 Deep violet
Season 5 1,000 Bioluminescent cyan & coral
Season 6 πŸŒ™ 1,000 Night ocean β€” deep indigo & violet (current season default)

Confetti

Tier Cost Count
Confetti+ 75 Γ—2
Confetti++ 300 Γ—5
Confetti MAX 1,200 Γ—15
Party Mode 150 Confetti on every result

🎲 Dice Charges (Costs Wins)

Item Cost Effect Tier
Extra Charge 2,000 Max dice charges: 1 β†’ 2 Tier 2 (1k wins)
Max Charge 15,000 Max dice charges: 2 β†’ 3 Tier 3 (5k wins)
🎲 Overcharge 100,000 Max dice charges: 3 β†’ 4 Tier 3 (5k wins)
🎲 Extra Die 1,000,000 Roll 3 dice. Triple 6s Γ—3, Triple 1s Γ·3 Tier 3 (5k wins)

🎲 Special Upgrades (Costs Wins)

All Special Upgrades require Tier 3 (5,000 total wins) to unlock.

Item Cost Effect
πŸ€ Fortune Charm 1,000,000 All streak bonuses are increased by 25%
7️⃣ Lucky Seven 7,000,000 Every 7th spin is guaranteed to win
πŸ”Š Win Echo 1,000,000 20% β†’ 40% chance each win is doubled (upgradeable via Echo Amplification)
πŸ’ͺ Resilience 10,000,000 When on a win streak, losses reduce streak by 1 instead of resetting it (50% base chance)
🎰 Jackpot 3,000,000 1% β†’ 3% chance each win multiplies all gains by 25Γ—. 5% chance for Jackpot Echo (upgradeable via Jackpot Resonance)
πŸ›‘οΈ Streak Armor 500,000–2,750,000 Infinite upgrade (10 levels). Requires Resilience. +1% to Resilience save chance per level (50% β†’ 60% max)
🎣 Lure Mastery 5,000–1,500,000+ Fish Bucks Infinite upgrade (no cap). +10% to all fish catch value per level, stacking on top of Master Lure's 20Γ—
🎰 Jackpot Resonance 5,000,000–40,000,000+ Wins Infinite upgrade (10 levels max). Requires Jackpot. +0.2% jackpot proc rate per level (1% β†’ 3%)
πŸ”Š Echo Amplification 2,000,000–25,000,000+ Wins Infinite upgrade (10 levels max). Requires Win Echo. +2% echo proc rate per level (20% β†’ 40%)
⚑ Proc Streak 3,000,000–50,000,000+ Wins Infinite upgrade (15 levels max). Requires any proc upgrade. Multiplies proc payouts by (1 + streak Γ— level Γ— 0.005). Counter shown in sidebar.

🌌 Class System (Costs Wins β€” Tier 3)

Each class costs 10,000,000 Wins. All three can be owned simultaneously; only one can be equipped at a time. Equipping a new class replaces the previous one. Toggle equip by clicking an already-equipped class.

Class Effect
🌍 Earth +25% to all fish income (manual reels and Auto-Fish)
πŸŒ™ Moon +5% added to every proc rate (Jackpot, Win Echo, Fortune Charm)
⭐ Star +20% applied to all win multiplier payouts

πŸ”„ Fish Exchange

Converts Fish Bucks into Wins at a diminishing rate. Available in the shop's functional tab when Fish Bucks > 0. Two buttons: 10% (10% of current balance) or ALL (entire balance).

Rate: 1.0 / (1 + total_ever_exchanged / 50,000,000) β€” starts at 1:1, halves at 50M lifetime exchanged, continues declining. The live rate is shown before each conversion.

🌌 Legendary (Costs Fish Bucks)

Item Cost Effect
The Singularity 1,000,000,000 Transcend reality. Every spin is a win.

Running Locally

Requirements

  • Python 3.8+
  • PostgreSQL 14+
  • Node.js (for the one-time JSX build step)

1. Install Python dependencies

pip install -r requirements.txt

2. Set up PostgreSQL

# Create DB user and database
sudo -u postgres psql -c "CREATE USER wheelapp WITH PASSWORD '<your-password>';"
sudo -u postgres psql -c "CREATE DATABASE wheeldb OWNER wheelapp;"

Then apply the baseline schema and run migrations:

PGPASSWORD='<your-password>' psql -U wheelapp -d wheeldb -h localhost -f schema.sql
DATABASE_URL="postgresql://wheelapp:<your-password>@localhost/wheeldb" python migrate.py

3. Configure environment

Both variables are required β€” the server will refuse to start without them.

export DATABASE_URL="postgresql://wheelapp:<your-password>@localhost/wheeldb"
export WHEEL_SECRET_KEY="$(python -c 'import secrets; print(secrets.token_hex(32))')"
export PORT=5000   # optional, defaults to 5000

For convenience, copy .env.example to .env β€” python-dotenv will load it automatically.

4. Build the frontend

The JSX source must be transpiled once (and again after any app.jsx changes):

npx babel static/app.jsx --presets @babel/preset-react,@babel/preset-env -o static/app.js

5. Start the server

Production (recommended):

gunicorn -c gunicorn.conf.py server:app

Development:

python server.py

Open http://localhost:5000 in your browser. You'll be prompted to register or log in.


Staging Environment

A separate staging environment runs on port 5001 against a wheeldb_staging database, using a git worktree on the staging branch.

/home/user/wheel-app/           ← master (production, port 5000, wheeldb)
/home/user/wheel-app-staging/   ← staging (port 5001, wheeldb_staging)

Start staging dev server:

cd /home/user/wheel-app-staging && PORT=5001 python server.py

Promote to production:

cd /home/user/wheel-app && ./deploy.sh

deploy.sh merges staging β†’ master, applies pending migrations, rebuilds the frontend, and reloads gunicorn.


Database Migrations

Schema changes are managed with numbered SQL files and a lightweight migration runner.

python migrate.py              # apply pending migrations
python migrate.py --status     # show applied / pending migrations
python migrate.py --dry-run    # preview without executing

Migration files live in migrations/NNN_description.sql. Applied versions are tracked in the schema_migrations table in each database.


Project Structure

wheel-app/
β”œβ”€β”€ server.py          # Thin entry point: create_app() β†’ gunicorn target
β”œβ”€β”€ app.py             # Flask app factory: config, extensions, blueprints, error handlers
β”œβ”€β”€ auth.py            # Blueprint: /api/me, /api/register, /api/login, /api/logout
β”œβ”€β”€ game.py            # Blueprint: /api/state, /api/spin, /api/buy, /api/equip,
β”‚                      #            /api/equip-cosmetic, /api/equip-class, /api/fish-click,
β”‚                      #            /api/click-frenzy, /api/fish-exchange,
β”‚                      #            /api/stats, /api/leaderboard, /api/health
β”œβ”€β”€ db.py              # psycopg2 ThreadedConnectionPool + db_connection() context manager
β”œβ”€β”€ models.py          # User class, FISH_SKINS, SHOP_ITEMS, INFINITE_UPGRADES, helper functions
β”œβ”€β”€ security.py        # check_lockout(), record_attempt(), clear_attempts(), require_json()
β”œβ”€β”€ extensions.py      # Flask-Limiter and Flask-Login instances
β”œβ”€β”€ migrate.py         # SQL migration runner (apply / status / dry-run)
β”œβ”€β”€ deploy.sh          # Production deploy: merge staging β†’ migrate β†’ build β†’ reload
β”œβ”€β”€ gunicorn.conf.py   # Gunicorn config: 4 gthread workers Γ— 4 threads, PORT from env
β”œβ”€β”€ schema.sql         # PostgreSQL baseline schema
β”œβ”€β”€ migrations/        # Numbered SQL migration files (NNN_description.sql)
β”œβ”€β”€ requirements.txt   # Python dependencies
β”œβ”€β”€ .env.example       # Required environment variable template
└── static/
    β”œβ”€β”€ index.html     # Slim HTML shell
    β”œβ”€β”€ app.jsx        # React source (edit this)
    β”œβ”€β”€ app.js         # Compiled output (generated by Babel β€” do not edit directly)
    └── styles.css     # All CSS

API Reference

All game endpoints require authentication (session cookie). POST endpoints require Content-Type: application/json.

Auth

Endpoint Method Rate Limit Description
/api/me GET β€” Returns {username} or {username: null}
/api/register POST 5/hr Create account
/api/login POST 10/min Authenticate
/api/logout POST β€” Clear session

Game

Endpoint Method Rate Limit Description
/api/health GET β€” DB connectivity check β†’ {"status":"ok"} or 503
/api/state GET β€” Full game state (including community pot)
/api/spin POST 10/sec Server determines outcome, updates DB
/api/buy POST β€” Purchase shop item
/api/equip POST β€” Equip a fish skin
/api/equip-cosmetic POST β€” Toggle a cosmetic item on/off
/api/community-pot/state GET β€” Current pot progress and target
/api/community-pot/contribute POST 5/sec Contribute Fish Bucks to the global pot
/api/fish-click POST 5/sec Legacy endpoint β€” no-op (returns current state)
/api/click-frenzy POST 1/sec Legacy endpoint β€” no-op (returns current state)
/api/cast POST 5/sec Start a fishing session β€” returns {bite_at, expires_at}
/api/reel POST 5/sec Attempt a reel β€” server validates timing, returns catch result
/api/auto-fish-tick POST 1/5sec One automated catch cycle (requires Auto-Fisher I+)
/api/settings POST β€” Persist user preferences (e.g. low_spec_mode)
/api/stats GET β€” Personal stats (including Season History and fastest catch %)
/api/leaderboard GET β€” Public β€” top 10 players
/api/equip-class POST β€” Equip or unequip a class item ({"item_id": "class_earth"})
/api/fish-exchange POST β€” Convert Fish Bucks β†’ Wins ({"mode": "10pct"} or {"mode": "all"})

/api/spin response:

{
  "result": "win",
  "angle": 2345.6,
  "wins_delta": 4,
  "losses_delta": 0,
  "streak": 4,
  "owned_items": ["regen_shield"],
  "active_cosmetics": ["auto_guard"],
  "shield_charges": 0,
  "regen_recharge_wins": 0,
  "shield_used": false,
  "shield_used_type": null,
  "shield_broke": false,
  "guard_triggered": false,
  "guard_blocked": false,
  "bonus_earned": 4,
  "echo_triggered": false,
  "jackpot_hit": false,
  "resilience_triggered": false,
  "lucky_seven_triggered": false,
  "fortune_charm_triggered": false,
  "auto_guard_failed": false,
  "proc_streak": 3
}

wins_delta and losses_delta represent the change in currency from this spin. The client adds these to its local state to avoid race conditions.

/api/leaderboard (public, no auth required):

[
  { "username": "alice", "wins": 42, "losses": 18, "streak": 5, "best_streak": 12 },
  ...
]

Returns top 10 players by win count. Auto-refreshed client-side every 5 seconds.


Frontend Architecture

The frontend is a pre-compiled React app. Edit static/app.jsx and run the Babel build step to update static/app.js. Key components:

Component Purpose
App Root: checks /api/me, renders AuthPage or GameApp
AuthPage Login/register form with error handling
GameApp Main game: wheel, fish, shop, all API calls
Fish Left-side mascot β€” aura, mood, trail effects
FishingPanel Cast & Reel minigame β€” bobber, bite bar, shadow fish, Auto-Cast/Auto-Fish toggles
FishEncyclopedia Modal showing all 13 catchable species (silhouettes until discovered)
GuardWheel Mini canvas wheel overlay for guard activation (50/50 animation)
StreakPanel Sidebar streak display (only shown at streak β‰₯ 2)
ShopPanel Two-column shop (cosmetics left, functional right); collapsible via a pinned β€Ί/β€Ή toggle button
ShopItem Individual item card (buy / equip / active states; full desc on hover)
Scoreboard Win/loss counter below the wheel
StatsPanel Modal overlay showing personal stats (πŸ“Š button)
Confetti Win confetti overlay
Leaderboard Vertical panel (bottom-left) β€” top 10 players with wins, best streak, and live streak glow effect; refreshes every 5s
FireEffect Full-viewport canvas fire effect behind all UI β€” ember particles + cellular automaton inferno, scaled by win streak
drawWheel Canvas rendering with theme support (default / fire / ice / neon / void / gold)
drawGuardWheel Canvas rendering for the guard mini-wheel (50% green / 50% red)

Mobile layout is handled entirely in CSS (@media (max-width: 768px)) and a small amount of React state (isMobile, mobilePanel) in GameApp. No separate mobile components β€” the same components are reused, conditionally positioned via CSS class toggles.

No localStorage β€” all state lives in PostgreSQL. Legacy localStorage keys are cleared on mount.


Tech Stack

  • Backend: Python, Flask, flask-login, flask-limiter, bcrypt
  • Database: PostgreSQL (psycopg2 with ThreadedConnectionPool)
  • WSGI: Gunicorn (gthread workers)
  • Frontend: React 18 (CDN UMD), pre-compiled JSX via Babel CLI, vanilla CSS
  • Auth: Server-side sessions via signed HTTP-only cookies (SameSite=Lax)

About

A casino-style spinning wheel incremental game with a fish mascot, streaks, and a full upgrade shop

Resources

Stars

Watchers

Forks

Contributors