A fun game created with AI
Created by FunBuilder4747 • January 28, 2026
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Wizard Academy: Graduation Trials</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #1a0033 0%, #2d0066 50%, #4a0099 100%);
font-family: 'Georgia', serif;
overflow: hidden;
touch-action: manipulation;
}
#gameContainer {
position: relative;
width: 100%;
height: 100vh;
max-width: 800px;
max-height: 600px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
canvas {
border: 3px solid #ffd700;
box-shadow: 0 0 30px rgba(255, 215, 0, 0.5);
background: #0a0015;
touch-action: none;
}
#ui {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
color: #ffd700;
font-size: clamp(12px, 2vw, 16px);
text-shadow: 2px 2px 4px #000;
pointer-events: none;
}
#controls {
position: absolute;
bottom: 10px;
left: 10px;
right: 10px;
display: flex;
justify-content: space-around;
gap: 10px;
flex-wrap: wrap;
}
.spell-btn {
padding: clamp(8px, 2vw, 12px);
font-size: clamp(10px, 2vw, 14px);
border: 2px solid #ffd700;
background: rgba(0, 0, 0, 0.7);
color: #ffd700;
cursor: pointer;
border-radius: 5px;
font-family: 'Georgia', serif;
font-weight: bold;
touch-action: manipulation;
min-width: 60px;
min-height: 44px;
}
.spell-btn:active {
transform: scale(0.95);
background: rgba(255, 215, 0, 0.3);
}
.spell-btn.fire { border-color: #ff4500; color: #ff4500; }
.spell-btn.water { border-color: #1e90ff; color: #1e90ff; }
.spell-btn.earth { border-color: #8b4513; color: #8b4513; }
.spell-btn.air { border-color: #87ceeb; color: #87ceeb; }
/* Mobile optimization CSS */
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #000;
font-family: Arial, sans-serif;
overflow: hidden; /* Prevent scrolling on mobile */
/* Safe area insets for iPhone notch/home indicator */
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
/* Prevent text selection and long-press menus on mobile */
-webkit-user-select: none;
user-select: none;
-webkit-touch-callout: none;
/* Disable tap highlight on mobile */
-webkit-tap-highlight-color: transparent;
/* Optimize for touch */
touch-action: manipulation;
}
#game {
border: 2px solid #fff;
max-width: 100vw;
max-height: 100vh;
display: block;
touch-action: none; /* Prevent default touch behaviors on canvas */
}
/* UI elements should be positioned safely */
.game-ui {
position: absolute;
color: #fff;
font-size: clamp(14px, 3vw, 24px); /* Responsive font size */
z-index: 10;
pointer-events: none; /* UI doesn't interfere with touch controls */
}
.score {
top: max(10px, env(safe-area-inset-top) + 10px);
left: max(10px, env(safe-area-inset-left) + 10px);
}
.lives {
top: max(10px, env(safe-area-inset-top) + 10px);
right: max(10px, env(safe-area-inset-right) + 10px);
}
</style>
</head>
<body>
<div id="gameContainer">
<div id="ui">
<div>Health: <span id="health">100</span> | Mana: <span id="mana">100</span> | Trial: <span id="trial">1</span>/5</div>
<div>Spells Learned: <span id="spellCount">4</span> | Creatures Befriended: <span id="friendCount">0</span></div>
</div>
<canvas id="game" width="800" height="600"></canvas>
<div id="controls">
<button class="spell-btn fire" id="fireBtn">🔥 Fire</button>
<button class="spell-btn water" id="waterBtn">💧 Water</button>
<button class="spell-btn earth" id="earthBtn">🌍 Earth</button>
<button class="spell-btn air" id="airBtn">💨 Air</button>
<button class="spell-btn" id="potionBtn">🧪 Potion</button>
</div>
</div>
<script>
window.addEventListener('load', function() {
try {
const canvas = document.getElementById('game');
if (!canvas) { alert('Canvas not found'); return; }
const ctx = canvas.getContext('2d');
if (!ctx) { alert('Canvas context failed'); return; }
// Responsive canvas
function resizeCanvas() {
const container = document.getElementById('gameContainer');
const maxWidth = Math.min(window.innerWidth - 20, 800);
const maxHeight = Math.min(window.innerHeight - 120, 600);
const scale = Math.min(maxWidth / 800, maxHeight / 600);
canvas.style.width = (800 * scale) + 'px';
canvas.style.height = (600 * scale) + 'px';
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
window.addEventListener('orientationchange', () => setTimeout(resizeCanvas, 100));
// Game state
const game = {
player: { x: 400, y: 500, width: 30, height: 40, speed: 4, health: 100, maxHealth: 100, mana: 100, maxMana: 100 },
spells: [],
creatures: [],
particles: [],
potionIngredients: [],
currentTrial: 1,
trialProgress: 0,
spellsLearned: ['fire', 'water', 'earth', 'air'],
creaturesFriended: 0,
selectedSpell: 'fire',
potionBrewing: false,
potionTimer: 0,
collectedIngredients: [],
lastSpellTime: 0,
spellCooldown: 500
};
// Keyboard controls
const keys = {};
window.addEventListener('keydown', (e) => {
keys[e.key] = true;
if (e.key === '1') game.selectedSpell = 'fire';
if (e.key === '2') game.selectedSpell = 'water';
if (e.key === '3') game.selectedSpell = 'earth';
if (e.key === '4') game.selectedSpell = 'air';
if (e.key === ' ' || e.key === 'Enter') castSpell();
if (e.key === 'p' || e.key === 'P') startPotionBrewing();
e.preventDefault();
});
window.addEventListener('keyup', (e) => {
keys[e.key] = false;
});
// Touch controls
let touchStartX = 0, touchStartY = 0;
canvas.addEventListener('touchstart', (e) => {
e.preventDefault();
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
}, { passive: false });
canvas.addEventListener('touchmove', (e) => {
e.preventDefault();
const rect = canvas.getBoundingClientRect();
const scaleX = 800 / rect.width;
const scaleY = 600 / rect.height;
const touchX = (e.touches[0].clientX - rect.left) * scaleX;
const touchY = (e.touches[0].clientY - rect.top) * scaleY;
// Move player towards touch
if (touchX < game.player.x) keys['ArrowLeft'] = true;
else keys['ArrowLeft'] = false;
if (touchX > game.player.x + game.player.width) keys['ArrowRight'] = true;
else keys['ArrowRight'] = false;
}, { passive: false });
canvas.addEventListener('touchend', (e) => {
e.preventDefault();
keys['ArrowLeft'] = false;
keys['ArrowRight'] = false;
const deltaX = e.changedTouches[0].clientX - touchStartX;
const deltaY = e.changedTouches[0].clientY - touchStartY;
// Tap to cast spell
if (Math.abs(deltaX) < 10 && Math.abs(deltaY) < 10) {
castSpell();
}
}, { passive: false });
// Button controls
document.getElementById('fireBtn').addEventListener('click', () => { game.selectedSpell = 'fire'; castSpell(); });
document.getElementById('waterBtn').addEventListener('click', () => { game.selectedSpell = 'water'; castSpell(); });
document.getElementById('earthBtn').addEventListener('click', () => { game.selectedSpell = 'earth'; castSpell(); });
document.getElementById('airBtn').addEventListener('click', () => { game.selectedSpell = 'air'; castSpell(); });
document.getElementById('potionBtn').addEventListener('click', startPotionBrewing);
// Spell casting
function castSpell() {
const now = Date.now();
if (now - game.lastSpellTime < game.spellCooldown) return;
const manaCost = 15;
if (game.mana < manaCost) return;
game.mana -= manaCost;
game.lastSpellTime = now;
const spell = {
x: game.player.x + game.player.width / 2,
y: game.player.y,
width: 20,
height: 20,
speed: 6,
type: game.selectedSpell,
damage: 25
};
game.spells.push(spell);
// Create particles
for (let i = 0; i < 5; i++) {
createParticle(spell.x, spell.y, spell.type);
}
}
// Potion brewing
function startPotionBrewing() {
if (game.collectedIngredients.length >= 3) {
game.potionBrewing = true;
game.potionTimer = 3;
}
}
// Particle effects
function createParticle(x, y, type) {
const colors = {
fire: '#ff4500',
water: '#1e90ff',
earth: '#8b4513',
air: '#87ceeb'
};
game.particles.push({
x: x,
y: y,
vx: (Math.random() - 0.5) * 3,
vy: (Math.random() - 0.5) * 3,
life: 30,
color: colors[type] || '#ffd700',
size: Math.random() * 4 + 2
});
}
// Spawn creatures
function spawnCreature() {
const types = ['dragon', 'phoenix', 'unicorn', 'griffin'];
const type = types[Math.floor(Math.random() * types.length)];
const creature = {
x: Math.random() * 700 + 50,
y: -50,
width: 40,
height: 40,
speed: 1 + Math.random() * 2,
health: 50,
maxHealth: 50,
type: type,
friendly: false,
friendProgress: 0
};
game.creatures.push(creature);
}
// Spawn potion ingredients
function spawnIngredient() {
game.potionIngredients.push({
x: Math.random() * 760 + 20,
y: Math.random() * 200 + 50,
width: 15,
height: 15,
type: ['mushroom', 'herb', 'crystal'][Math.floor(Math.random() * 3)]
});
}
// Collision detection
function checkCollision(a, b) {
return a.x < b.x + b.width &&
a.x + a.width > b.x &&
a.y < b.y + b.height &&
a.y + a.height > b.y;
}
// Update game
let lastTime = Date.now();
let spawnTimer = 0;
let ingredientTimer = 0;
let manaRegenTimer = 0;
let potionBrewTimer = 0;
function update() {
const now = Date.now();
const deltaTime = (now - lastTime) / 1000;
lastTime = now;
// Move player
if (keys['ArrowLeft'] || keys['a'] || keys['A']) {
game.player.x = Math.max(0, game.player.x - game.player.speed);
}
if (keys['ArrowRight'] || keys['d'] || keys['D']) {
game.player.x = Math.min(770, game.player.x + game.player.speed);
}
if (keys['ArrowUp'] || keys['w'] || keys['W']) {
game.player.y = Math.max(0, game.player.y - game.player.speed);
}
if (keys['ArrowDown'] || keys['s'] || keys['S']) {
game.player.y = Math.min(560, game.player.y + game.player.speed);
}
// Mana regeneration
manaRegenTimer += deltaTime;
if (manaRegenTimer >= 0.5) {
game.mana = Math.min(game.maxMana, game.mana + 2);
manaRegenTimer = 0;
}
// Update spells
for (let i = game.spells.length - 1; i >= 0; i--) {
const spell = game.spells[i];
spell.y -= spell.speed;
if (spell.y < -spell.height) {
game.spells.splice(i, 1);
continue;
}
// Check spell-creature collision
for (let j = game.creatures.length - 1; j >= 0; j--) {
const creature = game.creatures[j];
if (checkCollision(spell, creature)) {
creature.health -= spell.damage;
game.spells.splice(i, 1);
// Create hit particles
for (let k = 0; k < 10; k++) {
createParticle(creature.x + creature.width/2, creature.y + creature.height/2, spell.type);
}
if (creature.health <= 0) {
creature.friendly = true;
game.creaturesFriended++;
game.trialProgress++;
// Award new spell
if (game.trialProgress % 3 === 0) {
const newSpells = ['lightning', 'ice', 'nature', 'light'];
const newSpell = newSpells[Math.floor(Math.random() * newSpells.length)];
if (!game.spellsLearned.includes(newSpell)) {
game.spellsLearned.push(newSpell);
}
}
}
break;
}
}
}
// Update creatures
spawnTimer += deltaTime;
if (spawnTimer >= 2) {
spawnCreature();
spawnTimer = 0;
}
for (let i = game.creatures.length - 1; i >= 0; i--) {
const creature = game.creatures[i];
if (!creature.friendly) {
creature.y += creature.speed;
// Creature attacks player
if (checkCollision(creature, game.player)) {
game.player.health -= 0.5;
}
if (creature.y > 600) {
game.creatures.splice(i, 1);
}
} else {
// Friendly creature floats away
creature.y -= 2;
creature.x += Math.sin(creature.y * 0.05) * 2;
if (creature.y < -50) {
game.creatures.splice(i, 1);
}
}
}
// Update particles
for (let i = game.particles.length - 1; i >= 0; i--) {
const p = game.particles[i];
p.x += p.vx;
p.y += p.vy;
p.life--;
if (p.life <= 0) {
game.particles.splice(i, 1);
}
}
// Spawn ingredients
ingredientTimer += deltaTime;
if (ingredientTimer >= 5 && game.potionIngredients.length < 5) {
spawnIngredient();
ingredientTimer = 0;
}
// Collect ingredients
for (let i = game.potionIngredients.length - 1; i >= 0; i--) {
const ingredient = game.potionIngredients[i];
if (checkCollision(game.player, ingredient)) {
game.collectedIngredients.push(ingredient.type);
game.potionIngredients.splice(i, 1);
for (let j = 0; j < 5; j++) {
createParticle(ingredient.x, ingredient.y, 'earth');
}
}
}
// Potion brewing
if (game.potionBrewing) {
potionBrewTimer += deltaTime;
if (potionBrewTimer >= 1) {
game.potionTimer--;
potionBrewTimer = 0;
if (game.potionTimer <= 0) {
game.player.health = Math.min(game.maxHealth, game.player.health + 50);
game.player.mana = game.maxMana;
game.collectedIngredients = [];
game.potionBrewing = false;
}
}
}
// Check trial completion
if (game.trialProgress >= 10) {
game.currentTrial++;
game.trialProgress = 0;
game.player.health = game.maxHealth;
game.player.mana = game.maxMana;
if (game.currentTrial > 5) {
game.currentTrial = 5;
}
}
// Game over check
if (game.player.health <= 0) {
game.player.health = game.maxHealth;
game.player.mana = game.maxMana;
game.currentTrial = 1;
game.trialProgress = 0;
game.creatures = [];
game.spells = [];
}
// Update UI
document.getElementById('health').textContent = Math.floor(game.player.health);
document.getElementById('mana').textContent = Math.floor(game.mana);
document.getElementById('trial').textContent = game.currentTrial;
document.getElementById('spellCount').textContent = game.spellsLearned.length;
document.getElementById('friendCount').textContent = game.creaturesFriended;
}
// Draw game
function draw() {
// Clear canvas
ctx.fillStyle = '#0a0015';
ctx.fillRect(0, 0, 800, 600);
// Draw stars background
ctx.fillStyle = '#ffffff';
for (let i = 0; i < 50; i++) {
const x = (i * 137) % 800;
const y = (i * 197) % 600;
ctx.fillRect(x, y, 2, 2);
}
// Draw potion ingredients
for (const ingredient of game.potionIngredients) {
if (ingredient.type === 'mushroom') {
ctx.fillStyle = '#ff69b4';
} else if (ingredient.type === 'herb') {
ctx.fillStyle = '#32cd32';
} else {
ctx.fillStyle = '#9370db';
}
ctx.beginPath();
ctx.arc(ingredient.x + ingredient.width/2, ingredient.y + ingredient.height/2, ingredient.width/2, 0, Math.PI * 2);
ctx.fill();
}
// Draw player
ctx.fillStyle = '#ffd700';
ctx.fillRect(game.player.x, game.player.y, game.player.width, game.player.height);
// Draw wizard hat
ctx.fillStyle = '#4b0082';
ctx.beginPath();
ctx.moveTo(game.player.x + game.player.width/2, game.player.y - 15);
ctx.lineTo(game.player.x, game.player.y);
ctx.lineTo(game.player.x + game.player.width, game.player.y);
ctx.closePath();
ctx.fill();
// Draw health bar
ctx.fillStyle = '#ff0000';
ctx.fillRect(game.player.x, game.player.y - 10, game.player.width, 5);
ctx.fillStyle = '#00ff00';
ctx.fillRect(game.player.x, game.player.y - 10, game.player.width * (game.player.health / game.maxHealth), 5);
// Draw spells
for (const spell of game.spells) {
const colors = {
fire: '#ff4500',
water: '#1e90ff',
earth: '#8b4513',
air: '#87ceeb'
};
ctx.fillStyle = colors[spell.type] || '#ffd700';
ctx.beginPath();
ctx.arc(spell.x, spell.y, spell.width/2, 0, Math.PI * 2);
ctx.fill();
// Spell glow
ctx.strokeStyle = colors[spell.type] || '#ffd700';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(spell.x, spell.y, spell.width/2 + 3, 0, Math.PI * 2);
ctx.stroke();
}
// Draw creatures
for (const creature of game.creatures) {
if (creature.friendly) {
ctx.fillStyle = '#00ff00';
} else {
ctx.fillStyle = '#ff00ff';
}
// Draw creature body
ctx.fillRect(creature.x, creature.y, creature.width, creature.height);
// Draw creature features based on type
ctx.fillStyle = '#ffffff';
if (creature.type === 'dragon') {
// Wings
ctx.fillRect(creature.x - 10, creature.y + 10, 10, 15);
ctx.fillRect(creature.x + creature.width, creature.y + 10, 10, 15);
} else if (creature.type === 'unicorn') {
// Horn
ctx.beginPath();
ctx.moveTo(creature.x + creature.width/2, creature.y - 10);
ctx.lineTo(creature.x + creature.width/2 - 5, creature.y);
ctx.lineTo(creature.x + creature.width/2 + 5, creature.y);
ctx.closePath();
ctx.fill();
}
// Health bar for creatures
if (!creature.friendly) {
ctx.fillStyle = '#ff0000';
ctx.fillRect(creature.x, creature.y - 8, creature.width, 4);
ctx.fillStyle = '#00ff00';
ctx.fillRect(creature.x, creature.y - 8, creature.width * (creature.health / creature.maxHealth), 4);
}
}
// Draw particles
for (const p of game.particles) {
ctx.fillStyle = p.color;
ctx.globalAlpha = p.life / 30;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fill();
ctx.globalAlpha = 1;
}
// Draw potion brewing indicator
if (game.potionBrewing) {
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
ctx.fillRect(250, 200, 300, 200);
ctx.strokeStyle = '#ffd700';
ctx.lineWidth = 3;
ctx.strokeRect(250, 200, 300, 200);
ctx.fillStyle = '#ffd700';
ctx.font = 'bold 24px Georgia';
ctx.textAlign = 'center';
ctx.fillText('Brewing Potion...', 400, 250);
ctx.fillText(game.potionTimer + 's', 400, 300);
// Cauldron
ctx.fillStyle = '#4b4b4b';
ctx.fillRect(350, 320, 100, 60);
ctx.fillStyle = '#9370db';
ctx.fillRect(360, 330, 80, 40);
}
// Draw spell selection indicator
ctx.fillStyle = '#ffd700';
ctx.font = 'bold 16px Georgia';
ctx.textAlign = 'left';
ctx.fillText('Selected: ' + game.selectedSpell.toUpperCase(), 10, 580);
// Draw ingredient count
ctx.fillText('Ingredients: ' + game.collectedIngredients.length + '/3', 10, 560);
// Draw trial progress
ctx.fillStyle = '#ffd700';
ctx.fillRect(250, 20, 300, 20);
ctx.fillStyle = '#00ff00';
ctx.fillRect(250, 20, 300 * (game.trialProgress / 10), 20);
ctx.strokeStyle = '#ffd700';
ctx.lineWidth = 2;
ctx.strokeRect(250, 20, 300, 20);
ctx.fillStyle = '#ffd700';
ctx.font = 'bold 14px Georgia';
ctx.textAlign = 'center';
ctx.fillText('Trial Progress: ' + game.trialProgress + '/10', 400, 35);
// Graduation message
if (game.currentTrial === 5 && game.trialProgress >= 10) {
ctx.fillStyle = 'rgba(0, 0, 0, 0.8)';
ctx.fillRect(150, 200, 500, 200);
ctx.strokeStyle = '#ffd700';
ctx.lineWidth = 4;
ctx.strokeRect(150, 200, 500, 200);
ctx.fillStyle = '#ffd700';
ctx.font = 'bold 32px Georgia';
ctx.textAlign = 'center';
ctx.fillText('🎓 GRADUATED! 🎓', 400, 260);
ctx.font = 'bold 18px Georgia';
ctx.fillText('You are now a Master Wizard!', 400, 300);
ctx.fillText('Spells Mastered: ' + game.spellsLearned.length, 400, 330);
ctx.fillText('Creatures Befriended: ' + game.creaturesFriended, 400, 360);
}
}
// Game loop
function gameLoop() {
update();
draw();
requestAnimationFrame(gameLoop);
}
gameLoop();
} catch(e) {
document.body.innerHTML = '<div style="color:white;padding:20px;text-align:center;">Game error: ' + e.message + '<br><br>Please refresh the page.</div>';
console.error(e);
}
});
</script>
</body>
</html>
Install GB3A on your device for a better experience!