Fortuna is a randomizer-wheel browser-source overlay (OBS, Streamlabs, or any
Chromium ≥ 80 streaming app): load it with names, objectives, or
stipulations, hit SPIN, and the wheel decelerates onto a result. Entries
carry a good / bad / neutral tag — a good draw pops confetti, a bad draw
pours rain, neutral gets a subtle glow (all re-skinnable). Viewers can enter
drawings from chat with !entry. Theme designers can restyle the wheel with
CSS variables or replace the whole presentation (Magic 8-ball, crystal ball…)
— see docs/THEMING.md.
- No cloud, no accounts — everything runs on your machine over Streamer.bot's WebSocket.
- Deterministic spins — the sidecar picks the winner once; every OBS source and the control page derive the identical animation and land on the same slice at the same moment (docs/PROTOCOL.md).
- State survives restarts — entries, settings, and the last draw persist
in
config.json; overlays repaint on reconnect via a sync-on-connect replay.
| Piece | What it is |
|---|---|
overlay/wheel.html |
The OBS browser source (canvas wheel + effects) |
fortuna-shared/control.html |
Streamer control page (browser tab or OBS custom dock) |
fortuna-sidecar.mjs |
The one Node process — owns entries, timers, and the spin decision |
actions/*.cs |
Two tiny Streamer.bot C# actions (+ optional auto-start launcher) |
mock-sb-server.mjs |
A fake Streamer.bot for styling/dev with no SB install (npm start) |
Requirements: Streamer.bot 1.0.4+, Node ≥ 18, OBS.
First, get the code onto the machine that runs Streamer.bot — either
git clone https://github.com/FlashGalatine/fortuna-wheel.git
or click <> Code → Download ZIP on the repo page and extract it. The
<repo> paths below refer to that folder.
- WebSocket Server (Servers/Clients → WebSocket Server): Start it on
127.0.0.1:8080with Authentication OFF. - HTTP Server (Servers/Clients → HTTP Server): Start it on
7474and add two Path → Folder maps pointing into this repo:
| Path | Folder |
|---|---|
fortuna-overlay |
<repo>\overlay |
fortuna-shared |
<repo>\fortuna-shared |
Create two actions, each with a single Core → C# → Execute C# Code sub-action, named exactly:
Fortuna Push— paste actions/fortuna-push.cs, Compile.Fortuna Command— paste actions/fortuna-command.cs, Compile.
Optional: Fortuna Sidecar Start
(actions/fortuna-sidecar-start.cs, needs a
System.dll reference — instructions in the file header) so SB launches the
sidecar automatically.
Add Command triggers straight onto the Fortuna Command action — no
Set Argument sub-actions needed (the action detects chat triggers itself):
!entry— viewers join an open drawing;user/userIdare relayed automatically (one entry per viewer).!wheel <cmd> [value…]— mod controls:!wheel openEntries,!wheel closeEntries,!wheel addEntry Run it back | bad,!wheel spin. Consider restricting this trigger's permissions to moderators in SB.
Double-click start-fortuna.bat (installs deps on first run), or
npm install && npm run sidecar. A single-instance guard on :7493 makes double
launches harmless.
- Wheel overlay: Browser source →
http://127.0.0.1:7474/fortuna-overlay/wheel.html(1920×1080 recommended). - Control page: open
http://127.0.0.1:7474/fortuna-shared/control.htmlin a browser, or dock it: OBS → Docks → Custom Browser Docks.
- Add entries on the control page (or
setEntriesyour own list) and tag them. - SPIN. The result card pops with the tag's effect. “Remove it from the wheel” appears under the last draw; or tick remove the drawn entry afterwards / the always-on setting for elimination-style wheels.
- Viewer drawings: set max entries and/or a time window, click Open
entries, and chat joins with
!entry. When it fills up or times out the Spin button pulses — the spin itself stays in your hands.
npm start— mock Streamer.bot (HTTP :7474 + WS :8080) with a landing page;/mock/fixturebroadcasts a sample wheel, POST/mock/pushany payload.npm run verify— 49 offline checks: spin math determinism, the real panel-core against the mock (subscribe case, sync replay, serialized queue), HTTP maps, and a real sidecar E2E (entry CRUD,!entrydedupe/limits, spin lifecycle, restart persistence). Uses off-default ports (7478/8084/7494) so it runs beside a live SB.npm run verify:render— real-pixel checks in a system Edge/Chrome (npm i --no-save playwright-corefirst): painted wheel, revealed draw with confetti on the fx layer, control page. Writes gitignored PNGs.npm run shots— regenerates the docs screenshots.
| Port | What |
|---|---|
| 8080 / 7474 | Streamer.bot WebSocket / HTTP (or the mock's mimics) |
| 7493 | Sidecar single-instance guard (FORTUNA_GUARD_PORT) |
| 7478 / 8084 / 7494 | verify-suite off-default ports |
Built by Ashe "Flash" Galatine.
- Email — AsheJunius@gmail.com
- X — @AsheJunius · BlueSky — @projectgalatine.com
- Twitch — FlashGalatine
- Support — Patreon ProjectGalatine · CashApp $ProjectGalatine
MIT — see LICENSE. Sole runtime dependency is ws (MIT). See THIRD_PARTY_NOTICES.md.

