Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
214 commits
Select commit Hold shift + click to select a range
1fce5dd
cleanslate and move on
kkortes Apr 8, 2026
7352faf
cleanslate and move on
kkortes Apr 8, 2026
feaefc8
cleanslate and move on
kkortes Apr 9, 2026
c10d9b3
cleanslate and move on
kkortes Apr 9, 2026
bb83fce
cleanslate and move on
kkortes Apr 9, 2026
708c416
cleanslate and move on
kkortes Apr 10, 2026
6f36b65
cleanslate and move on
kkortes Apr 10, 2026
6826ddd
cleanslate and move on
kkortes Apr 10, 2026
4185d5d
cleanslate and move on
kkortes Apr 10, 2026
6ce3dba
cleanslate and move on
kkortes Apr 10, 2026
f3bf754
cleanslate and move on
kkortes Apr 10, 2026
0ade1b3
cleanslate and move on
kkortes Apr 10, 2026
fecb83b
cleanslate and move on
kkortes Apr 12, 2026
d6cfb68
cleanslate and move on
kkortes Apr 12, 2026
6b78f8a
cleanslate and move on
kkortes Apr 12, 2026
33224db
cleanslate and move on
kkortes Apr 13, 2026
f88451e
cleanslate and move on
kkortes Apr 14, 2026
b1e9b3c
cleanslate and move on
kkortes Apr 14, 2026
b0e37b1
Merge pull request #9 from ApeEgg/feat/implement-vite
kkortes Apr 14, 2026
53b64fa
cleanslate and move on
kkortes Apr 14, 2026
9842f44
cleanslate and move on
kkortes Apr 14, 2026
e5bc69f
cleanslate and move on
kkortes Apr 14, 2026
8e9ac5d
cleanslate and move on
kkortes Apr 14, 2026
fc820af
cleanslate and move on
kkortes Apr 15, 2026
9be7627
cleanslate and move on
kkortes Apr 15, 2026
f738d3a
cleanslate and move on
kkortes Apr 15, 2026
2385ceb
cleanslate and move on
kkortes Apr 16, 2026
afa2c5e
cleanslate and move on
kkortes Apr 16, 2026
6f6dafc
cleanslate and move on
kkortes Apr 16, 2026
c3bd7c8
cleanslate and move on
kkortes Apr 16, 2026
3f03249
cleanslate and move on
kkortes Apr 16, 2026
42427d8
cleanslate and move on
kkortes Apr 16, 2026
0843dec
cleanslate and move on
kkortes Apr 16, 2026
34d257d
cleanslate and move on
kkortes Apr 16, 2026
ca25a5a
Add launch.json for dev server configs and fix game server startup
kkortes Apr 17, 2026
4da8ce5
theme refactor via light-dark() and inspector polish
kkortes Apr 17, 2026
1a9202f
add readme stub
kkortes Apr 17, 2026
16a1df1
default master volume to 0 and add clear localStorage button to DevBar
kkortes Apr 17, 2026
33e82e1
readme: minor whitespace
kkortes Apr 17, 2026
2a21558
fix: persist rememberMe, codeOfConduct, email and password via settings
kkortes Apr 17, 2026
edb27b4
chore: update stylecheat
kkortes Apr 17, 2026
07b9890
fix: sidebar spacing, bar colors and headline alignment
kkortes Apr 17, 2026
f81c4ca
chore: update CLAUDE.md and authorization cleanup
kkortes Apr 17, 2026
39d6f64
cleanslate and move on
kkortes Apr 18, 2026
e78a4d6
cleanslate and move on
kkortes Apr 18, 2026
9e23c74
cleanslate and move on
kkortes Apr 18, 2026
fc11482
fix: render sidebar HP via split spans toggled by show-numeric
kkortes Apr 18, 2026
f92ea7a
fix: clear stale cookie on auth failure to prevent reload loop
kkortes Apr 18, 2026
61b4881
Merge wip/continue-rewrite into chore/major-rewrite-to-stylecheat-and…
kkortes Apr 18, 2026
8f35a84
fix
kkortes Apr 18, 2026
902bfaf
combat-loop: enrich per-combatant render props for circular arena
kkortes Apr 18, 2026
9b32a0c
combat: add CombatArena/AbilityBar/HealthBar/Image/Card Vibe components
kkortes Apr 18, 2026
2a8162b
combat: add VictoryOrLoss and ResultAnnouncement components
kkortes Apr 18, 2026
2fc769c
combat: rewrite Combat overlay as circular arena composition
kkortes Apr 18, 2026
d86698b
ix
kkortes Apr 18, 2026
6b7a5ca
Merge wip/continue-rewrite: combat UI port + Vibe conditional fix
kkortes Apr 18, 2026
8c699ef
deps: switch to bare imports, remove /nodemodules/ scheme
kkortes Apr 18, 2026
6204ab0
merge wip/continue-rewrite: bare imports
kkortes Apr 18, 2026
893fa58
cleanslate and move on
kkortes Apr 19, 2026
15a7c7b
fix
kkortes May 1, 2026
0624db9
test
kkortes May 1, 2026
7b4b793
bump vibe, truly
kkortes May 1, 2026
1ca2454
deploying to vercel
kkortes May 1, 2026
dfd7acc
deply config
kkortes May 1, 2026
ea10473
test
kkortes May 1, 2026
474c32e
configure dev launch + allow .test hosts in vite
kkortes May 6, 2026
ce97368
Merge branch 'wip/continue-rewrite' into chore/major-rewrite-to-style…
kkortes May 6, 2026
3bc3828
chore: open battle-brawlers infinite PR
kkortes May 6, 2026
d9cb731
test
kkortes May 6, 2026
2e3a10b
refactor: drive data inspector rows with stylecheat accordion
kkortes May 6, 2026
c58860f
refactor: address PR #20 review feedback
kkortes May 7, 2026
cd068ba
fix: address PR #22 review feedback
kkortes May 7, 2026
6ae19a8
add prettier with pre-commit hook and format codebase
kkortes May 7, 2026
7c0804a
remove data-* attrs, divs, nested calc, and svelte residues
kkortes May 7, 2026
fe619a3
split BrawlerDetailContent + clean up CSS, conventions, inspector
kkortes May 7, 2026
493e45f
fix tooltip pointer, scaling pages, devbar persistence, and conventions
kkortes May 7, 2026
41b4597
fix tooltips, tier colors, scaling-page defaults, ability tooltip parity
kkortes May 8, 2026
647b2e4
add ability status overlay, fix status colors and stun icon
kkortes May 8, 2026
20dc760
rewrite equipment tooltip and unify stat metadata
kkortes May 8, 2026
e27585e
overhaul /debug, align combat visuals with reference
kkortes May 11, 2026
94c19d8
fix combat scaling, statuses, debug heal sync
kkortes May 11, 2026
61ade10
fix combat parity: stack victory, rewards staging, ability bar, modal…
kkortes May 11, 2026
8026164
optimize DataInspector: short-circuit closed branches, memoize derive…
kkortes May 11, 2026
f2fb376
touch-ups: unify accordions, consolidate ability dnd, restructure sid…
kkortes May 11, 2026
b69edc2
fix victory stinger double-play, combat exit state, accordion expand
kkortes May 11, 2026
2b1860e
fix brawler-detail redirect, ability bar dnd-zone height, the-arena r…
kkortes May 13, 2026
5c5e6ac
add inventory drawer + equipment table, drawer/tooltip touch-ups
kkortes May 21, 2026
92dde3c
touch-ups: chevron rotation system, full-width sidebar cards, back-bu…
kkortes May 22, 2026
a9d805e
fix progression scroll target and assorted UI inconsistencies
kkortes May 22, 2026
49db330
fix tooltips, coin stack wrapping/empty state, and assorted UI
kkortes May 23, 2026
6096036
fix ability dnd slot sizing, cross-character drops, random-duel parity
kkortes May 24, 2026
86df763
added esbuild
kkortes May 25, 2026
6db26a2
new vibe version
kkortes May 25, 2026
759546d
fix
kkortes May 25, 2026
85ad784
lock tooltips in place; keep symlinked vibe live in dev
kkortes May 25, 2026
85eb908
fix
kkortes May 28, 2026
356704d
pr review fixes
kkortes May 28, 2026
9ca7b00
fix bar fill direction, tooltip spacing, data inspector clicks
kkortes May 28, 2026
f24104d
new stylecheat version
kkortes May 28, 2026
6132419
more component and styling fixes
kkortes May 28, 2026
2504ffe
Merge branch 'feat/more-fixes' into chore/major-rewrite-to-stylecheat…
kkortes May 28, 2026
89ef0f1
rework notifications, brawler slot dropdown, prettier formatting cleanup
kkortes May 28, 2026
39be457
slim color palette to base hues + semantic aliases, unify ability-bar…
kkortes May 28, 2026
a7f9cbb
Merge branch 'chore/major-rewrite-to-stylecheat-and-vibe' into game/b…
kkortes May 28, 2026
e1dde12
bump vibe to 1.9.6
kkortes May 28, 2026
42e1cd0
rename async-await-websockets to @ape-egg/async-await-websockets
kkortes May 28, 2026
52e27de
Merge pull request #27 from kkortes/chore/scope-aaw-to-ape-egg
kkortes May 28, 2026
fc96b9d
unify <stay> chrome, refine menu and fight bars, destructure backend …
kkortes May 29, 2026
661ed5d
Merge pull request #28 from kkortes/feat/stay-stone-blocks
kkortes May 29, 2026
6c65779
disable cleanUrls so component .html fetches don't 308-redirect
kkortes May 29, 2026
bb6ca56
Merge pull request #29 from kkortes/chore/vercel-clean-urls-off
kkortes May 29, 2026
51a426f
cache component templates 5min, hashed assets forever
kkortes May 29, 2026
b50aafb
Merge branch 'chore/vercel-clean-urls-off' into game/battle-brawlers
kkortes May 29, 2026
e0fad8a
soften --rarity-common gray; show actual HP on sidebar brawler bar ho…
kkortes May 29, 2026
d3b8768
redesign brawlers gallery and brawler-detail layout, extract BrawlerP…
kkortes May 29, 2026
a9bf3e0
fix mismatched size-constraint close tags
kkortes May 29, 2026
d8cd2f3
extract Dialog shell, restyle modals, reposition notifications
kkortes May 29, 2026
cc74c7e
rebuild home as guide+FAQ, clickable logo, extract IconCell, swap Dev…
kkortes May 29, 2026
5f16dcf
Update components/Topbar.html
kkortes May 29, 2026
89554ce
rebuild CoreStats with IconCell baseplate, mobile polish, dnd grab-of…
kkortes May 29, 2026
f580870
Merge branch 'feat/clean-up-core-stats-presentation' into feat/sporad…
kkortes May 29, 2026
c70e093
redesign AccountProgression as battle pass + notification icons + tab…
kkortes May 29, 2026
4722f99
chore: scaffold inventory design cleanup branch
kkortes May 29, 2026
8fac834
swap inventory drawer background from scrim-1 to white
kkortes May 29, 2026
84bbfd6
match inventory drawer to ability inventory bg, border + inset shadow
kkortes May 29, 2026
1cdf929
frame inventory with stone-textured padding, fix accordion-content se…
kkortes May 29, 2026
f5f7fc7
wrap inventory padding in inner frame so accordion closes cleanly
kkortes May 29, 2026
182a0d9
apply HP/Armor/Dmg/Res modifiers from character + equipment to combat…
kkortes May 30, 2026
de11daf
apply All Resistances modifier to status limits, rename Res tag
kkortes May 30, 2026
2f30b25
render modifier values in green like lucky stats
kkortes May 30, 2026
d4509bf
rename lucky styling prop to percentage, iterate all limits, move sho…
kkortes May 30, 2026
3b60146
merge STAT_SHORT_LABELS into STAT_LABELS as single source of stat names
kkortes May 30, 2026
240bc68
fix
kkortes May 30, 2026
0502f93
fix: format stat value of 1 as number not 100%
kkortes May 30, 2026
d72d4c5
add Steel armor, Alora's Touch signature heal, stat budget table
kkortes May 30, 2026
51ff420
add intimidating roar troll signature, unified buff/debuff system wit…
kkortes May 30, 2026
e8b0c95
add combat-components dev page: status chips, VFX animations, SFX audio
kkortes May 30, 2026
bd15815
auto-generate counter variants from STATUS_EFFECTS
kkortes May 30, 2026
3f65f6a
key status-chip each-loops by statusKey so chips don't flicker per tick
kkortes May 30, 2026
1481a00
replace per-status icon overlay on ability tiles with a single buff/d…
kkortes May 30, 2026
db7bf88
tune intimidating roar duration from 3 to 2 ticks
kkortes May 30, 2026
3d333ba
add Stoneskin dwarf signature: self-applied 50% damage-taken buff
kkortes May 30, 2026
e9c2af5
shorten level-up Platinum coin label to Coin
kkortes May 31, 2026
b32c7a9
make Stoneskin a WindDown so the buff lands at cast start
kkortes May 31, 2026
eadbaf5
rename ability appliesTo to target with self/enemy values
kkortes May 31, 2026
f7b6579
Merge branch 'dwarf-signature-stoneskin' into feat/intimidating-roar
kkortes May 31, 2026
f8aac5a
add Warcry human signature and split damage multipliers into incoming…
kkortes May 31, 2026
f6987f4
add hit chance lucky stat and miss animation
kkortes May 31, 2026
797de26
add Smokebomb goblin signature and fix boss-fight miss roll
kkortes May 31, 2026
a5aad97
wire dedicated icons for hitChance, stoneSkin, smokeBomb, warCry, int…
kkortes May 31, 2026
4aabd28
wire alorasTouch icon and reorganize _icons holding pen
kkortes May 31, 2026
6c9bfea
add Gore and Pretending to be humble abilities, fight descriptions, i…
kkortes May 31, 2026
c22b4cb
add emil_jonsson_91@hotmail.com to TESTER_EMAILS
kkortes May 31, 2026
b39a8da
gate Heal now button on isTester
kkortes May 31, 2026
2f7c431
rework DevBar reset buttons, gate element badges, add icons page
kkortes May 31, 2026
d7bccad
build Gear Up vendor/blacksmith cards with level tiers
kkortes May 31, 2026
c18b221
revamp armor as flat damage reduction with armor penetration
kkortes Jun 1, 2026
e909ec4
refine equipment & ability tooltips, reuse StatGroup for stats
kkortes Jun 1, 2026
130c071
add provoke stat: weighted aggro, combat chance display, Steel +10
kkortes Jun 1, 2026
3322ae2
add brawler activity state, rework buff/debuff icons, bump vibe 1.9.7
kkortes Jun 1, 2026
cf0f769
add ability combat stats: 50% Block, Heartpiercer + Powershot weapon,…
kkortes Jun 1, 2026
4e0aebd
remove rarity colors, add brawlers character icon
kkortes Jun 1, 2026
e07dfa4
add test mode toggle, gate battle pass behind tester, fix lock-closed…
kkortes Jun 1, 2026
c128a75
render tooltip descriptions as HTML via $.unsafe, relocate status dur…
kkortes Jun 1, 2026
e895f7f
add flat tooltip gallery page, make tooltip cards prop-driven
kkortes Jun 1, 2026
748672a
rename provoke to provocation, polish tooltips and combat shield
kkortes Jun 1, 2026
3f6b308
fix matchmaking xp range off-by-one, remove debug script
kkortes Jun 1, 2026
75c3853
add weapon arsenal, derive item cost from level, rebalance armor
kkortes Jun 1, 2026
e737393
add eraromik@gmail.com to tester whitelist
kkortes Jun 2, 2026
98f3163
fix
kkortes Jun 2, 2026
cb36f9b
expose game version in topbar, add release-push, rename server dir
kkortes Jun 3, 2026
b02a7d9
chore(release): v0.1.1
kkortes Jun 3, 2026
a31453e
chore(release): v0.1.2
kkortes Jun 3, 2026
cc0f4ee
chore(release): v0.1.3
kkortes Jun 3, 2026
6c32371
fix release-push: set upstream on push
kkortes Jun 3, 2026
71174f0
chore(release): v0.1.4
kkortes Jun 3, 2026
58f25f4
add ability designs dev page and bar damage numbers
kkortes Jun 4, 2026
489951a
refactor ability bars onto shared AbilityBar component
kkortes Jun 4, 2026
e001b36
fix brawler ability resolution, overflow hiding, and slot drag-and-drop
kkortes Jun 5, 2026
26e48c9
add brawler-slot flip animation and shared fight-slot dnd
kkortes Jun 5, 2026
a6dda1e
add ability bar healing numbers and debug creature blacklist
kkortes Jun 6, 2026
f52e54a
refine ability cell designs and inventory layout
kkortes Jun 6, 2026
fc981b8
add desktop click-to-add ability selection + touch dnd
kkortes Jun 6, 2026
273627c
refine equipment tooltip and ability cell UI
kkortes Jun 6, 2026
02deda4
fix plain tooltip to fit content, add text showcase + worktree setup
kkortes Jun 7, 2026
616669a
Merge branch 'claude/compassionate-benz-3ef397' into feat/more-ui-ux-…
kkortes Jun 7, 2026
9e512f5
refactor tooltips and move isTester into settings
kkortes Jun 7, 2026
8070737
add basic-ability styling, shared Cross button, ability bar cursor
kkortes Jun 7, 2026
e88489f
add ability elements with tinting, fix available abilities render
kkortes Jun 7, 2026
11ff1b2
improve dodge animation with duplicating ghost effect
kkortes Jun 7, 2026
666ade1
add equipment type/race system, race dots in gear-up listing
kkortes Jun 8, 2026
eb74f37
bump vieb
kkortes Jun 8, 2026
6358fd4
add form-elements page with Stylecheat disabled-state overrides
kkortes Jun 8, 2026
5ddb0e5
fix mis-nested button/crow tags in form-elements page
kkortes Jun 8, 2026
c693f38
add equipment stats, elemental resistances, and signature abilities
kkortes Jun 9, 2026
e632ba7
add combat preview with state toggles to combat-components page
kkortes Jun 9, 2026
126b2b1
redesign combat status effects as elemental pins with announce and ti…
kkortes Jun 9, 2026
ecb08cd
fix ability bar rendering, dnd ghost, self-cast absorb, floater sizing
kkortes Jun 10, 2026
41c46f1
add tester race-lock skip, tooltip status chips, XP level cap, combat…
kkortes Jun 10, 2026
b57b45f
add heal buffer, ghost hp trail, ability anticipation squish, combat …
kkortes Jun 10, 2026
3436abc
make ability buffs cover attacks on start and end ticks
kkortes Jun 10, 2026
78b56d0
add specialization hint, badge variants, up-to fight slots, ui polish
kkortes Jun 10, 2026
35af7e8
add fight button face lift, sounds browser, weapon swing sfx
kkortes Jun 10, 2026
1b690a2
discount all in-combat healing at fight end via healingReceived ledger
kkortes Jun 10, 2026
11030dd
add tester entity admin tool: /_internal character editor with file-w…
kkortes Jun 10, 2026
b7cbea6
add imagegen tool: fullscreen prompt modal, character schema, spider …
kkortes Jun 11, 2026
881296d
fix select-press arming on unbrawlable states, composite ability bars
kkortes Jun 12, 2026
eb762ed
add weave/skewer/recharge icons, fix spider-web holes, stagger brawl …
kkortes Jun 12, 2026
5398292
add immobilized banner, pve sizing, weave stagger, fight page facelift
kkortes Jun 12, 2026
0667263
add debug playground, balance graphs, stat tooltips, vendor portraits
kkortes Jun 12, 2026
fd742d0
add Skjaldborg shield, Shield Wall ability, element tooltip borders
kkortes Jun 13, 2026
7e0a415
add stomp ability sfx, faster release, tooltip alt-detail reveals
kkortes Jun 14, 2026
b4bd126
fix inventory keybind seeding, debug item levels, combat tweaks
kkortes Jun 14, 2026
5ad8b1d
add ability icons, riposte counter, combat buff fix, tooltip cleanup
kkortes Jun 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 18 additions & 0 deletions .claude/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"version": "0.0.1",
"configurations": [
{
"name": "Battle Brawlers (Frontend)",
"runtimeExecutable": "bun",
"runtimeArgs": ["run", "dev"],
"port": 5000,
"autoPort": true
},
{
"name": "Battle Brawlers (Backend)",
"runtimeExecutable": "bun",
"runtimeArgs": ["--cwd", "server", "--watch", "--env-file=.env", "index.js"],
"port": 1337
}
]
}
14 changes: 14 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "bash \"$CLAUDE_PROJECT_DIR/scripts/setup-worktree.sh\""
}
]
}
]
}
}
6 changes: 6 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh
files=$(git diff --cached --name-only --diff-filter=ACMR)
[ -z "$files" ] && exit 0

