fix: mobile — scale sprites to canvas size, fix viewport scroll

- Add scale factor (SF) based on canvas height so bots and referee
  shrink proportionally on small screens (reference: 500px)
- Scale judge chair/ladder dimensions with SF
- Push judge seat lower on small canvases so it stays visible
- Use 100dvh instead of 100vh to account for mobile browser chrome
  (address bar, tab bar) — eliminates scroll under browser UI
- App root uses dvh, main area uses min-h-0 + overflow-y-auto

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-07 22:07:52 +00:00
co-authored by Claude Opus 4.6
parent 486d6f445d
commit 07fa2cf35c
3 changed files with 19 additions and 16 deletions
+2 -2
View File
@@ -4,10 +4,10 @@ import NavBar from './components/NavBar.vue'
</script>
<template>
<div class="min-h-screen bg-surface synthwave-grid flex flex-col relative">
<div class="h-[100dvh] bg-surface synthwave-grid flex flex-col relative">
<div class="fixed inset-0 crt-overlay z-40" />
<NavBar />
<main class="flex-1 relative z-10">
<main class="flex-1 min-h-0 relative z-10 overflow-y-auto">
<RouterView />
</main>
</div>
+16 -13
View File
@@ -296,6 +296,8 @@ export async function createFightScene(config: FightSceneConfig) {
const W = k.width()
const H = k.height()
// Scale factor so sprites shrink on small canvases (reference: 500px tall)
const SF = Math.min(1, H / 500)
const GROUND_Y = H * 0.78
const HOME_A = W * 0.28
const HOME_B = W * 0.72
@@ -1898,32 +1900,33 @@ export async function createFightScene(config: FightSceneConfig) {
// Umpire chair (center-back, behind fighters)
const CHAIR_X = W / 2
const CHAIR_SEAT_Y = GROUND_Y * 0.38
k.add([k.rect(4, GROUND_Y - CHAIR_SEAT_Y + 15), k.pos(CHAIR_X - 22, CHAIR_SEAT_Y - 8), k.color(safeColor(k,'#554433')), k.opacity(0.7), k.z(3)])
k.add([k.rect(4, GROUND_Y - CHAIR_SEAT_Y + 15), k.pos(CHAIR_X + 18, CHAIR_SEAT_Y - 8), k.color(safeColor(k,'#554433')), k.opacity(0.7), k.z(3)])
const CHAIR_SEAT_Y = GROUND_Y * (0.38 + (1 - SF) * 0.2)
const cs = SF // chair scale
k.add([k.rect(4 * cs, GROUND_Y - CHAIR_SEAT_Y + 15 * cs), k.pos(CHAIR_X - 22 * cs, CHAIR_SEAT_Y - 8 * cs), k.color(safeColor(k,'#554433')), k.opacity(0.7), k.z(3)])
k.add([k.rect(4 * cs, GROUND_Y - CHAIR_SEAT_Y + 15 * cs), k.pos(CHAIR_X + 18 * cs, CHAIR_SEAT_Y - 8 * cs), k.color(safeColor(k,'#554433')), k.opacity(0.7), k.z(3)])
for (let i = 0; i < 6; i++) {
const rungY = CHAIR_SEAT_Y + 15 + i * ((GROUND_Y - CHAIR_SEAT_Y - 15) / 6)
k.add([k.rect(44, 3), k.pos(CHAIR_X - 22, rungY), k.color(safeColor(k,'#443322')), k.opacity(0.6), k.z(3)])
const rungY = CHAIR_SEAT_Y + 15 * cs + i * ((GROUND_Y - CHAIR_SEAT_Y - 15 * cs) / 6)
k.add([k.rect(44 * cs, 3), k.pos(CHAIR_X - 22 * cs, rungY), k.color(safeColor(k,'#443322')), k.opacity(0.6), k.z(3)])
}
k.add([k.rect(54, 5), k.pos(CHAIR_X - 27, CHAIR_SEAT_Y - 2), k.color(safeColor(k,'#665544')), k.opacity(0.8), k.z(3)])
k.add([k.rect(54, 1), k.pos(CHAIR_X - 27, CHAIR_SEAT_Y - 2), k.color(safeColor(k,theme.accent)), k.opacity(0.3), k.z(3)])
k.add([k.rect(48, 4), k.pos(CHAIR_X - 24, CHAIR_SEAT_Y - 10), k.color(safeColor(k,'#665544')), k.opacity(0.8), k.z(3)])
k.add([k.rect(3, 12), k.pos(CHAIR_X - 27, CHAIR_SEAT_Y - 10), k.color(safeColor(k,'#554433')), k.opacity(0.7), k.z(3)])
k.add([k.rect(3, 12), k.pos(CHAIR_X + 24, CHAIR_SEAT_Y - 10), k.color(safeColor(k,'#554433')), k.opacity(0.7), k.z(3)])
k.add([k.rect(54 * cs, 5), k.pos(CHAIR_X - 27 * cs, CHAIR_SEAT_Y - 2), k.color(safeColor(k,'#665544')), k.opacity(0.8), k.z(3)])
k.add([k.rect(54 * cs, 1), k.pos(CHAIR_X - 27 * cs, CHAIR_SEAT_Y - 2), k.color(safeColor(k,theme.accent)), k.opacity(0.3), k.z(3)])
k.add([k.rect(48 * cs, 4), k.pos(CHAIR_X - 24 * cs, CHAIR_SEAT_Y - 10 * cs), k.color(safeColor(k,'#665544')), k.opacity(0.8), k.z(3)])
k.add([k.rect(3, 12 * cs), k.pos(CHAIR_X - 27 * cs, CHAIR_SEAT_Y - 10 * cs), k.color(safeColor(k,'#554433')), k.opacity(0.7), k.z(3)])
k.add([k.rect(3, 12 * cs), k.pos(CHAIR_X + 24 * cs, CHAIR_SEAT_Y - 10 * cs), k.color(safeColor(k,'#554433')), k.opacity(0.7), k.z(3)])
k.add([
k.sprite('judge', { anim: 'idle' }),
k.pos(CHAIR_X, CHAIR_SEAT_Y),
k.anchor('bot'),
k.scale(1.3),
k.scale(1.3 * SF),
k.z(4),
k.opacity(0.9),
'judge',
])
const scaleA = 1.8 + botA.tier * 0.4
const scaleA = (1.8 + botA.tier * 0.4) * SF
k.add([k.sprite('botA', { anim: 'idle' }), k.pos(-100, GROUND_Y - 6), k.anchor('bot'), k.scale(scaleA), k.z(10), k.opacity(0), 'fighterA'])
const scaleB = 1.8 + botB.tier * 0.4
const scaleB = (1.8 + botB.tier * 0.4) * SF
k.add([k.sprite('botB', { anim: 'idle' }), k.pos(W + 100, GROUND_Y - 6), k.anchor('bot'), k.scale(-scaleB, scaleB), k.z(10), k.opacity(0), 'fighterB'])
config.onReady?.()
+1 -1
View File
@@ -649,7 +649,7 @@ function stopAutoBattle() {
</script>
<template>
<div class="h-[calc(100vh-4rem)] flex flex-col px-2 sm:px-3 py-2 sm:py-3 overflow-hidden">
<div class="h-[calc(100dvh-4rem)] flex flex-col px-2 sm:px-3 py-2 sm:py-3 overflow-hidden">
<div v-if="isLoading" class="flex-1 flex items-center justify-center">
<p class="font-display text-text-muted animate-pulse tracking-wider">LOADING FIGHT...</p>
</div>