You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A web-based DPS simulator for World of Warcraft powered by SimulationCraft.
The application is DPS-only — healer and tank simulations are not supported.
Screenshots
Features
Battle.net Login — OAuth2 authorization, character fetching from armory
Armory Simulations — automatic character data retrieval from Blizzard API
Addon Export Simulations — paste SimulationCraft addon text without logging in
Great Vault Finder — /vault page; paste addon export (with Great Vault open in-game), auto-detects vault items, simulates each item as an upgrade and ranks them by DPS gain
Simulation History — all simulations saved, tied to Battle.net account (persists across browsers and re-logins); public list of recent results with pagination
DPS Trend Chart — DPS over time chart per character and fight style in the profile view
Emoji Reactions — 🔥💪😢💀🤣 reactions on simulation results; toggle/swap like YouTube thumbs; logged-in users only
DPS Charts — Total DMG + DPS pie charts (Plotly/kaleido, rendered server-side to PNG)
CSV Export — download spell breakdown as CSV from any result page
Social Sharing — every result has a unique URL with OG meta tags (Discord, Twitter previews)
Rankings — /rankings page with TOP DPS podium (🥇🥈🥉) + table for places 4–10; filterable by fight style, class, spec; one entry per unique character; top 3 mini-podium on home page
Result Page Enhancements — avg item level badge; equipped gear list with slot, ilvl, icon, Wowhead link; buff uptime bars; author profile link (/u/{bnet_id}); talent string display with one-click copy for in-game import
Admin Panel — manage news, appearance, simulation limits, health check, active job list, user list, logs (Keycloak OAuth2)
Admin Error Tracking — frontend window.onerror and unhandledrejection handler in admin/core.js; errors sent to POST /admin/api/client-error with IP-based rate limiting (10 req/min); stored in admin_logs table; visible in Logs tab filtered by ERROR
Rate Limiting — API abuse protection (slowapi, per-IP)
Watchdog — automatic cleanup of old jobs and timeout handling
Internationalization — full i18n PL/EN with language switcher, browser auto-detection and localStorage persistence
Main Character — modal on first login to select main character; saved permanently to Battle.net account (users table); displayed in header dropdown
User Dropdown Menu — header dropdown under the main character name with: Characters, History, Public Profile, Favorites, Settings, Logout
View Persistence — active view (home/symulacje/profil/ustawienia/ulubione) persisted via URL hash; browser back/forward works correctly
Settings Page — change main character (select from character list), language preference, theme preference; profile privacy toggle; per-character privacy
Sliding Session — session TTL extended by 30 days on every active use; no forced re-logins during normal usage
Skeleton Loaders — loading skeletons on home, symulacje, profil views instead of spinners
Smart History Loading — home always loads public history; /symulacje and /profil load private history for logged-in users, public for guests; history reloads on every view switch
Design Tokens — CSS custom properties for all colors (including --danger with dark/light theme variants), spacing, typography, radius, shadows
Public Profiles — every Battle.net user has a public profile at /u/{bnet_id} showing main character, best DPS, sim count and history; respects privacy settings
Favorites — logged-in users can favorite any public profile (❤️ button on profile page); favorites are tied to bnet_id and persist across all devices; accessible via /#ulubione
Spell Breakdown with Icons — spell icons from WoW CDN next to each ability; Wowhead tooltip on hover (native widget, tooltips.js); works on both #symulacje and /result/
Action Sequence Log — collapsible timeline of all events in a sample iteration (cast / proc / buff / debuff), with spell icons
Buff Uptime Bars — progress bars for all buffs and debuffs with partial uptime (0–100%); color-coded by type
Profile history: reaction counts — emoji reaction summary (🔥 3 💀 1) on each history entry in the profile view; backend aggregates counts from reactions table via LEFT JOIN
Admin: all registered users visible — user list uses LEFT JOIN so users with 0 simulations are shown with sim_count: 0
Roadmap
🤷 Może kiedyś
Admin: featured/pinned results — admin can highlight a specific simulation (e.g. weekly DPS record) with a custom label; pinned results appear in a dedicated section on the home page; max 3–5 at a time (#69)
Admin: role management — grant/revoke admin role directly from the panel without going into Keycloak console; requires Keycloak service account with manage-users permissions (#65)
Auth: unified login — link admin Keycloak account with Battle.net account for a single login flow; rejected for now — admin accounts are SSO-only, no BNet overlap (#57)
Requirements
Python 3.10+
PostgreSQL 15+
Docker & Docker Compose (recommended)
Battle.net developer account (OAuth2 app)
Keycloak (for admin panel)
Local Setup
Docker Compose (recommended)
cp .env.example .env
# Edit .env and fill in all required environment variables
docker compose up --build
The app will be available at http://localhost:8000.
Base application URL (used in OG meta tags and share links)
https://sim.miyazakitakara.ovh
KEYCLOAK_URL
⚠️ admin
Keycloak URL (for admin panel)
—
KEYCLOAK_REALM
⚠️ admin
Keycloak realm
—
KEYCLOAK_CLIENT_ID
⚠️ admin
Keycloak client ID
—
KEYCLOAK_CLIENT_SECRET
⚠️ admin
Keycloak client secret
—
ADMIN_REDIRECT_URI
⚠️ admin
OAuth callback URL after admin login
—
RESULTS_DIR
Directory for simulation results
/app/results
SIMC_PATH
Path to simc binary
/app/SimulationCraft/simc
MAX_CONCURRENT_SIMS
Max number of concurrent simulations
3
JOB_TIMEOUT
Simulation timeout in seconds
360
JOBS_TTL
Lifetime of completed jobs in memory (seconds)
14400 (4h)
ALLOWED_ORIGINS
CORS allowed origins (comma-separated)
*
LOG_LEVEL
Log level (DEBUG/INFO/WARNING/ERROR)
INFO
Admin Panel
The admin panel is available at /admin and requires a Keycloak session.
What you can configure
Section
What you can do
Appearance
App emoji, header title, hero text — changes reflected instantly without restart
News
Add, edit, publish/unpublish news entries shown on the home page
Limits
MAX_CONCURRENT_SIMS, JOB_TIMEOUT, JOBS_TTL — adjustable at runtime
Tasks
View active/running simulation jobs, cancel a stuck job
Health
Check status of PostgreSQL, SimulationCraft binary, results directory
Users
Browse registered users (all users, not just those who ran simulations)
Logs
Browse structured application logs by level (INFO/WARNING/ERROR); includes frontend JS errors
Appearance config
Appearance is stored in appearance.json in the results directory and served via GET /api/appearance (public, no auth required). The frontend fetches it on every page load.
The frontend uses Alpine.js with a mixin pattern. Key rules:
app() is the only Alpine x-data on the main page
Views (views/*.html) are loaded dynamically by loadView(name) into #view-container and initialized via Alpine.initTree() — they have no own x-data, they operate within the parent scope
Exception: views that need isolated state (e.g. ulubione.html) use x-data="favoritesView()" but the function must be defined globally (in a <script> loaded in index.html) before Alpine boots — inline <script> inside innerHTML is not executed by the browser
Mixins (SimMixin, CharsMixin, HistoryMixin) are merged by mergeMixins() which uses Object.defineProperties — this ensures getters (e.g. sortedSpells, filteredChars) are correctly copied with their descriptors preserved
Getters referencing this.* must be defined directly in the state object in app(), not in mixins — ...spread destroys getter descriptors
rankings.html, profile.html and vault.html are standalone pages (not views), served by FastAPI at GET /rankings, GET /u/{bnet_id} and GET /vault
State property names matter — views use the actual state field names (e.g. loadingHistory, not aliases); aliased names are not visible after Alpine.initTree()
Wowhead tooltips — tooltips.js loaded in both index.html and result.html; whTooltips = {colorLinks:false, iconizeLinks:false, renameLinks:false}; on /result/WH.Tooltips.refreshLinks() is called after Alpine renders spell links into the DOM (await $nextTick())
CSS Design Tokens
All visual constants are defined as CSS custom properties in :root and overridden in [data-theme="light"]:
Token
Dark
Light
Usage
--accent
#c89a3c
#a07820
Primary brand color, active tabs, CTA buttons
--accent2
#7c5cfc
#5a3fd4
Secondary accent, public char buttons
--danger
#c0392b
#e74c3c
Destructive actions, private char buttons, active segment buttons