git diff --cached --name-only --diff-filter=ACMR -z | xargs -0 bunx prettier --write --ignore-unknown --log-level=warn
git diff --cached --name-only --diff-filter=ACMR -z | xargs -0 git add
27 changes: 18 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
node_modules

# Output
.output
.vercel
/.svelte-kit
/build
dist

# OS
.DS_Store
Thumbs.db

# Env
.env
.env.*
!.env.example
!.env.test

# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
.env*.local

# Logs
*.log

# Editor
.vscode
.idea

# Claude
.claude/*
!.claude/launch.json
!.claude/settings.json

# Stuff
_potential
_unused
_unused

# Test artifacts
test-results
static/audio/Imported Assets
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20.0
24.12
13 changes: 13 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
node_modules
dist
build
.vercel
.output
test-results
bun.lockb
.env*
.claude/settings.local.json
static
*.svg
_potential
_unused
5 changes: 1 addition & 4 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
{
"useTabs": false,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
"plugins": ["@ape-egg/prettier-plugin-vibe"]
}
87 changes: 87 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Battle Brawlers

The world's websites are overengineered. It doesn't have to be that way. Keep it simple Claude.

Strategy auto-battler. Currently a Multi-Page App with Vite middleware mapping URLs to `pages/*.html`; **subject to change** — could become an SPA later, so don't lean on MPA assumptions in feature code. The game must work responsively down to ~360px wide; reach for Stylecheat's three media queries (`sm:` ≤768px, `md:` 768–1024px, `lg:` >1024px) before any custom `@media`.

Open work — missing assets, content, and roadmap items — lives in [`TODO.md`](TODO.md). Log new gaps there as you hit them.

## Stack

- **Runtime**: Vibe (`@ape-egg/vibe`) — runtime-first reactive framework
- **CSS**: Stylecheat (hybrid build) — attribute-based CSS framework. We use `ChromeOnlyModifiers.css` (the `[g] { gap: calc(attr(g type(<number>)) * var(--unit)); }` form), **not** `Modifiers.css` (the `g-4`/`p-2` form).
- **Dev server**: Vite via `vite-plugin-vibe` for HMR. A custom `mpa-routes` middleware in `vite.config.js` maps URLs to `pages/*.html` (including dynamic routes like `/brawlers/:i` → `pages/brawler-detail.html`).
- **Vibe source**: Symlinked from `/Users/kortes/Projects/webdev/vibe/nodemodules/@ape-egg/vibe` (also `vite-plugin-vibe`).
- **`@ape-egg/async-await-websockets` source**: Symlinked from `/Users/kortes/Projects/webdev/async-await-websockets` (root + `server`).

## Dogfooding Vibe & Stylecheat

This project is the **primary dogfood** for `@ape-egg/vibe` and Stylecheat — both live as symlinks (see Stack). Things you'd expect from a mature framework (React/Vue/Svelte) may simply be missing in Vibe.

**When you hit a Vibe quirk or bug, STOP. Do not work around it.** No `setTimeout`, no `queueMicrotask`, no reaching into `window.__vibe*`, no wrapping in a manual signal. Workarounds in app code hide the gap and let it rot.

Instead, report it to me in this exact shape:

1. **The issue** — what Vibe does vs what you expected (one or two sentences).
2. **What you're trying to do** — the actual code you wanted to write, pasted inline as a code block, even if it doesn't run.
3. **Proposed solutions** — 1–3 options: the upstream fix in `webdev/vibe`, and (if applicable) a temporary local workaround. Be explicit that the upstream fix is the right one.

Frame it as **"Vibe is missing feature parity with modern frontend frameworks"** — because that's what most of these are. I decide whether we fix it upstream now or accept a workaround for this turn.

The same applies to Stylecheat (but rarer — Stylecheat is more mature).

## Game Server

The WebSocket backend lives in `server/`. Frontend integration:

- Connection lives on `$.socket` (see `js/connectSocket.js`); lifecycle is managed centrally — features should consume `$.socket` rather than open new connections.
- **Calling backend functions**: every file under `server/events/` is a server function, addressed by its path. Invoke from the client with `await $.socket.sendAsync('<dir>/<file>', payload)` — e.g. `events/user/authenticate.js` is `$.socket.sendAsync('user/authenticate', { token, … })`, `events/pvp/get-random-opponent.js` is `$.socket.sendAsync('pvp/get-random-opponent', …)`. New backend capabilities → drop a `.js` file in `events/<dir>/<file>.js` (server auto-registers) and call it the same way from the client.
- Game state seeded onto `$` flows from the server through `sendAsync` responses (mainly in `js/boot.js` and `js/connectSocket.js`). New event handlers should plug into the same place so reactive bindings stay coherent.
- Auth happens via `$.token`; the server validates it on the websocket handshake. Don't store credentials elsewhere.
- Constants (`js/constants/*`) must match the server's expectations — when the backend renames or adds a key, update the constant file in lockstep.
- Helpers belong in `/js/helpers.js`. Tiny utilities (formatters, parsers) should not get their own files.

## Guidelines for CLAUDE

`~` = enforce
`-` = avoid
`❌` = forbidden

### Testing

- `-` Playwright MCP, unless explicitly asked.
- `~` Prefer the Claude Desktop App Preview for in-app checks over the Playwright test browser.
- `~` Rely on manual browser testing — the user runs the game and reports issues; point out what to check.

### Markup & components

- `❌` HTML comments. The only HTML "comments" allowed are Vibe directives (`<!-- if -->`, `<!-- else -->`, `<!-- /if -->`, `<!-- each -->`, `<!-- /each -->`) — reactive control flow, not comments. Use JS `// TODO:` for "do later".
- `❌` `<div>`. Use semantic/custom element names: `<page-home>`, `<fight-row>`, `<ability-cell>`, `<xp-bar>`, `<coin-stack>`, etc.
- `❌` `class=""`. Exception: `<a class="button">` to give a tag a different visual treatment (Stylecheat keys some looks off `class`).
- `❌` `style=""`. Set CSS custom props via `<element attr="@[value]">`; only acceptable for unavoidable cases like tooltip absolute positioning.
- `-` `data-*` prefix. Use plain attributes — CSS `chip[stunned]`, HTML `<element @[status]>`. Exception: genuine HTML data semantics like `data-src`.
- `~` Reuse the wrapper element's name for inner pieces — `<tooltip>`/`<tooltip-content>`/`<tooltip-title>`, `<combatant-card>`/`<combatant-header>`/`<combatant-name>`.
- `~` Page structure: `<script type="module">` at top, `<page-xxx>` wrapper, `<style>` at bottom.
- `~` Call functions bare from markup: `onclick="fn()"`, never `onclick="window.fn()"`.

### Styling & CSS

- `~` Prefer Stylecheat attributes (`g="4"`, `p="2"`, `vertical`, `primary`, `absolute`, `flex`, `down`, …) over hand-written CSS. Use ChromeOnly forms — `g="4"`, not `g-4`.
- `~` Local component styles go in a `<style>` at the bottom of the file, scoped with `[component-name]` (or unscoped when the element name is already unique). Lift shared/theme styles into `css/index.css`.
- `~` `attr()` is Stylecheat-only. For attribute-driven custom values, set a `--x` custom prop via a Vibe binding + a one-line rule.
- `-` `z-index`. Stacking should fall out of source order, `position`, and stacking contexts. Reorder the DOM first; in flex/grid use `order: -1` (see `css/stylecheat.css` ~line 1989). Last resort only: a named `var(--z-…)` token, and ask first.
- `❌` Hex colors outside `css/index.css`. Always `var(--color-name)`; add the var to `index.css` first if it's missing.
- `❌` `rem`, and raw `px` greater than `1px`. Use `calc(var(--unit) * N)`.

### Reactive state (Vibe)

- `~` Global state via `$` (not `window.$`). Component-local state: `const id = component(state); const s = $[id];`.
- `❌` Touching `window.__vibe*` internals (`__vibeComponents`, `__vibeGlobalState`, `__vibeManifest`, …). If something seems to need them, that's a missing public API → fix it upstream in `webdev/vibe`.
- `~` Boolean attributes: a pure `@[expr]` on a non-`data-*`/`aria-*`/`on*` attribute becomes a real boolean attribute (set when truthy, removed when falsy). `<modal-root open="@[when]">` + CSS `modal-root[open]` / `:not([open])` works directly.
- `~` Name-binding: when an attribute name equals the binding leaf (`name="@[ability.name]"`), use `<element @[ability.name]>` — same pattern as `<icon @[ability.icon]>`.
- `❌` Baking a loop-derived value into a handler with `@[…]`. A `@[…]` span is stringified once at hydrate, so `@[idx]`/`@[item.x]` goes stale on reorder/removal (this is how `equipItem($.inventory[@[idx]])` broke). Reference the loop alias bare — `onclick="equipItem(item)"` — and read `$.state` live inside the handler. The only `@[…]` that belongs in a handler is component-local `this.X`.

### Files

- `~` Every file ends with a trailing newline.
- `~` Imports: package imports first, then relative project imports.
79 changes: 64 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
## My personal repo
# Battle Brawlers

This repo is a work in progress and is currently my personal thing. Feel free to fork or ask questions about it, but expect things to change drastically.
Strategy auto-battler — a per-game branch of the [`webdev-game-stack`](https://github.com/kkortes/webdev-game-stack) monorepo

## Information

This is a highly opinionated monorepo for game dev using web tech.

The stack is:

- `Svelte` for frontend (https://svelte.dev)
- `Vibe` for frontend (runtime-first reactive framework via `@ape-egg/vibe`)
- `Stylecheat` for styling (attribute-based CSS framework)
- `Vite` + `vite-plugin-vibe` for dev server / HMR
- `Bun` for backend (https://bun.sh)
- `MongoDB` for database (https://www.mongodb.com)

## Run the client locally

```
nvm use
bun install
bun dev
```

The dev server is reachable both at `http://localhost:<port>` (printed on start) and at `https://webdev-game-stack.test` via the local Caddy proxy.

## Run the server locally

`touch .env` and add:
`touch server/.env` and add:

```
PORT=1337
Expand All @@ -34,9 +35,9 @@ PASSWORD_RESET_HASH=<custom_hash>
```

```
cd svelte-game-server
npm install
npm run dev
cd server
bun install
bun run dev
```

## Features
Expand All @@ -45,13 +46,61 @@ npm run dev
- ✅ Account log in
- ✅ Account creation
- ✅ Account password recovery
- ✅ Notification center
- ✅ Render backend hosting setup (https://render.com)
- ✅ Vercel frontend hosting setup (https://vercel.com)
- ✅ Tailwind CSS for styling (https://tailwindcss.com)
- ✅ Vibe + Stylecheat front-end (formerly Svelte + Tailwind)

## Code base quirks
## Combat stats budget

Source of truth for balancing races, equipment, racial bonuses, and (eventually) player-allocable specs. Pricing is **linear — no diminishing returns, no soft caps**.

**Baseline anchor:** `1 spec point = 2 damage = 4 health`

### Flat stats — what 1 spec point buys

Armor in this table assumes the **flat-reduction model**: each point of armor subtracts 1 damage from every incoming hit (clamped at 0). It does not deplete.

| Stat | 1 spec point = |
| ---------------------------------- | --------------------------------- |
| Health (`maxHealth`) | +4 HP |
| Armor (`maxArmor`) | +1 armor (flat reduction per hit) |
| Damage (`damage`) | +2 damage |
| Critical Chance (`criticalChance`) | +1% |
| Critical Damage (`criticalDamage`) | +10% |
| Block Chance (`blockChance`) | +1% |
| Dodge Chance (`dodgeChance`) | +1% |
| Magic Chance (`magicChance`) | TBD — mechanic pending |

### Modifier stats — what 1 spec point buys

- `.env (development) & .env.production (production)` are injected into `src/constants/ENV_VARS.ts`. Trying to parse `import.meta.X` won't work in Svelte files, due to vite crashing when there is CSS in the files that they parse.
Modifiers are % multipliers in `combatStats.modifiers`. Rates below are pegged to default base values so the EV roughly matches the flat-stat table.

| Modifier | 1 spec point = |
| ---------------------- | ------------------------------------------------------- |
| `modifiers.maxHealth` | +15% |
| `modifiers.maxArmor` | +10% |
| `modifiers.damage` | +25% |
| `modifiers.resistance` | +2% (scales `wounded`/`concussed`/`exposed` thresholds) |

### Rules

- Linear pricing only. Stats must be honest and easy for the player to calculate.
- Unimplemented stats (currently `magicChance`) don't render in any UI until they have gameplay.
- When adding a new stat, give it a row here _before_ it ships. If it can't be priced linearly, it doesn't ship.
- Racial bonuses, equipment rolls, and spec choices all draw from the same currency — this table is the contract.

### Cost & the coin economy

Because stat scaling is linear, equipment doesn't differentiate by stat _shape_ — a higher-level piece is simply more of the same (e.g. armor = its level, so a higher-level armor is a strict upgrade of a lower one). The differentiator is **coin cost**, spent against a deliberately scarce economy: a player has roughly **25 coins total by level 25, shared across all 6 characters**. You can't gear everyone in top equipment — every purchase is a trade-off.

So when pricing current and future equipment:

- **Cost is the balancing lever, not stats.** A strictly-better item must cost proportionally more coins; price is what gates power, not stat complexity.
- Cheap, low-level gear stays relevant as the affordable pick when coins are tight.
- The only stat-shape trade-off we currently make is **heavy armor** (`+10` armor for `−40%` hit chance). Everything else competes purely on cost-vs-power along the linear curve.

## Code base quirks

- This repo utilizes `sveltekit-autoimport` (https://github.com/yuanchuan/sveltekit-autoimport) hence some `.svelte` and `.js` imports seem to magically appear out of nowhere. See `vite.config.js` to see what's going on.
- Routing is currently MPA-flavored: a Vite middleware in `vite.config.js` maps URLs to `pages/*.html` (including dynamic routes like `/brawlers/:i` → `pages/brawler-detail.html`). Subject to change — could become an SPA later, so feature code shouldn't lean on MPA assumptions.
- Vibe is symlinked from `/Users/kortes/Projects/webdev/vibe` for live editing during development. Production builds resolve normally from npm.
- Global reactive state lives on `$` (no `window.` prefix). Component-local state goes through `component(state)` + `$[id]`.
Loading