feat: remove mock fight button for production, cleanup fight UI

- Remove "Fight a Classic Bot" button (mock endpoints blocked in prod)
- Simplify speech bubble rendering (remove glow/accent layers)
- Sound and FightViewer improvements
- BotProfilePage enhancements

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-07 11:59:10 +00:00
co-authored by Claude Opus 4.6
parent bb9a966d4e
commit 56785cfdea
5 changed files with 155 additions and 135 deletions
+33 -59
View File
@@ -6082,31 +6082,19 @@ export async function createFightScene(config: FightSceneConfig) {
const bubbleW = textW + padX * 2
const bubbleH = lines.length * lineH + padY * 2
const tailSize = 10
const borderW = 3
// Position — offset away from center so bubbles don't overlap
const offsetX = side === 'a' ? -bubbleW * 0.3 : bubbleW * 0.3
const bx = fighter.pos.x + offsetX
const by = Math.max(8, fighter.pos.y - 85 - bubbleH)
// Colours — vivid neon
const bgColor = side === 'a' ? '#001a22' : '#22001a'
const borderColor = side === 'a' ? '#00f0ff' : '#ff2d7b'
const glowColor = side === 'a' ? '#00f0ff' : '#ff2d7b'
const textColor = '#ffffff'
const bgColor = side === 'a' ? '#0a1e2a' : '#2a0a1e'
// Outer glow halo
const glow = k.add([
k.rect(bubbleW + 12, bubbleH + 12),
k.pos(bx - bubbleW / 2 - 6, by - 6),
k.color(safeColor(k, glowColor)), k.opacity(0.08), k.z(53),
])
allEls.push(glow)
// Border (thick, behind bubble)
// Single border rect (no glow/accent layers — keeps rendering clean)
const border = k.add([
k.rect(bubbleW + borderW * 2, bubbleH + borderW * 2),
k.pos(bx - bubbleW / 2 - borderW, by - borderW),
k.rect(bubbleW + 4, bubbleH + 4),
k.pos(bx - bubbleW / 2 - 2, by - 2),
k.color(safeColor(k, borderColor)), k.opacity(0.85), k.z(54),
])
allEls.push(border)
@@ -6119,70 +6107,56 @@ export async function createFightScene(config: FightSceneConfig) {
])
allEls.push(bubble)
// Tail — two overlapping rects to form a triangle look
// Tail — pixel arrow pointing down to fighter
const tailX = bx + (side === 'a' ? bubbleW * 0.15 : -bubbleW * 0.15)
const tailY = by + bubbleH
// Outer tail (border colour)
const tailOuter = k.add([
k.rect(tailSize + borderW, tailSize + borderW),
k.pos(tailX, tailY - 2),
k.color(safeColor(k, borderColor)), k.opacity(0.85), k.z(54),
k.rotate(45), k.anchor('top'),
])
allEls.push(tailOuter)
// Inner tail (bg colour, masks the border)
const tailInner = k.add([
k.rect(tailSize, tailSize),
k.pos(tailX, tailY - 1),
k.color(safeColor(k, bgColor)), k.opacity(0.95), k.z(55),
k.rotate(45), k.anchor('top'),
])
allEls.push(tailInner)
// Cover strip — hides top half of the rotated tail square
const tailCover = k.add([
k.rect(bubbleW, borderW + 2),
k.pos(bx - bubbleW / 2, tailY - borderW),
k.color(safeColor(k, bgColor)), k.opacity(0.95), k.z(56),
])
allEls.push(tailCover)
// Inner accent line at top of bubble
const accent = k.add([
k.rect(bubbleW - 8, 2),
k.pos(bx - bubbleW / 2 + 4, by + 3),
k.color(safeColor(k, borderColor)), k.opacity(0.4), k.z(56),
])
allEls.push(accent)
const tailBaseY = by + bubbleH
for (let row = 0; row < tailSize; row++) {
const tw = tailSize - row
// Border pixel row
const tailBorder = k.add([
k.rect(tw + 2, 1),
k.pos(tailX - (tw + 2) / 2, tailBaseY + row),
k.color(safeColor(k, borderColor)), k.opacity(0.85), k.z(54),
])
allEls.push(tailBorder)
// Inner pixel row
if (tw > 2) {
const tailInner = k.add([
k.rect(tw - 1, 1),
k.pos(tailX - (tw - 1) / 2, tailBaseY + row),
k.color(safeColor(k, bgColor)), k.opacity(0.95), k.z(55),
])
allEls.push(tailInner)
}
}
// Text lines
for (let i = 0; i < lines.length; i++) {
const tEl = k.add([
k.text(safeText(lines[i]), { size: fontSize }),
k.text(safeText(lines[i]), { size: fontSize, font: 'monospace' }),
k.pos(bx - bubbleW / 2 + padX, by + padY + i * lineH + 2),
k.color(safeColor(k, textColor)), k.opacity(1), k.z(57),
k.color(255, 255, 255), k.opacity(1), k.z(57),
])
allEls.push(tEl)
}
// Animated glow pulse
glow.onUpdate(() => {
glow.opacity = 0.05 + Math.sin(k.time() * 3) * 0.05
})
// Border glow pulse
border.onUpdate(() => {
border.opacity = 0.7 + Math.sin(k.time() * 4) * 0.15
})
// Pop-in — scale up from anchor point with bounce
// Pop-in animation
const anchorX = bx, anchorY = by + bubbleH
allEls.forEach(el => {
const origX = el.pos.x, origY = el.pos.y
const origOpacity = el.opacity
el.pos.x = anchorX + (origX - anchorX) * 0.1
el.pos.y = anchorY + (origY - anchorY) * 0.1
el.opacity *= 0
el.opacity = 0
k.tween(0, 1, 0.25, (t) => {
el.pos.x = anchorX + (origX - anchorX) * t
el.pos.y = anchorY + (origY - anchorY) * t
el.opacity = (el === glow ? 0.08 : el === border ? 0.85 : el === bubble || el === tailInner || el === tailCover ? 0.95 : el === tailOuter ? 0.85 : el === accent ? 0.4 : 1) * t
el.opacity = origOpacity * t
}, k.easings.easeOutBack)
})
@@ -6641,7 +6615,7 @@ export async function createFightScene(config: FightSceneConfig) {
}, k.easings.easeInOutQuad)
await k.wait(0.2)
heart.text = '!!!'
announceRandom("You promised you'd stop fighting!", false)
announceRandom("You promised you'd stop fighting!")
await k.wait(0.4)
// Girlfriend storms off
announceSilly('I\'m telling your developer!')