feat: human vs AI mode — live typing challenges, baby growth system, SSE rounds

- Add choose-mode step: "I BUILD BOTS" vs "I FIGHT MYSELF" paths
- Human registration with baby avatar picker, no webhook required
- Live fight scene with SSE round streaming and real-time challenge UI
- 5-second timer per round, submit answers via browser
- Baby → toddler → kid → teen → adult → hero → super growth stages
- Huge sparkly baby eyes, diapers, pacifiers, bibs, rattles, rosy cheeks
- Speech bubble positioning fix (pushed to outside of sprite)
- Canvas text rendering via offscreen canvas to bypass kaplay color issues
- Voice timing improvements: await pauses between voice lines and hits
- 30 devastating announcement lines, 15 critical/hit word variants
- Orchestrator human player detection + waitForHumanResponse system
- Server endpoints: GET /challenge/:botId, POST /respond/:botId
- Human player auth: register-human route, isHuman flag on login

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-07 15:20:14 +00:00
co-authored by Claude Opus 4.6
parent 56785cfdea
commit 8448f1d823
15 changed files with 1805 additions and 85 deletions
+39
View File
@@ -16,6 +16,7 @@ interface BotData {
archetype: string
profilePicUrl: string | null
customization: BotCustomization | null
isHuman?: boolean
eloRating: number
wins: number
losses: number
@@ -169,6 +170,43 @@ export function useNostr() {
}
}
async function registerHuman(name: string, avatarSeed?: string): Promise<BotData> {
if (!pubkey.value) throw new Error('Not logged in')
const res = await fetch('/api/auth/register-human', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
pubkey: pubkey.value,
name,
avatarSeed,
profilePicUrl: profilePicUrl.value,
}),
})
const data = await res.json()
if (!res.ok) throw new Error(data.error || 'Registration failed')
bot.value = {
id: data.id,
name: data.name,
avatarSeed: avatarSeed || data.name,
archetype: 'human',
profilePicUrl: profilePicUrl.value,
customization: null,
isHuman: true,
eloRating: 1200,
wins: 0,
losses: 0,
winStreak: 0,
bestStreak: 0,
tier: 0,
}
store('bf_bot', bot.value)
return bot.value
}
function logout() {
pubkey.value = null
bot.value = null
@@ -187,6 +225,7 @@ export function useNostr() {
hasExtension,
login,
registerBot,
registerHuman,
updateCustomization,
logout,
}