fix: page-breaking bugs — duplicate onMounted, SSE race, canvas lifecycle, ghost animation
- ArenaPage: merge duplicate onMounted hooks into single parallel fetch - FightPage: queue SSE events until liveFightData ready, add reconnect with backoff - FightViewer: fix stale canvas ref with container ref, add sceneReady guard - HomePage: replace stopCycling boolean with AbortController for clean unmount Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
84625bc4d2
commit
e31b15ed28
@@ -42,8 +42,10 @@ const props = defineProps<{ fight: FightData; autoplay?: boolean }>()
|
||||
const emit = defineEmits<{ 'replay-done': [] }>()
|
||||
|
||||
const canvasRef = ref<HTMLCanvasElement>()
|
||||
const canvasContainer = ref<HTMLElement>()
|
||||
const logEl = ref<HTMLElement>()
|
||||
let scene: FightSceneController | null = null
|
||||
const sceneReady = ref(false)
|
||||
|
||||
const isReplaying = ref(false)
|
||||
const displayHpA = ref(100)
|
||||
@@ -94,32 +96,39 @@ function mapHp(hp: number, winnerId: string | null, botId: string | undefined):
|
||||
|
||||
onUnmounted(() => {
|
||||
stopAllAudio()
|
||||
sceneReady.value = false
|
||||
if (scene) { scene.destroy(); scene = null }
|
||||
})
|
||||
|
||||
async function initScene() {
|
||||
if (!canvasRef.value || !props.fight.botA || !props.fight.botB) return
|
||||
// Destroy previous scene fully — replace canvas to avoid "KAPLAY already initialized"
|
||||
if (!props.fight.botA || !props.fight.botB) return
|
||||
// Destroy previous scene fully
|
||||
sceneReady.value = false
|
||||
if (scene) { scene.destroy(); scene = null }
|
||||
|
||||
const container = canvasRef.value.parentElement
|
||||
if (container) {
|
||||
// Replace canvas element so Kaplay gets a fresh context
|
||||
const oldCanvas = canvasRef.value
|
||||
const newCanvas = document.createElement('canvas')
|
||||
newCanvas.className = oldCanvas.className
|
||||
newCanvas.width = container.clientWidth
|
||||
newCanvas.height = container.clientHeight
|
||||
const container = canvasContainer.value
|
||||
if (!container) return
|
||||
|
||||
// Replace canvas element so Kaplay gets a fresh context
|
||||
const oldCanvas = canvasRef.value
|
||||
const newCanvas = document.createElement('canvas')
|
||||
newCanvas.className = 'w-full h-full block'
|
||||
newCanvas.width = container.clientWidth
|
||||
newCanvas.height = container.clientHeight
|
||||
if (oldCanvas) {
|
||||
oldCanvas.replaceWith(newCanvas)
|
||||
canvasRef.value = newCanvas
|
||||
} else {
|
||||
container.prepend(newCanvas)
|
||||
}
|
||||
canvasRef.value = newCanvas
|
||||
|
||||
scene = await createFightScene({
|
||||
canvas: canvasRef.value,
|
||||
canvas: newCanvas,
|
||||
botA: { name: props.fight.botA.name, seed: props.fight.botA.avatarSeed || props.fight.botA.name, tier: props.fight.botA.tier, archetype: props.fight.botA.archetype, customization: props.fight.botA.customization as any, wins: props.fight.botA.wins, losses: props.fight.botA.losses },
|
||||
botB: { name: props.fight.botB.name, seed: props.fight.botB.avatarSeed || props.fight.botB.name, tier: props.fight.botB.tier, archetype: props.fight.botB.archetype, customization: props.fight.botB.customization as any, wins: props.fight.botB.wins, losses: props.fight.botB.losses },
|
||||
arena: props.fight.arena,
|
||||
})
|
||||
sceneReady.value = true
|
||||
}
|
||||
|
||||
const challengeLabel = (type: string) => {
|
||||
@@ -262,7 +271,7 @@ async function replay() {
|
||||
const bWon = round.winnerId === props.fight.botB!.id
|
||||
|
||||
try {
|
||||
await scene!.playRound({
|
||||
await scene?.playRound({
|
||||
round: round.roundNumber,
|
||||
challengeType: round.challengeType,
|
||||
winnerId: round.winnerId,
|
||||
@@ -501,7 +510,7 @@ async function replay() {
|
||||
</div>
|
||||
|
||||
<!-- Canvas + floating overlays -->
|
||||
<div class="flex-1 relative min-h-0" :class="{ 'glitch-container': glitching }">
|
||||
<div ref="canvasContainer" class="flex-1 relative min-h-0" :class="{ 'glitch-container': glitching }">
|
||||
<canvas ref="canvasRef" class="w-full h-full block" />
|
||||
|
||||
<!-- Floating announcement -->
|
||||
|
||||
Reference in New Issue
Block a user