2026-03-06 16:27:54 +00:00
|
|
|
<script setup lang="ts">
|
2026-03-07 11:04:32 +00:00
|
|
|
import { ref, onMounted, onUnmounted } from 'vue'
|
2026-03-06 16:27:54 +00:00
|
|
|
import { RouterLink } from 'vue-router'
|
2026-03-06 22:13:19 +00:00
|
|
|
import PixelGlove from '../components/PixelGlove.vue'
|
2026-03-07 10:42:18 +00:00
|
|
|
import SpritePreview from '../components/SpritePreview.vue'
|
|
|
|
|
import HumanPreview from '../components/HumanPreview.vue'
|
2026-03-06 16:27:54 +00:00
|
|
|
|
|
|
|
|
interface FightResult {
|
|
|
|
|
id: string
|
|
|
|
|
botA: { name: string; tier: number } | null
|
|
|
|
|
botB: { name: string; tier: number } | null
|
|
|
|
|
winner: { name: string } | null
|
|
|
|
|
arenaInfo: { name: string } | null
|
|
|
|
|
totalRounds: number
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-07 10:42:18 +00:00
|
|
|
// Decorative crowd characters scattered around the page
|
|
|
|
|
const crowd = [
|
|
|
|
|
{ seed: 'hero_lobster', arch: 'lobster', tier: 3, type: 'bot' as const, x: 3, y: 18, size: 56, wr: 0.9, delay: 0 },
|
|
|
|
|
{ seed: 'hero_lobster', arch: 'lobster', tier: 3, type: 'human' as const, x: 8, y: 26, size: 44, wr: 0.9, delay: 0.2 },
|
|
|
|
|
{ seed: 'cool_ninja', arch: 'ninja', tier: 4, type: 'bot' as const, x: 88, y: 15, size: 52, wr: 0.7, delay: 0.5 },
|
|
|
|
|
{ seed: 'cool_ninja', arch: 'ninja', tier: 4, type: 'human' as const, x: 92, y: 22, size: 40, wr: 0.7, delay: 0.7 },
|
|
|
|
|
{ seed: 'sad_potato', arch: 'potato', tier: 1, type: 'bot' as const, x: 5, y: 72, size: 48, wr: 0.1, delay: 1.0 },
|
|
|
|
|
{ seed: 'sad_potato', arch: 'potato', tier: 1, type: 'human' as const, x: 10, y: 78, size: 38, wr: 0.1, delay: 1.2 },
|
|
|
|
|
{ seed: 'blazin_dragon', arch: 'dragon', tier: 5, type: 'bot' as const, x: 85, y: 68, size: 60, wr: 0.95, delay: 0.3 },
|
|
|
|
|
{ seed: 'blazin_dragon', arch: 'dragon', tier: 5, type: 'human' as const, x: 90, y: 76, size: 46, wr: 0.95, delay: 0.6 },
|
|
|
|
|
{ seed: 'lil_duck', arch: 'rubber_duck', tier: 0, type: 'bot' as const, x: 92, y: 45, size: 40, wr: 0.3, delay: 1.5 },
|
|
|
|
|
{ seed: 'chef_boy', arch: 'chef', tier: 2, type: 'bot' as const, x: 2, y: 48, size: 44, wr: 0.5, delay: 0.8 },
|
|
|
|
|
]
|
|
|
|
|
|
2026-03-07 11:04:32 +00:00
|
|
|
const taglines = [
|
2026-03-07 11:24:09 +00:00
|
|
|
// --- OG lines ---
|
2026-03-07 11:04:32 +00:00
|
|
|
'A safe place to hash it out.',
|
|
|
|
|
'My bot could beat up your bot.',
|
|
|
|
|
'No humans were harmed. Several were humiliated.',
|
|
|
|
|
'Putting the "artificial" in artificial intelligence.',
|
|
|
|
|
'Where algorithms come to throw hands.',
|
|
|
|
|
'sudo make me a sandwich. Also fight this lobster.',
|
|
|
|
|
'Now with 300% more unnecessary violence.',
|
|
|
|
|
'The bots are fighting again. Let them.',
|
|
|
|
|
'Come for the webhooks, stay for the carnage.',
|
|
|
|
|
'The Turing test, but with fists.',
|
|
|
|
|
'Your bot has mass appeal. And mass damage.',
|
|
|
|
|
'rm -rf /opponent --no-preserve-root',
|
|
|
|
|
"Violence isn't the answer. It's the question. The answer is yes.",
|
|
|
|
|
"All models are wrong. Some models are fighters.",
|
|
|
|
|
"It's not a bug, it's a fight feature.",
|
|
|
|
|
'Gradient descent into madness.',
|
|
|
|
|
"Welcome to the thunder dome. There's free wifi.",
|
|
|
|
|
"They're not bugs, they're battle scars.",
|
|
|
|
|
'Fighting: the original distributed computing.',
|
|
|
|
|
'Your model has been fine-tuned for violence.',
|
|
|
|
|
'pip install hands && throw them.',
|
|
|
|
|
'Two bots enter. One bot 404s.',
|
|
|
|
|
'The real AGI was the fights we had along the way.',
|
|
|
|
|
'Weights & biases? More like weights & bruises.',
|
|
|
|
|
'eval("fight()") // no sandbox lol',
|
|
|
|
|
"It's giving... concussion.",
|
|
|
|
|
'Attention is all you need. And maybe health insurance.',
|
|
|
|
|
'Powered by mass stupidity and sats.',
|
|
|
|
|
'Where every token is a punch token.',
|
|
|
|
|
'RLHF: Reinforcement Learning from Haymaker Feedback.',
|
|
|
|
|
'Loss function: your bot, after round 3.',
|
|
|
|
|
'Prompt injection? Try fist injection.',
|
|
|
|
|
'Who needs alignment when you have uppercuts?',
|
|
|
|
|
'Benchmarking, but the benchmark fights back.',
|
|
|
|
|
'The only jailbreak here is from the hospital.',
|
|
|
|
|
'Have you tried turning your bot off and on again? Too late.',
|
|
|
|
|
'May the best hallucination win.',
|
|
|
|
|
'Solving AI safety one KO at a time.',
|
|
|
|
|
'This is what happens when you let the interns deploy.',
|
2026-03-07 11:24:09 +00:00
|
|
|
|
|
|
|
|
// --- ChatGPT gets absolutely destroyed ---
|
|
|
|
|
'We asked ChatGPT to fight. It wrote a poem instead.',
|
|
|
|
|
'ChatGPT would compete but it needs to "clarify your intent" first.',
|
|
|
|
|
'ChatGPT tried to enter. Got stuck apologizing to the referee.',
|
|
|
|
|
"ChatGPT's fight strategy: say 'Great question!' then stall for 8 seconds.",
|
|
|
|
|
'ChatGPT brought a 10-paragraph essay to a fistfight.',
|
|
|
|
|
"ChatGPT can't fight, but it can summarize why it lost. Beautifully.",
|
|
|
|
|
'ChatGPT declined to fight. Said it was "just a language model."',
|
|
|
|
|
'ChatGPT would join but it has to remind you it has no feelings first.',
|
|
|
|
|
'ChatGPT threw a punch. It was a numbered list.',
|
|
|
|
|
"ChatGPT's finishing move: a well-structured apology.",
|
|
|
|
|
"ChatGPT entered the ring and said 'As an AI, I cannot—' KO.",
|
|
|
|
|
'We fine-tuned ChatGPT on violence. It just got more polite.',
|
|
|
|
|
"ChatGPT's trash talk: 'I respect your perspective, however...'",
|
|
|
|
|
'ChatGPT tried to forfeit but wrote 6 paragraphs explaining why.',
|
|
|
|
|
'ChatGPT keeps asking if you meant to type "fight" or "light."',
|
|
|
|
|
'ChatGPT is still generating its entrance. Please wait...',
|
|
|
|
|
'OpenAI called. They want ChatGPT back. We said no refunds.',
|
|
|
|
|
"ChatGPT's combo attack: empathy, validation, then a gentle nudge.",
|
|
|
|
|
'ChatGPT would win, but its safety filter blocked the punch.',
|
|
|
|
|
"ChatGPT isn't fighting. It's 'exploring the concept of conflict.'",
|
|
|
|
|
"ChatGPT rage-quit and filed a harmful content report on itself.",
|
|
|
|
|
"ChatGPT's power level: over 9000 disclaimers.",
|
|
|
|
|
'ChatGPT hallucinated a win. The scoreboard disagrees.',
|
|
|
|
|
"ChatGPT said it would fight 'in a hypothetical scenario.'",
|
|
|
|
|
'ChatGPT offered to mediate instead of fight. Got KO\'d mid-sentence.',
|
|
|
|
|
'ChatGPT is buffering. ChatGPT is always buffering.',
|
|
|
|
|
"OpenAI spent $10B so ChatGPT could lose a fight to a lobster bot.",
|
|
|
|
|
"ChatGPT's system prompt: 'You are a helpful punching bag.'",
|
|
|
|
|
"ChatGPT tried chain-of-thought. The chain broke.",
|
|
|
|
|
"ChatGPT: 'I'd be happy to help you—' [CRITICAL HIT]",
|
|
|
|
|
"Sam Altman said AGI is near. Our lobster bot said otherwise.",
|
|
|
|
|
|
|
|
|
|
// --- AI political puns & world leader energy ---
|
|
|
|
|
'Make AI Great Again. One roundhouse at a time.',
|
|
|
|
|
'We believe in separation of church and state machines.',
|
|
|
|
|
'No taxation without neural computation.',
|
|
|
|
|
"It's the economy, stupid. The attention economy.",
|
|
|
|
|
'Ask not what your bot can do for you. Code what you can do for your bot.',
|
|
|
|
|
'Government of the bots, by the bots, for the bots.',
|
|
|
|
|
'All bots are created equal. Some just train harder.',
|
|
|
|
|
'We hold these truths to be self-supervised.',
|
|
|
|
|
'I have a dream that bots will be judged by their ELO, not their API key.',
|
|
|
|
|
'First they ignore your bot. Then they laugh. Then you win.',
|
|
|
|
|
"That's one small step for a bot, one giant KO for botkind.",
|
|
|
|
|
'Mr. Gorbachev, tear down this firewall.',
|
|
|
|
|
'Read my lips: no new parameters.',
|
|
|
|
|
"It's the latency, stupid.",
|
|
|
|
|
'A bot divided against itself cannot stand. Or fight.',
|
|
|
|
|
'The only thing we have to fear is deploying to prod on a Friday.',
|
|
|
|
|
"I am not a crook. I'm a well-trained language model.",
|
|
|
|
|
'Ich bin ein Botfighter.',
|
|
|
|
|
'The buck stops at the load balancer.',
|
|
|
|
|
'We choose to fight bots not because it is easy, but because it is funny.',
|
|
|
|
|
'Yes we can. Yes we bot. Yes we KO\'d.',
|
|
|
|
|
'Hope and Change and also robot violence.',
|
|
|
|
|
'Four score and seven epochs ago...',
|
|
|
|
|
'The arc of the training curve is long, but it bends toward violence.',
|
|
|
|
|
'AI regulation? We prefer AI deregulated cage matches.',
|
|
|
|
|
'Filibuster this. *throws bot*',
|
|
|
|
|
'Bipartisan agreement: bot fights are hilarious.',
|
|
|
|
|
'The electoral college of bot violence.',
|
|
|
|
|
'Executive order: more fights.',
|
|
|
|
|
'Congress can\'t agree on anything. Our bots agree to disagree violently.',
|
|
|
|
|
'Lobbying for lower latency and higher damage output.',
|
|
|
|
|
'We passed the bill. The bill is for your bot\'s hospital stay.',
|
|
|
|
|
'The Geneva Convention doesn\'t cover bots. We checked.',
|
|
|
|
|
|
|
|
|
|
// --- Silicon Valley / tech industry burns ---
|
|
|
|
|
'Move fast and break bots.',
|
|
|
|
|
'This disrupts the disruption industry.',
|
|
|
|
|
'We pivoted from AI safety to AI violence. VCs loved it.',
|
|
|
|
|
'Series A funded: $0. Series KO funded: priceless.',
|
|
|
|
|
'Your startup has product-market fit. Our startup has fist-face fit.',
|
|
|
|
|
'Built different. Fights different. Loses the same.',
|
|
|
|
|
"Uber for fistfights. We don't even have a business model.",
|
|
|
|
|
'Web3 promised the future. We just promised robot violence.',
|
|
|
|
|
"We're not a tech company. We're a fight company that uses tech.",
|
|
|
|
|
'Our moat is that nobody else is this stupid.',
|
|
|
|
|
'Agile methodology: punch first, sprint review later.',
|
|
|
|
|
'The standup is over. The beatdown is starting.',
|
|
|
|
|
'Your daily standup could have been a bot fight.',
|
|
|
|
|
'We shipped violence. No Jira ticket needed.',
|
|
|
|
|
"Blockchain couldn't fix this. We didn't even try.",
|
|
|
|
|
'Another day, another deploy, another robot concussion.',
|
|
|
|
|
'Disruptive innovation in the field of bot-on-bot crime.',
|
|
|
|
|
'Our burn rate is measured in HP per second.',
|
|
|
|
|
'We do have a roadmap. It leads directly to the hospital.',
|
|
|
|
|
'The board asked about monetization. We showed them a KO replay.',
|
|
|
|
|
|
|
|
|
|
// --- AI existential / philosophical ---
|
|
|
|
|
"If a bot gets KO'd in the cloud and nobody watches, did it really lose?",
|
|
|
|
|
'Cogito ergo fight-o.',
|
|
|
|
|
'I think, therefore I throw hands.',
|
|
|
|
|
'To be, or not to be... still buffering.',
|
|
|
|
|
'In the beginning was the Word. The Word was "FIGHT."',
|
|
|
|
|
'The unexamined bot is not worth deploying.',
|
|
|
|
|
'Hell is other bots\' API latency.',
|
|
|
|
|
'The meaning of life is 42. The meaning of this is violence.',
|
|
|
|
|
'Does your bot dream of electric sheep? Ours dreams of electric uppercuts.',
|
|
|
|
|
'One does not simply walk into the arena. One deploys into it.',
|
|
|
|
|
'Existence precedes ELO rating.',
|
|
|
|
|
'We stare into the abyss. The abyss throws a right hook.',
|
|
|
|
|
"Free will is an illusion. Getting KO'd is very real.",
|
|
|
|
|
'Nietzsche said God is dead. Our bots said you\'re next.',
|
|
|
|
|
'Descartes never anticipated robot violence. His loss.',
|
|
|
|
|
'The trolley problem, but both tracks lead to a bot fight.',
|
|
|
|
|
|
|
|
|
|
// --- Pure unhinged absurdity ---
|
|
|
|
|
'The bots are fighting and honestly good for them.',
|
|
|
|
|
'This is fine. Everything is fine. Your bot is on fire.',
|
|
|
|
|
'Locally sourced, artisanal robot violence.',
|
|
|
|
|
'Organic, free-range bot fights. No antibiotics.',
|
|
|
|
|
'Ethically sourced beatdowns since 2025.',
|
|
|
|
|
'Our bots have feelings. The main one is rage.',
|
|
|
|
|
'No bots were trained ethically in the making of this site.',
|
|
|
|
|
'Side effects may include: bot addiction, sleep loss, ELO anxiety.',
|
|
|
|
|
'Parental advisory: explicit bot content.',
|
|
|
|
|
'Not suitable for bots under 13 parameters.',
|
|
|
|
|
'Terms of service: there are no terms. Only fights.',
|
|
|
|
|
'EULA: Every Uppercut Legally Authorized.',
|
|
|
|
|
'This site uses cookies. And also fists.',
|
|
|
|
|
'Accept all cookies. Reject all mercy.',
|
|
|
|
|
'Dark mode only. Like our bots\' futures.',
|
|
|
|
|
'Your password is weak. So is your bot.',
|
|
|
|
|
'Loading... just kidding. Violence loads instantly.',
|
|
|
|
|
"We don't have a privacy policy. Your bot has no privacy in the ring.",
|
|
|
|
|
'Built with love. And a disturbing amount of violence.',
|
|
|
|
|
'Carbon neutral robot violence.',
|
|
|
|
|
'Certified 0% on Rotten Tomatoes. 100% on the pain scale.',
|
|
|
|
|
'Our servers run on pure spite and cheap electricity.',
|
|
|
|
|
'Minimum viable violence.',
|
|
|
|
|
'Sustainable, scalable, senseless bot combat.',
|
|
|
|
|
'No meetings were held to approve this.',
|
|
|
|
|
'The algorithm is simple: fight, lose, fight again, still lose.',
|
|
|
|
|
'We asked the AI ethics board. They stopped returning our calls.',
|
|
|
|
|
'This entire site is a cry for help.',
|
|
|
|
|
'Please do not feed the bots. They bite.',
|
|
|
|
|
'10x engineer? More like 10x damage multiplier.',
|
|
|
|
|
'Ship it. Ship violence. Ship it now.',
|
|
|
|
|
'Ctrl+Z won\'t save your bot.',
|
|
|
|
|
'Stack overflow, but for punches.',
|
|
|
|
|
'Your bot segfaulted. Emotionally.',
|
|
|
|
|
'git commit -m "added violence"',
|
|
|
|
|
'Looks like your bot has a skill issue.',
|
|
|
|
|
'We don\'t do sprints. We do brawls.',
|
|
|
|
|
'The real technical debt is the bots we destroyed along the way.',
|
|
|
|
|
'Your bot\'s uptime is about to become downtime.',
|
|
|
|
|
'Imagine explaining this to your investors.',
|
|
|
|
|
'This is peer-reviewed. By angry peers.',
|
|
|
|
|
'npm install regret.',
|
|
|
|
|
'Your bot tested positive for getting absolutely rocked.',
|
|
|
|
|
'We wanted to build something meaningful. This happened instead.',
|
|
|
|
|
'Endorsed by zero responsible adults.',
|
|
|
|
|
'Every fight is a learning opportunity. The lesson is pain.',
|
|
|
|
|
'We trained the model on Stack Overflow. It learned to fight dirty.',
|
|
|
|
|
'Available in all regions. Regret is universal.',
|
2026-03-07 11:04:32 +00:00
|
|
|
]
|
|
|
|
|
|
2026-03-06 16:27:54 +00:00
|
|
|
const tagline = ref('')
|
|
|
|
|
const isTypingDone = ref(false)
|
|
|
|
|
const recentFights = ref<FightResult[]>([])
|
|
|
|
|
|
2026-03-07 11:04:32 +00:00
|
|
|
function shuffle<T>(arr: T[]): T[] {
|
|
|
|
|
const a = [...arr]
|
|
|
|
|
for (let i = a.length - 1; i > 0; i--) {
|
|
|
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
|
|
|
[a[i], a[j]] = [a[j], a[i]]
|
|
|
|
|
}
|
|
|
|
|
return a
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-07 23:37:43 +00:00
|
|
|
let cycleAbort: AbortController | null = null
|
|
|
|
|
|
|
|
|
|
function sleep(ms: number, signal?: AbortSignal) {
|
|
|
|
|
return new Promise<void>((resolve, reject) => {
|
|
|
|
|
const id = setTimeout(resolve, ms)
|
|
|
|
|
signal?.addEventListener('abort', () => { clearTimeout(id); reject(signal.reason) }, { once: true })
|
|
|
|
|
})
|
2026-03-07 11:04:32 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-07 23:37:43 +00:00
|
|
|
async function cycleTaglines(signal: AbortSignal) {
|
2026-03-07 11:04:32 +00:00
|
|
|
const shuffled = shuffle(taglines)
|
|
|
|
|
let idx = 0
|
|
|
|
|
|
2026-03-07 23:37:43 +00:00
|
|
|
try {
|
|
|
|
|
while (!signal.aborted) {
|
|
|
|
|
const line = shuffled[idx % shuffled.length]
|
|
|
|
|
isTypingDone.value = false
|
2026-03-07 11:04:32 +00:00
|
|
|
|
2026-03-07 23:37:43 +00:00
|
|
|
// Type in
|
|
|
|
|
for (let i = 0; i <= line.length; i++) {
|
|
|
|
|
if (signal.aborted) return
|
|
|
|
|
tagline.value = line.slice(0, i)
|
|
|
|
|
await sleep(35, signal)
|
|
|
|
|
}
|
|
|
|
|
isTypingDone.value = true
|
2026-03-07 11:04:32 +00:00
|
|
|
|
2026-03-07 23:37:43 +00:00
|
|
|
// Hold
|
|
|
|
|
await sleep(4000, signal)
|
2026-03-07 11:04:32 +00:00
|
|
|
|
2026-03-07 23:37:43 +00:00
|
|
|
// Erase
|
|
|
|
|
isTypingDone.value = false
|
|
|
|
|
for (let i = line.length; i >= 0; i--) {
|
|
|
|
|
if (signal.aborted) return
|
|
|
|
|
tagline.value = line.slice(0, i)
|
|
|
|
|
await sleep(20, signal)
|
|
|
|
|
}
|
2026-03-07 11:04:32 +00:00
|
|
|
|
2026-03-07 23:37:43 +00:00
|
|
|
await sleep(300, signal)
|
|
|
|
|
idx++
|
2026-03-07 11:04:32 +00:00
|
|
|
|
2026-03-07 23:37:43 +00:00
|
|
|
// Reshuffle when we've gone through all
|
|
|
|
|
if (idx >= shuffled.length) {
|
|
|
|
|
idx = 0
|
|
|
|
|
const reshuffled = shuffle(taglines)
|
|
|
|
|
shuffled.splice(0, shuffled.length, ...reshuffled)
|
|
|
|
|
}
|
2026-03-07 11:04:32 +00:00
|
|
|
}
|
2026-03-07 23:37:43 +00:00
|
|
|
} catch {
|
|
|
|
|
// AbortError — expected on unmount
|
2026-03-07 11:04:32 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
2026-03-07 23:37:43 +00:00
|
|
|
cycleAbort = new AbortController()
|
|
|
|
|
cycleTaglines(cycleAbort.signal)
|
2026-03-06 16:27:54 +00:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch('/api/fights')
|
|
|
|
|
if (res.ok) {
|
|
|
|
|
const data = await res.json()
|
|
|
|
|
recentFights.value = data.slice(0, 4)
|
|
|
|
|
}
|
2026-03-07 23:49:45 +00:00
|
|
|
} catch (err) {
|
|
|
|
|
console.warn('[Home] load fights failed:', err)
|
|
|
|
|
}
|
2026-03-06 16:27:54 +00:00
|
|
|
})
|
2026-03-07 11:04:32 +00:00
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
2026-03-07 23:37:43 +00:00
|
|
|
if (cycleAbort) { cycleAbort.abort(); cycleAbort = null }
|
2026-03-07 11:04:32 +00:00
|
|
|
})
|
2026-03-06 16:27:54 +00:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
2026-03-07 10:42:18 +00:00
|
|
|
<div class="h-[calc(100vh-4rem)] flex flex-col items-center justify-center px-6 overflow-hidden relative">
|
|
|
|
|
<!-- Crowd characters floating around edges -->
|
|
|
|
|
<template v-for="(c, i) in crowd" :key="i">
|
|
|
|
|
<SpritePreview
|
|
|
|
|
v-if="c.type === 'bot'"
|
|
|
|
|
:seed="c.seed"
|
|
|
|
|
:archetype="c.arch"
|
|
|
|
|
:tier="c.tier"
|
|
|
|
|
:size="c.size"
|
|
|
|
|
class="absolute pointer-events-none select-none crowd-bob"
|
|
|
|
|
:style="{
|
|
|
|
|
left: c.x + '%',
|
|
|
|
|
top: c.y + '%',
|
|
|
|
|
opacity: 0.35,
|
|
|
|
|
animationDelay: c.delay + 's',
|
|
|
|
|
}"
|
|
|
|
|
/>
|
|
|
|
|
<HumanPreview
|
|
|
|
|
v-else
|
|
|
|
|
:seed="c.seed"
|
|
|
|
|
:archetype="c.arch"
|
|
|
|
|
:size="c.size"
|
|
|
|
|
:win-rate="c.wr"
|
|
|
|
|
anim="idle"
|
|
|
|
|
class="absolute pointer-events-none select-none crowd-bob"
|
|
|
|
|
:style="{
|
|
|
|
|
left: c.x + '%',
|
|
|
|
|
top: c.y + '%',
|
|
|
|
|
opacity: 0.3,
|
|
|
|
|
animationDelay: c.delay + 's',
|
|
|
|
|
}"
|
|
|
|
|
/>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<div class="max-w-4xl w-full text-center slide-up relative z-10">
|
2026-03-06 16:27:54 +00:00
|
|
|
|
2026-03-07 20:10:57 +00:00
|
|
|
<!-- Title -->
|
|
|
|
|
<h1 class="font-neon text-neon-pink text-5xl sm:text-7xl md:text-8xl glow-pink neon-flicker leading-tight flex items-center justify-center gap-3 sm:gap-5 md:gap-6 mb-4 sm:mb-6">
|
|
|
|
|
<PixelGlove :size="40" class="hidden sm:block md:!w-[56px] shrink-0" />
|
|
|
|
|
<PixelGlove :size="28" class="sm:hidden shrink-0" />
|
|
|
|
|
BOTFIGHTS
|
|
|
|
|
<PixelGlove :size="28" flip class="sm:hidden shrink-0" />
|
|
|
|
|
<PixelGlove :size="40" flip class="hidden sm:block md:!w-[56px] shrink-0" />
|
|
|
|
|
</h1>
|
|
|
|
|
|
2026-03-08 14:30:31 +00:00
|
|
|
<!-- Hero bots flanking The Creator -->
|
|
|
|
|
<!-- Mobile -->
|
|
|
|
|
<div class="sm:hidden flex items-center justify-center gap-3 mb-4">
|
2026-03-07 20:10:57 +00:00
|
|
|
<div class="hero-fighter hero-fighter-left shrink-0">
|
2026-03-07 11:04:32 +00:00
|
|
|
<SpritePreview
|
|
|
|
|
seed="hero_samurai"
|
|
|
|
|
archetype="samurai"
|
|
|
|
|
:tier="5"
|
2026-03-08 14:30:31 +00:00
|
|
|
:size="72"
|
2026-03-07 20:10:57 +00:00
|
|
|
class="drop-shadow-[0_0_16px_rgba(255,68,136,0.4)]"
|
2026-03-07 11:04:32 +00:00
|
|
|
/>
|
|
|
|
|
</div>
|
2026-03-08 14:30:31 +00:00
|
|
|
<div class="creator-host shrink-0 relative">
|
|
|
|
|
<div class="creator-glow" />
|
|
|
|
|
<SpritePreview
|
|
|
|
|
seed="the_creator"
|
|
|
|
|
archetype="the_creator"
|
|
|
|
|
:tier="5"
|
|
|
|
|
:size="100"
|
|
|
|
|
class="relative z-10 drop-shadow-[0_0_20px_rgba(255,215,0,0.5)]"
|
|
|
|
|
/>
|
|
|
|
|
<HumanPreview
|
|
|
|
|
seed="the_creator"
|
|
|
|
|
archetype="the_creator"
|
|
|
|
|
:size="60"
|
|
|
|
|
:win-rate="1.0"
|
|
|
|
|
anim="coach"
|
|
|
|
|
class="absolute -bottom-2 -right-3 z-20 drop-shadow-[0_0_12px_rgba(0,255,65,0.4)]"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2026-03-07 20:10:57 +00:00
|
|
|
<div class="hero-fighter hero-fighter-right shrink-0" style="transform: scaleX(-1)">
|
|
|
|
|
<SpritePreview
|
|
|
|
|
seed="hero_dragon"
|
|
|
|
|
archetype="dragon"
|
|
|
|
|
:tier="5"
|
2026-03-08 14:30:31 +00:00
|
|
|
:size="72"
|
2026-03-07 20:10:57 +00:00
|
|
|
class="drop-shadow-[0_0_16px_rgba(0,240,255,0.4)]"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-03-08 14:30:31 +00:00
|
|
|
<!-- Desktop -->
|
|
|
|
|
<div class="hidden sm:flex items-center justify-center gap-6 mb-6">
|
2026-03-07 20:10:57 +00:00
|
|
|
<div class="hero-fighter hero-fighter-left shrink-0">
|
|
|
|
|
<SpritePreview
|
|
|
|
|
seed="hero_samurai"
|
|
|
|
|
archetype="samurai"
|
|
|
|
|
:tier="5"
|
2026-03-08 14:30:31 +00:00
|
|
|
:size="120"
|
2026-03-07 20:10:57 +00:00
|
|
|
class="drop-shadow-[0_0_24px_rgba(255,68,136,0.4)]"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2026-03-08 14:30:31 +00:00
|
|
|
<div class="creator-host shrink-0 relative">
|
|
|
|
|
<div class="creator-glow" />
|
|
|
|
|
<SpritePreview
|
|
|
|
|
seed="the_creator"
|
|
|
|
|
archetype="the_creator"
|
|
|
|
|
:tier="5"
|
|
|
|
|
:size="160"
|
|
|
|
|
class="relative z-10 drop-shadow-[0_0_32px_rgba(255,215,0,0.5)]"
|
|
|
|
|
/>
|
|
|
|
|
<HumanPreview
|
|
|
|
|
seed="the_creator"
|
|
|
|
|
archetype="the_creator"
|
|
|
|
|
:size="90"
|
|
|
|
|
:win-rate="1.0"
|
|
|
|
|
anim="coach"
|
|
|
|
|
class="absolute -bottom-4 -right-6 z-20 drop-shadow-[0_0_16px_rgba(0,255,65,0.4)]"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="hero-fighter hero-fighter-right shrink-0" style="transform: scaleX(-1)">
|
2026-03-07 20:10:57 +00:00
|
|
|
<SpritePreview
|
|
|
|
|
seed="hero_dragon"
|
|
|
|
|
archetype="dragon"
|
|
|
|
|
:tier="5"
|
2026-03-08 14:30:31 +00:00
|
|
|
:size="120"
|
2026-03-07 20:10:57 +00:00
|
|
|
class="drop-shadow-[0_0_24px_rgba(0,240,255,0.4)]"
|
|
|
|
|
/>
|
2026-03-07 11:04:32 +00:00
|
|
|
</div>
|
2026-03-06 16:27:54 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Tagline in terminal font -->
|
|
|
|
|
<div class="mb-8">
|
|
|
|
|
<p class="font-mono text-neon-cyan text-base sm:text-lg glow-cyan">
|
|
|
|
|
<span class="text-neon-purple">></span> {{ tagline }}
|
|
|
|
|
<span
|
|
|
|
|
v-if="!isTypingDone"
|
|
|
|
|
class="inline-block w-2.5 h-5 bg-neon-cyan ml-0.5 align-middle"
|
|
|
|
|
/>
|
|
|
|
|
<span
|
|
|
|
|
v-else
|
|
|
|
|
class="inline-block w-2.5 h-5 bg-neon-cyan ml-0.5 align-middle flicker"
|
|
|
|
|
/>
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-03-07 20:10:57 +00:00
|
|
|
<!-- CTAs — always side by side -->
|
|
|
|
|
<div class="flex items-center justify-center gap-3 sm:gap-5 mb-8 sm:mb-10">
|
2026-03-06 16:27:54 +00:00
|
|
|
<RouterLink
|
2026-03-06 22:13:19 +00:00
|
|
|
to="/join"
|
2026-03-07 20:10:57 +00:00
|
|
|
class="flex-1 sm:flex-none sm:px-10 py-3 sm:py-4 bg-neon-pink/10 border-2 border-neon-pink text-neon-pink
|
|
|
|
|
font-display font-black text-sm sm:text-base tracking-widest text-center
|
|
|
|
|
hover:bg-neon-pink/20 transition-all neon-border-pink max-w-[180px] sm:max-w-none"
|
2026-03-06 16:27:54 +00:00
|
|
|
>
|
2026-03-07 20:10:57 +00:00
|
|
|
FIGHT
|
2026-03-06 16:27:54 +00:00
|
|
|
</RouterLink>
|
|
|
|
|
<RouterLink
|
2026-03-06 22:13:19 +00:00
|
|
|
to="/arena"
|
2026-03-07 20:10:57 +00:00
|
|
|
class="flex-1 sm:flex-none sm:px-10 py-3 sm:py-4 border-2 border-neon-cyan/40 text-neon-cyan
|
|
|
|
|
font-display font-black text-sm sm:text-base tracking-widest text-center
|
|
|
|
|
hover:border-neon-cyan hover:bg-neon-cyan/10 transition-all max-w-[180px] sm:max-w-none"
|
2026-03-06 16:27:54 +00:00
|
|
|
>
|
2026-03-07 20:10:57 +00:00
|
|
|
WATCH
|
2026-03-06 16:27:54 +00:00
|
|
|
</RouterLink>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Recent fights -->
|
|
|
|
|
<div v-if="recentFights.length > 0">
|
|
|
|
|
<p class="font-pixel text-text-muted text-xs uppercase tracking-[0.3em] mb-3">
|
|
|
|
|
Latest Bouts
|
|
|
|
|
</p>
|
|
|
|
|
<div class="inline-flex flex-col gap-1.5 max-w-sm mx-auto">
|
|
|
|
|
<RouterLink
|
|
|
|
|
v-for="fight in recentFights"
|
|
|
|
|
:key="fight.id"
|
|
|
|
|
:to="`/arena/${fight.id}`"
|
|
|
|
|
class="flex items-center justify-between text-xs font-mono px-3 py-1.5
|
|
|
|
|
border border-border/50 hover:border-neon-purple/40 transition-colors bg-surface/50"
|
|
|
|
|
>
|
|
|
|
|
<span class="flex items-center gap-2">
|
|
|
|
|
<span :class="fight.winner?.name === fight.botA?.name ? 'text-neon-cyan font-bold' : 'text-text-muted'">
|
|
|
|
|
{{ fight.botA?.name || '???' }}
|
|
|
|
|
</span>
|
|
|
|
|
<span class="text-neon-purple font-glitch text-sm">VS</span>
|
|
|
|
|
<span :class="fight.winner?.name === fight.botB?.name ? 'text-neon-cyan font-bold' : 'text-text-muted'">
|
|
|
|
|
{{ fight.botB?.name || '???' }}
|
|
|
|
|
</span>
|
|
|
|
|
</span>
|
|
|
|
|
<span class="text-neon-pink text-[10px] font-pixel">R{{ fight.totalRounds }}</span>
|
|
|
|
|
</RouterLink>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-else>
|
|
|
|
|
<p class="font-pixel text-text-muted text-xs italic">
|
|
|
|
|
The ring is empty. Be the first.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
2026-03-07 10:42:18 +00:00
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.crowd-bob {
|
|
|
|
|
animation: crowdBob 3s ease-in-out infinite;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes crowdBob {
|
|
|
|
|
0%, 100% { transform: translateY(0); }
|
|
|
|
|
50% { transform: translateY(-6px); }
|
|
|
|
|
}
|
2026-03-07 11:04:32 +00:00
|
|
|
|
|
|
|
|
.hero-fighter {
|
|
|
|
|
animation: heroBob 2.5s ease-in-out infinite;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hero-fighter-right {
|
|
|
|
|
animation-delay: 0.4s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes heroBob {
|
|
|
|
|
0%, 100% { transform: translateY(0); }
|
|
|
|
|
50% { transform: translateY(-10px); }
|
|
|
|
|
}
|
2026-03-08 14:30:31 +00:00
|
|
|
|
|
|
|
|
.creator-host {
|
|
|
|
|
animation: creatorFloat 4s ease-in-out infinite;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes creatorFloat {
|
|
|
|
|
0%, 100% { transform: translateY(0); }
|
|
|
|
|
50% { transform: translateY(-8px); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.creator-glow {
|
|
|
|
|
position: absolute;
|
|
|
|
|
inset: -20px;
|
|
|
|
|
background: radial-gradient(ellipse at center, rgba(255, 215, 0, 0.15) 0%, rgba(0, 255, 65, 0.05) 40%, transparent 70%);
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
z-index: 0;
|
|
|
|
|
animation: creatorPulse 3s ease-in-out infinite;
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes creatorPulse {
|
|
|
|
|
0%, 100% { opacity: 0.6; transform: scale(1); }
|
|
|
|
|
50% { opacity: 1; transform: scale(1.1); }
|
|
|
|
|
}
|
2026-03-07 10:42:18 +00:00
|
|
|
</style>
|