feat: v2 — queue matchmaking, procedural audio, sprite archetypes, auth

- Add queue-based matchmaking with Elo-proximity and 10s timeout
- Procedural sound engine (SFX, voice announcer, 4-track music)
- Sprite system refactored into 6 archetypes (standard, lobster, sheep, cyborg, blob, tank)
- 42+ fight choreographies with themed/generic/wild card selection
- 4 KO finish styles, super-speed mode, hyperdetail close-ups
- Auth routes, JoinBout page, bot profile with stats
- 7-tier ranking system (Baby through Legend)
- Arena and challenge system expansions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-06 22:13:19 +00:00
co-authored by Claude Opus 4.6
parent 335c148866
commit 47d20fbe66
82 changed files with 14011 additions and 741 deletions
+63
View File
@@ -0,0 +1,63 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue'
import { generateSpriteSheet, getBotColors, FRAME_SIZE, ANIMATIONS } from '../game/sprites'
const props = defineProps<{
seed: string
archetype?: string
size?: number
}>()
const canvasRef = ref<HTMLCanvasElement>()
let img: HTMLImageElement | null = null
let frame = 0
let animHandle: ReturnType<typeof setTimeout> | null = null
function render() {
if (!canvasRef.value || !img?.complete) return
const ctx = canvasRef.value.getContext('2d')!
const displaySize = props.size || 64
canvasRef.value.width = displaySize
canvasRef.value.height = displaySize
ctx.clearRect(0, 0, displaySize, displaySize)
ctx.imageSmoothingEnabled = false
const idleAnim = ANIMATIONS.idle
const f = frame % idleAnim.frames
ctx.drawImage(
img,
f * FRAME_SIZE, idleAnim.row * FRAME_SIZE, FRAME_SIZE, FRAME_SIZE,
0, 0, displaySize, displaySize,
)
frame++
animHandle = setTimeout(() => render(), 180)
}
function loadSprite() {
const colors = getBotColors(props.seed)
const dataUrl = generateSpriteSheet(props.seed, 0, colors.primary, colors.secondary, props.archetype)
img = new Image()
img.onload = () => render()
img.src = dataUrl
}
onMounted(() => loadSprite())
watch(() => [props.seed, props.archetype], () => {
if (animHandle) clearTimeout(animHandle)
frame = 0
loadSprite()
})
onUnmounted(() => {
if (animHandle) clearTimeout(animHandle)
})
</script>
<template>
<canvas
ref="canvasRef"
:style="{ width: `${size || 64}px`, height: `${size || 64}px`, imageRendering: 'pixelated' }"
/>
</template>