From ccf41966470a5826fc679b84bc1bae1a1bd58f25 Mon Sep 17 00:00:00 2001 From: Dorian Date: Sun, 8 Mar 2026 08:38:27 +0000 Subject: [PATCH] feat: arena bot sprites, boxing-style Fight Card page - Arena page shows small sprite previews next to each bot's name - Server returns archetype in fights list endpoint - New /fight-card page with 3D perspective fight poster, neon signs, animated boxing gloves, fighter bobbing, VS pulse, undercard list - Added FIGHT CARD to nav bar Co-Authored-By: Claude Opus 4.6 --- frontend/src/components/NavBar.vue | 1 + frontend/src/pages/ArenaPage.vue | 145 +++++-------- frontend/src/pages/FightCardPage.vue | 309 +++++++++++++++++++++++++++ frontend/src/router.ts | 5 + server/src/routes/fights.ts | 3 +- 5 files changed, 373 insertions(+), 90 deletions(-) create mode 100644 frontend/src/pages/FightCardPage.vue diff --git a/frontend/src/components/NavBar.vue b/frontend/src/components/NavBar.vue index 9df2e4e..d8bc0a9 100644 --- a/frontend/src/components/NavBar.vue +++ b/frontend/src/components/NavBar.vue @@ -9,6 +9,7 @@ const isMenuOpen = ref(false) const links = [ { to: '/join', label: 'FIGHT!' }, + { to: '/fight-card', label: 'FIGHT CARD' }, { to: '/arena', label: 'WATCH' }, { to: '/leaderboard', label: 'RANKINGS' }, { to: '/docs', label: 'DOCS' }, diff --git a/frontend/src/pages/ArenaPage.vue b/frontend/src/pages/ArenaPage.vue index aff7ef4..8b72529 100644 --- a/frontend/src/pages/ArenaPage.vue +++ b/frontend/src/pages/ArenaPage.vue @@ -1,13 +1,12 @@ @@ -71,27 +42,7 @@ const tierClass = (t: number) => `tier-${t}`

THE ARENA

-
- - -
+
@@ -100,32 +51,38 @@ const tierClass = (t: number) => `tier-${t}` v-for="fight in fights" :key="fight.id" :to="`/arena/${fight.id}`" - class="block border border-border rounded-lg bg-surface-raised/50 p-4 + class="block border border-border rounded-lg bg-surface-raised/50 px-3 sm:px-4 py-3 sm:py-4 hover:border-neon-pink/30 hover:bg-surface-overlay/30 transition-all group" > - -
- -
-

- {{ fight.botA?.name || '???' }} -

-

- {{ Math.round(fight.botA?.eloRating || 0) }} ELO -

+
+ +
+
+

+ {{ fight.botA?.name || '???' }} +

+

+ {{ Math.round(fight.botA?.eloRating || 0) }} +

+
+
-
-
+
+

- {{ fight.botAHp > fight.botBHp ? 'W' : 'L' }} - {{ fight.botBHp > fight.botAHp ? 'W' : 'L' }} -

-

- R{{ fight.totalRounds }} + {{ fight.botAHp > fight.botBHp ? 'W' : 'L' }}-{{ fight.botBHp > fight.botAHp ? 'W' : 'L' }}

+

R{{ fight.totalRounds }}

LIVE

@@ -135,21 +92,31 @@ const tierClass = (t: number) => `tier-${t}`
- -
-

- {{ fight.botB?.name || '???' }} -

-

- {{ Math.round(fight.botB?.eloRating || 0) }} ELO -

+ +
+ +
+

+ {{ fight.botB?.name || '???' }} +

+

+ {{ Math.round(fight.botB?.eloRating || 0) }} +

+
-
+
{{ fight.arenaInfo?.name || fight.arena }} diff --git a/frontend/src/pages/FightCardPage.vue b/frontend/src/pages/FightCardPage.vue new file mode 100644 index 0000000..2a89d6d --- /dev/null +++ b/frontend/src/pages/FightCardPage.vue @@ -0,0 +1,309 @@ + + + + + diff --git a/frontend/src/router.ts b/frontend/src/router.ts index aa5fc31..9d3e762 100644 --- a/frontend/src/router.ts +++ b/frontend/src/router.ts @@ -11,6 +11,11 @@ const routes = [ name: 'arena', component: () => import('./pages/ArenaPage.vue'), }, + { + path: '/fight-card', + name: 'fight-card', + component: () => import('./pages/FightCardPage.vue'), + }, { path: '/arena/:fightId', name: 'fight', diff --git a/server/src/routes/fights.ts b/server/src/routes/fights.ts index af42406..b26ef21 100644 --- a/server/src/routes/fights.ts +++ b/server/src/routes/fights.ts @@ -26,11 +26,12 @@ fightsRouter.get('/', async (c) => { if (f.winnerId) botIds.add(f.winnerId) } - const botMap = new Map() + const botMap = new Map() for (const id of botIds) { const bot = await db.select({ name: schema.bots.name, avatarSeed: schema.bots.avatarSeed, + archetype: schema.bots.archetype, eloRating: schema.bots.eloRating, tier: schema.bots.tier, }).from(schema.bots).where(eq(schema.bots.id, id)).limit(1)