149 lines
4.5 KiB
Markdown
149 lines
4.5 KiB
Markdown
# Virtue Slots
|
||
|
||
A browser-based slot machine game with a Christian religious theme, built with Phaser 3 and vanilla JavaScript. May Fortune Favor the Faithful.
|
||
|
||

|
||
|
||
---
|
||
|
||
## Features
|
||
|
||
- **10 holy symbols** — from Dove to Holy Grail, each with unique payout values scaled by holiness
|
||
- **Animated reels** — smooth spin, decelerate, and snap-to-symbol with sprite overlays
|
||
- **Win sequence** — "MATCH: 3×" banner punches in with elastic animation, sparkles, and shaking; followed by arcing coin animations splitting 60% to the player and 40% to The Lord
|
||
- **Loss sequence** — a devil carries the spent money up to the Sin box with a wobble animation
|
||
- **Split labels** — on a win, animated callouts show "YOUR WINNINGS 60%" and "THE LORD'S TITHE 40%" so the player always understands where the money goes
|
||
- **The Reckoning** — two filling vials on the right track cumulative funds for "The Lord" and "Sin"; whichever reaches $2,000 first wins; vials shake progressively harder as they approach the limit
|
||
- **Living background** — stars drift, twinkle, and pulse independently for an ambient celestial feel
|
||
|
||
---
|
||
|
||
## Tech Stack
|
||
|
||
| Thing | Choice |
|
||
|---|---|
|
||
| Game engine | [Phaser 3](https://phaser.io/) via CDN |
|
||
| Language | Vanilla JavaScript — ES6 modules |
|
||
| Bundler | **None** — files are served directly |
|
||
| Canvas | 1600 × 900, FIT + CENTER scale mode |
|
||
|
||
---
|
||
|
||
## Running Locally
|
||
|
||
Browsers block ES6 module imports from `file://`, so serve over HTTP:
|
||
|
||
```bash
|
||
# Python (built-in)
|
||
python3 -m http.server 8080
|
||
|
||
# Node (npx)
|
||
npx serve .
|
||
```
|
||
|
||
Then open **http://localhost:8080** in any modern browser.
|
||
|
||
---
|
||
|
||
## Controls
|
||
|
||
| Action | Input |
|
||
|---|---|
|
||
| Spin | Click the **SPIN** button |
|
||
| Spin | Press **Space Bar** |
|
||
|
||
---
|
||
|
||
## Game Economy
|
||
|
||
| Setting | Value |
|
||
|---|---|
|
||
| Starting funds | $1,000 |
|
||
| Cost per spin | $50 |
|
||
| Win rate | ~1 in 15 spins |
|
||
| Win split | 60% to player · 40% to The Lord |
|
||
| Loss result | $50 added to the Sin total |
|
||
|
||
---
|
||
|
||
## Symbols & Payouts
|
||
|
||
Symbols are ordered by holiness. A three-of-a-kind match pays the symbol's full payout value.
|
||
|
||
| Symbol | Holiness | Payout |
|
||
|---|---|---|
|
||
| Dove | 1 | $200 |
|
||
| Joel Osteen | 2 | $300 |
|
||
| Holy Bible | 3 | $400 |
|
||
| Lamb of God | 4 | $500 |
|
||
| Crown of Thorns | 5 | $600 |
|
||
| Halo | 6 | $700 |
|
||
| The Cross | 7 | $900 |
|
||
| Jesus on Cross | 8 | $1,100 |
|
||
| Baby Jesus | 9 | $1,300 |
|
||
| Holy Grail | 10 | $1,500 |
|
||
|
||
---
|
||
|
||
## Project Structure
|
||
|
||
```
|
||
index.html Loads Phaser 3 (CDN) and main.js as type="module"
|
||
main.js Phaser.Game config — registers all three scenes
|
||
|
||
state/
|
||
GameState.js Singleton: playerFunds, lordFunds, sinTotal, spinning flag
|
||
|
||
utils/
|
||
RNG.js shouldWin() (~1/15), pickResults() for reel targets
|
||
|
||
objects/
|
||
Symbol.js SYMBOLS array — id, label, holiness, payout, color
|
||
Reel.js Single reel: virtual infinite strip, pooled cells, sprite overlay
|
||
SlotMachine.js Orchestrates 3 reels; manages spin timing and result callback
|
||
WinAnimation.js Match banner → gold flash → arcing coin animation → split labels
|
||
LossAnimation.js Devil graphic rises to the Sin box
|
||
MatchBanner.js Full-screen "MATCH: 3× {label}" overlay with particle burst
|
||
VialDisplay.js Filling vial with shake escalation and winner detection
|
||
|
||
scenes/
|
||
BootScene.js Preloads assets (symbol spritesheet), then starts game
|
||
GameScene.js Background, stars, slot machine, vials, input handling
|
||
UIScene.js Overlay HUD: fund boxes (top), message + SPIN button (bottom)
|
||
|
||
assets/
|
||
symbol_sprites.png 200×100 px spritesheet — 10 frames, one per symbol in order
|
||
```
|
||
|
||
---
|
||
|
||
## Scene Communication
|
||
|
||
Scenes communicate exclusively through the global Phaser event bus (`this.game.events`):
|
||
|
||
| Emitter | Event | Payload |
|
||
|---|---|---|
|
||
| UIScene | `spin` | — |
|
||
| GameScene | `win` | `{ playerGain, lordGain, symbol }` |
|
||
| GameScene | `loss` | `{ sinAdded }` |
|
||
| GameScene | `funds-updated` | — |
|
||
| GameScene | `spin-complete` | — |
|
||
| GameScene | `insufficient-funds` | — |
|
||
| VialDisplay | `vial-winner` | `{ winner }` |
|
||
|
||
---
|
||
|
||
## Sprite Sheet
|
||
|
||
`assets/symbol_sprites.png` must be a horizontal sprite sheet:
|
||
|
||
- **Frame size:** 200 × 100 px
|
||
- **Frame count:** 10 (one per symbol)
|
||
- **Frame order:** must match the `SYMBOLS` array order in `objects/Symbol.js` (Dove at index 0, Holy Grail at index 9)
|
||
|
||
---
|
||
|
||
## License
|
||
|
||
Do whatever you want with it. Probably don't build a real gambling site.
|