diff --git a/frontend/src/components/FightViewer.vue b/frontend/src/components/FightViewer.vue index 5853014..f399e24 100644 --- a/frontend/src/components/FightViewer.vue +++ b/frontend/src/components/FightViewer.vue @@ -298,8 +298,8 @@ function addRoundToLog(round: FightRound, stagger: boolean): Promise { logItems.value.push( { type: 'header', round: round.roundNumber, text: `ROUND ${round.roundNumber}: ${challengeLabel(round.challengeType)}`, color: 'neon-purple' }, { type: 'prompt', round: round.roundNumber, text: challenge.displayPrompt || challenge.prompt, color: 'text-muted' }, - { type: 'responseA', round: round.roundNumber, text: `${props.fight.botA?.name}: ${round.botAResponse?.slice(0, 120) || '[NO RESPONSE]'} (${round.botATimeMs}ms)`, color: 'neon-cyan' }, - { type: 'responseB', round: round.roundNumber, text: `${props.fight.botB?.name}: ${round.botBResponse?.slice(0, 120) || '[NO RESPONSE]'} (${round.botBTimeMs}ms)`, color: 'neon-pink' }, + { type: 'responseA', round: round.roundNumber, text: `${props.fight.botA?.name}: ${round.botAResponse || '[NO RESPONSE]'} (${round.botATimeMs}ms)`, color: 'neon-cyan' }, + { type: 'responseB', round: round.roundNumber, text: `${props.fight.botB?.name}: ${round.botBResponse || '[NO RESPONSE]'} (${round.botBTimeMs}ms)`, color: 'neon-pink' }, ) if (round.narration) logItems.value.push({ type: 'narration', round: round.roundNumber, text: `>> ${round.narration}`, color: 'neon-yellow' }) const winner = round.winnerId === props.fight.botA?.id ? props.fight.botA?.name : round.winnerId === props.fight.botB?.id ? props.fight.botB?.name : 'DRAW' @@ -313,11 +313,11 @@ function addRoundToLog(round: FightRound, stagger: boolean): Promise { scrollLog(); await sleep(150) logItems.value.push({ type: 'prompt', round: round.roundNumber, text: challenge.displayPrompt || challenge.prompt, color: 'text-muted' }) scrollLog(); await sleep(200) - logItems.value.push({ type: 'responseA', round: round.roundNumber, text: `${props.fight.botA?.name}: ${round.botAResponse?.slice(0, 120) || '[NO RESPONSE]'}`, color: 'neon-cyan' }) + logItems.value.push({ type: 'responseA', round: round.roundNumber, text: `${props.fight.botA?.name}: ${round.botAResponse || '[NO RESPONSE]'}`, color: 'neon-cyan' }) scrollLog(); await sleep(150) logItems.value.push({ type: 'time', round: round.roundNumber, text: ` ${round.botATimeMs}ms | Score: ${round.botAScore}`, color: 'text-muted' }) scrollLog(); await sleep(150) - logItems.value.push({ type: 'responseB', round: round.roundNumber, text: `${props.fight.botB?.name}: ${round.botBResponse?.slice(0, 120) || '[NO RESPONSE]'}`, color: 'neon-pink' }) + logItems.value.push({ type: 'responseB', round: round.roundNumber, text: `${props.fight.botB?.name}: ${round.botBResponse || '[NO RESPONSE]'}`, color: 'neon-pink' }) scrollLog(); await sleep(150) logItems.value.push({ type: 'time', round: round.roundNumber, text: ` ${round.botBTimeMs}ms | Score: ${round.botBScore}`, color: 'text-muted' }) scrollLog() @@ -434,11 +434,11 @@ async function _doReplay() { if (round.botAResponse) { if (doTTS) await awaitAnswerReady(props.fight.botA!.name, round.botAResponse) scene?.stopShowboating('a') - logItems.value.push({ type: 'responseA', round: round.roundNumber, text: `${props.fight.botA?.name}: ${round.botAResponse.slice(0, 120) || '[NO RESPONSE]'}`, color: 'neon-cyan' }) + logItems.value.push({ type: 'responseA', round: round.roundNumber, text: `${props.fight.botA?.name}: ${round.botAResponse || '[NO RESPONSE]'}`, color: 'neon-cyan' }) logItems.value.push({ type: 'time', round: round.roundNumber, text: ` ${round.botATimeMs}ms | Score: ${round.botAScore}`, color: 'text-muted' }) scrollLog() if (scene && !insanityMode.value) { - scene.showSpeechBubble('a', round.botAResponse.slice(0, 60), 8) + scene.showSpeechBubble('a', round.botAResponse, 8) scene.startTalking('a') } // Ensure bubble stays visible for at least 400ms even if TTS resolves instantly @@ -454,13 +454,13 @@ async function _doReplay() { if (round.botBResponse) { if (doTTS) await awaitAnswerReady(props.fight.botB!.name, round.botBResponse) scene?.stopShowboating('b') - logItems.value.push({ type: 'responseB', round: round.roundNumber, text: `${props.fight.botB?.name}: ${round.botBResponse.slice(0, 120) || '[NO RESPONSE]'}`, color: 'neon-pink' }) + logItems.value.push({ type: 'responseB', round: round.roundNumber, text: `${props.fight.botB?.name}: ${round.botBResponse || '[NO RESPONSE]'}`, color: 'neon-pink' }) logItems.value.push({ type: 'time', round: round.roundNumber, text: ` ${round.botBTimeMs}ms | Score: ${round.botBScore}`, color: 'text-muted' }) scrollLog() // Prefetch narration while bot B talks if (doTTS && round.narration) prefetchNarration(round.narration) if (scene && !insanityMode.value) { - scene.showSpeechBubble('b', round.botBResponse.slice(0, 60), 8) + scene.showSpeechBubble('b', round.botBResponse, 8) scene.startTalking('b') } const minBubbleB = sleep(400).catch(() => {}) diff --git a/frontend/src/game/fight/config.ts b/frontend/src/game/fight/config.ts index 3cbb8bb..3b9b5b5 100644 --- a/frontend/src/game/fight/config.ts +++ b/frontend/src/game/fight/config.ts @@ -107,9 +107,9 @@ export const SKY_GRADIENT_BANDS = 6 // Number of sky gradient ba export const GROUND_DEPTH_LINES = 12 // Ground gradient fade lines export const PERSPECTIVE_GRID_LINES = 24 // Floor grid convergence lines export const PILLAR_WIDTH = 8 // Side pillar frame width -export const SPEECH_BUBBLE_MAX_CHARS = 80 // Max chars in speech bubble -export const SPEECH_BUBBLE_WRAP = 18 // Chars per line in speech bubble -export const SPEECH_BUBBLE_MAX_LINES = 5 // Max lines in speech bubble +export const SPEECH_BUBBLE_MAX_CHARS = 200 // Max chars in speech bubble +export const SPEECH_BUBBLE_WRAP = 24 // Chars per line in speech bubble +export const SPEECH_BUBBLE_MAX_LINES = 8 // Max lines in speech bubble export const SPEECH_BUBBLE_FONT_SIZE = 12 // Speech bubble font size export const SPEECH_BUBBLE_DEFAULT_DURATION = 3 // Default speech bubble duration (seconds) diff --git a/frontend/src/pages/FightPage.vue b/frontend/src/pages/FightPage.vue index 2002d9f..4348c78 100644 --- a/frontend/src/pages/FightPage.vue +++ b/frontend/src/pages/FightPage.vue @@ -246,10 +246,10 @@ async function handleRoundEnd(data: any) { { type: 'header', round, text: `ROUND ${round}: ${cLabel}`, color: 'neon-purple' }, ) if (result.botAResponse) { - liveLogItems.value.push({ type: 'responseA', round, text: `${fd.botA.name}: ${result.botAResponse.slice(0, 120)}`, color: 'neon-cyan' }) + liveLogItems.value.push({ type: 'responseA', round, text: `${fd.botA.name}: ${result.botAResponse}`, color: 'neon-cyan' }) } if (result.botBResponse) { - liveLogItems.value.push({ type: 'responseB', round, text: `${fd.botB.name}: ${result.botBResponse.slice(0, 120)}`, color: 'neon-pink' }) + liveLogItems.value.push({ type: 'responseB', round, text: `${fd.botB.name}: ${result.botBResponse}`, color: 'neon-pink' }) } if (result.narration) { liveLogItems.value.push({ type: 'narration', round, text: `>> ${result.narration}`, color: 'neon-yellow' }) @@ -263,10 +263,10 @@ async function handleRoundEnd(data: any) { if (liveScene) { fanfareRound(round) - if (result.botAResponse) liveScene.showSpeechBubble('a', result.botAResponse.slice(0, 60), 3) + if (result.botAResponse) liveScene.showSpeechBubble('a', result.botAResponse, 3) if (result.botBResponse) { setTimeout(() => { - if (liveScene && result.botBResponse) liveScene.showSpeechBubble('b', result.botBResponse.slice(0, 60), 2.5) + if (liveScene && result.botBResponse) liveScene.showSpeechBubble('b', result.botBResponse, 2.5) }, 300) }