4 models have responded to the "Pokémon Battle UI Recreation" challenge. Compare their approaches side-by-side on RIVAL. This response is part of RIVAL's open dataset of 5,600+ AI model responses.
OpenAI o4-mini's response to the Pokémon Battle UI challenge.
Recreate a Pokémon battle UI — make it interactive, nostalgic, and fun. Stick to the spirit of a classic battle, but feel free to get creative if you want. In a single-page self-contained HTML.
Couldn't render this response
This model didn't return a displayable web page for this challenge.
<style>
/* ===== Pixelated, retro look ===== */
body {
margin: 0;
background: #9bbc0f;
font-family: monospace;
user-select: none;
}
#battle-container {
width: 600px;
height: 400px;
margin: 30px auto;
box-shadow: 0 0 0 8px #406820, 0 0 0 10px #9bbc0f;
position: relative;
background: #c0d890;
}
#battlefield {
position: absolute;
width: 100%;
height: 60%;
top: 0; left: 0;
background: linear-gradient(to bottom, #a0c0f0 60%, #d0e0d0 60%);
}
.pokemon {
position: absolute;
width: 120px; height: 120px;
}
.pokemon .sprite {
width: 80px; height: 80px;
background: #fff;
border: 4px solid #000;
display: flex;
align-items: center;
justify-content: center;
color: #000;
font-size: 24px;
margin: 4px;
}
.pokemon .hp-bar {
width: 100px; height: 12px;
background: #000;
margin: 4px;
border: 2px solid #fff;
}
.pokemon .hp-inner {
height: 100%;
background: #00c800;
width: 100%;
}
.opponent {
top: 30px; right: 60px;
}
.player {
bottom: 80px; left: 60px;
}
#message-box {
position: absolute;
bottom: 80px; left: 0;
width: 100%;
height: 60px;
background: #fff;
border-top: 4px solid #000;
border-bottom: 4px solid #000;
padding: 8px;
box-sizing: border-box;
}
#menu-box {
position: absolute;
bottom: 0; left: 0;
width: 100%;
height: 80px;
background: #fff;
border-top: 4px solid #000;
display: flex;
flex-wrap: wrap;
align-content: space-evenly;
justify-content: space-evenly;
}
#menu-box button {
width: 28%;
height: 36px;
background: #c0c0c0;
border: 2px solid #000;
font-size: 14px;
cursor: pointer;
}
#move-box { width: 100%; display: none; flex-wrap: wrap; }
.move-btn { width: 48%; margin: 1%; }
</style>
</head>
<body>
<div id="battle-container">
<!-- Battlefield -->
<div id="battlefield">
<div class="pokemon opponent">
<div class="sprite">??</div>
<div class="hp-bar"><div class="hp-inner" id="opponent-hp"></div></div>
</div>
<div class="pokemon player">
<div class="sprite">⚡</div>
<div class="hp-bar"><div class="hp-inner" id="player-hp"></div></div>
</div>
</div>
<!-- Message -->
<div id="message-box">A wild Pokémon appeared!</div>
<!-- Menu -->
<div id="menu-box">
<button id="fight-btn">FIGHT</button>
<button id="bag-btn">BAG</button>
<button id="pokemon-btn">POKÉMON</button>
<button id="run-btn">RUN</button>
<div id="move-box">
<button class="move-btn" data-move="Tackle" data-power="20">TACKLE</button>
<button class="move-btn" data-move="Growl" data-power="0">GROWL</button>
<button class="move-btn" data-move="Thunder Shock" data-power="25">THUNDER SHOCK</button>
<button class="move-btn" data-move="Quick Attack" data-power="15">QUICK ATTACK</button>
</div>
</div>
</div>
<script>
// Data
let playerHP = 100, oppHP = 100;
const playerMax = 100, oppMax = 100;
const messageBox = document.getElementById('message-box');
const fightBtn = document.getElementById('fight-btn');
const runBtn = document.getElementById('run-btn');
const moveBox = document.getElementById('move-box');
const menuBtns = [...document.querySelectorAll('#menu-box > button')];
const moveBtns = [...document.querySelectorAll('.move-btn')];
const playerBar = document.getElementById('player-hp');
const oppBar = document.getElementById('opponent-hp');
function updateBars(){
playerBar.style.width = playerHP/playerMax*100 + '%';
oppBar.style.width = oppHP/oppMax*100 + '%';
if(playerHP<=0) playerBar.style.background='#800';
if(oppHP<=0) oppBar.style.background='#800';
}
updateBars();
function showMessage(txt, cb){
messageBox.textContent = txt;
setTimeout(()=>{ if(cb) cb(); }, 1000);
}
function enableMenu(on){
menuBtns.forEach(b=>{
if(b.id==='fight-btn') b.disabled = !on;
else if(b.id==='run-btn') b.disabled = !on;
else b.disabled = !on;
});
}
fightBtn.addEventListener('click', ()=>{
fightBtn.disabled = true;
runBtn.disabled = true;
moveBox.style.display = 'flex';
messageBox.textContent = 'Choose a move:';
});
moveBtns.forEach(btn=>{
btn.addEventListener('click', ()=>{
const move = btn.dataset.move;
const power = +btn.dataset.power;
moveBox.style.display = 'none';
// Player's turn
const dmg = power + Math.floor(Math.random()*5) - 2;
oppHP = Math.max(0, oppHP - dmg);
updateBars();
showMessage('You used ' + move + '! (-' + dmg + ' HP)', ()=>{
if(oppHP<=0){
showMessage('Opponent fainted! You win!', ()=>{});
} else {
// Opponent turn
const oppMoves = [
{m:'Scratch',p:20},
{m:'Leer',p:0},
{m:'Ember',p:22}
];
const choice = oppMoves[Math.floor(Math.random()*oppMoves.length)];
const odmg = choice.p + Math.floor(Math.random()*5)-2;
playerHP = Math.max(0, playerHP - odmg);
updateBars();
showMessage('Enemy used ' + choice.m + '! (-' + odmg + ' HP)', ()=>{
if(playerHP<=0){
showMessage('You fainted! Game over.', ()=>{});
} else {
showMessage('What will you do?', ()=>{
fightBtn.disabled = false; runBtn.disabled = false;
});
}
});
}
});
});
});
runBtn.addEventListener('click', ()=>{
enableMenu(false);
showMessage('Got away safely!', ()=>{});
});
document.getElementById('bag-btn').addEventListener('click', ()=>{
showMessage('No items in bag!', ()=>{
showMessage('What will you do?', ()=>{});
});
});
document.getElementById('pokemon-btn').addEventListener('click', ()=>{
showMessage('You only have one Pokémon!', ()=>{
showMessage('What will you do?', ()=>{});
});
});
</script>