Let’s create a Toast Catcher Game using HTML, CSS, and JavaScript! 🍞🎮
This fun and simple game challenges players to catch falling toasts using a moving plate or character.
We’ll use:
- HTML to set up the structure of the game – the toasts, catcher, and score.
- CSS to style the game with a cute and playful look.
- JavaScript to handle the game logic like toast movement, collision detection, and scoring.
This project is great for beginners learning how to build interactive games, and it’s also a fun way to practice animation and event handling in JavaScript. Let’s get started and catch some toasts!
HTML :
This HTML code sets up a simple web-based “Toast Catcher Game” using SVG graphics. It includes a styled game screen with a background, score display, life display, game-over screen, and toast elements (with wings) as part of the game visuals. The actual game logic would be handled in separate CSS and JavaScript files.
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>Toast Catcher Game | @coding.stella</title> <link rel="stylesheet" href="./style.css"> </head> <body> <div class="frame"> <svg id="game" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="450" height="680" fill="none" viewBox="0 0 450 680"> <path fill="#7DC8CF" d="M0 1h450v680H0z"/> <path fill="#976F4A" d="M0 0h450v80H0z"/> <path fill="#FDC571" d="M0 631h450v50H0z"/> <path fill="#67442B" d="M0 74h450v6H0z"/> <rect width="430" height="54" x="10" y="10" fill="#67442B" rx="12"/> <path xmlns="http://www.w3.org/2000/svg" fill="#FFE2B4" d="M391.652 25.303c3.524-3.523 9.148-3.665 12.842-.427l.017-.016.352-.334a9.407 9.407 0 0 1 13.285 13.286l-.333.352-13.303 13.303-13.304-13.304.016-.017c-3.238-3.695-3.097-9.318.428-12.843Z"/> <g fill="#FEDAA1" font="inherit" > <text id="score" x="25" y="46" >00000000</text> <text id="lives" x="345" y="46" font="inherit" ></text> </g> <path fill="#FEECBF" d="M104.139 183.699c1.5-19.5-32-23-32-1.5-15.5-5.5-20.5 13.5-12.5 16 14.5 0 43.5.5 55 .5 10.5-4-.5-22-10.5-15Zm295.5-2c1.642-21.263-33-24.5-34.5-3.5-18.5-6-24.258 16.956-15.5 19.682h60.837c11.495-4.362.111-23.815-10.837-16.182ZM93.078 379.908c1.792-23.22-34.939-29.209-41.439-2.209-16.5-8-22.677 16.903-13.12 19.88h66.384c12.543-4.763.121-26.007-11.825-17.671Zm192.561-69.209c1.295-16-22.804-22.105-27.5-3.5-11.919-5.513-18.639 12.448-11.736 14.5h47.954c9.061-3.282-.089-16.744-8.718-11Zm16 232.5c1.307-16.633-24.76-21.841-29.5-2.5-12.033-5.731-18.163 12.839-11.194 14.971h48.413c10.281-3.471.993-18.442-7.719-12.471Z"/> <g font-size="36" id="game-over-screen" pointer-events="none" visibility="hidden" > <text x="225" y="220" text-anchor="middle" stroke="#603719" stroke-width="10">GAME OVER</text> <text x="225" y="220" text-anchor="middle" fill="#f16f33">GAME OVER</text> <text id="final-score-info" x="225" y="260" text-anchor="middle" font-size="24" fill="white">Final Score: 0</text> </g> <!-- symbols --> <symbol id="toast" xmlns="http://www.w3.org/2000/svg" width="95" height="57" viewBox="0 0 95 57"> <path class="toast__wings" fill="#FDE2A9" stroke="#7F3412" stroke-linejoin="round" stroke-width="3" d="M3.793 18.165c.905-.484 1.938-.526 2.887-.399 1.88.252 4.141 1.27 6.375 2.527 3.967 2.234 8.385 5.539 11.558 8.103l1.279 1.048.105.096a1.5 1.5 0 0 1 .424.87l1.47 11.701a1.5 1.5 0 0 1-.432 1.254c-3.981 3.94-8.147 4.232-10.628 2.541-1.168-.796-2.067-2.187-1.735-3.753.053-.25.135-.483.24-.702-1.743-.454-3.15-1.018-4.257-1.658-1.747-1.01-2.903-2.31-3.22-3.799-.292-1.363.181-2.602 1.058-3.47-1.424-.708-2.823-1.57-4-2.646-2.349-2.147-3.818-5.157-2.921-9.21l.05-.2c.265-.997.838-1.817 1.747-2.303Zm85.793-2.258c-1.486-.17-3.23.45-4.847 1.238-2.93 1.426-6.42 3.904-9.438 6.2l-1.26.971-.133.116a1.5 1.5 0 0 0-.448 1.1l.251 12.107a1.5 1.5 0 0 0 1.44 1.468c3.919.158 6.967-.368 9.192-1.296 2.19-.913 3.742-2.294 4.306-3.937.288-.837.307-1.725.002-2.556-.304-.828-.892-1.499-1.647-1.973a5.05 5.05 0 0 0-.67-.351 23.515 23.515 0 0 0 2.936-2.553c1.003-1.038 1.868-2.154 2.475-3.29.6-1.126.998-2.366.924-3.61-.055-.913-.297-1.79-.868-2.481-.595-.72-1.4-1.06-2.215-1.153Z"/> <mask id="a" fill="#fff"> <path d="M63.941.713c6.616-.394 12.298 4.65 12.692 11.266l.12 2.016a12.94 12.94 0 0 1-1.657 7.165l1.421 23.884a8 8 0 0 1-7.51 8.461l-34.86 2.074a8 8 0 0 1-8.461-7.511l-1.343-22.575a12.946 12.946 0 0 1-3.543-8.17l-.06-1.017c-.427-7.167 5.038-13.323 12.204-13.75L63.941.714Z"/> </mask> <path fill="#C7511B" d="M63.941.713c6.616-.394 12.298 4.65 12.692 11.266l.12 2.016a12.94 12.94 0 0 1-1.657 7.165l1.421 23.884a8 8 0 0 1-7.51 8.461l-34.86 2.074a8 8 0 0 1-8.461-7.511l-1.343-22.575a12.946 12.946 0 0 1-3.543-8.17l-.06-1.017c-.427-7.167 5.038-13.323 12.204-13.75L63.941.714Z"/> <path fill="#7E3112" d="m63.941.713-.178-2.995.178 2.995Zm12.692 11.266-2.995.178 2.995-.178Zm.12 2.016 2.994-.178-2.994.178Zm-1.657 7.165-2.61-1.478a2.999 2.999 0 0 0-.385 1.656l2.995-.178Zm1.421 23.884 2.995-.178-2.995.178Zm-50.831 3.024-2.995.178 2.995-.178Zm-1.343-22.575 2.995-.178a3 3 0 0 0-.819-1.887l-2.176 2.065Zm-3.543-8.17-2.995.179 2.995-.179Zm-.06-1.017-2.995.178 2.994-.178Zm12.204-13.75-.178-2.994.178 2.995ZM63.941.714l.178 2.994a9 9 0 0 1 9.52 8.45l2.994-.178 2.995-.178c-.493-8.27-7.595-14.575-15.865-14.083l.178 2.995ZM76.633 11.98l-2.995.178.12 2.016 2.995-.178 2.994-.178-.12-2.016-2.994.178Zm.12 2.016-2.995.178a9.94 9.94 0 0 1-1.273 5.509l2.611 1.478 2.611 1.477a15.938 15.938 0 0 0 2.04-8.82l-2.994.178Zm-1.657 7.165-2.995.178 1.421 23.884 2.995-.178 2.995-.178L78.09 20.98l-2.995.178Zm1.421 23.884-2.995.178a5 5 0 0 1-4.694 5.288l.178 2.995.178 2.995c6.065-.361 10.689-5.57 10.328-11.634l-2.995.178Zm-7.51 8.461-.179-2.995-34.86 2.074.179 2.995.178 2.995 34.86-2.074-.179-2.995Zm-34.86 2.074-.178-2.995a5 5 0 0 1-5.288-4.694l-2.995.178-2.995.178c.361 6.064 5.57 10.688 11.634 10.328l-.178-2.995Zm-8.461-7.511 2.995-.178-1.343-22.576-2.995.179-2.995.178 1.343 22.575 2.995-.178Zm-1.343-22.575 2.176-2.065a9.946 9.946 0 0 1-2.724-6.283l-2.995.178-2.995.179a15.945 15.945 0 0 0 4.362 10.055l2.176-2.064Zm-3.543-8.17 2.995-.178-.06-1.017-2.996.178-2.994.178.06 1.018 2.995-.179Zm-.06-1.017 2.994-.178c-.328-5.513 3.875-10.249 9.389-10.577l-.179-2.994-.178-2.995c-8.82.525-15.546 8.1-15.021 16.922l2.994-.178Zm12.204-13.75.179 2.995L64.12 3.707 63.94.713l-.178-2.995L32.766-.438l.178 2.995Z" mask="url(#a)"/> <mask id="b" fill="#fff"> <path d="M64.353 3.719a9 9 0 0 1 9.518 8.45l.177 2.969a10.949 10.949 0 0 1-1.721 6.587l1.39 23.368a5 5 0 0 1-4.694 5.288l-32.78 1.95a5 5 0 0 1-5.288-4.694l-1.362-22.894a10.953 10.953 0 0 1-2.882-6.789l-.058-.973c-.36-6.064 4.263-11.273 10.327-11.634L64.353 3.72Z"/> </mask> <path fill="#FEBB63" d="M64.353 3.719a9 9 0 0 1 9.518 8.45l.177 2.969a10.949 10.949 0 0 1-1.721 6.587l1.39 23.368a5 5 0 0 1-4.694 5.288l-32.78 1.95a5 5 0 0 1-5.288-4.694l-1.362-22.894a10.953 10.953 0 0 1-2.882-6.789l-.058-.973c-.36-6.064 4.263-11.273 10.327-11.634L64.353 3.72Z"/> <path fill="#F78E39" d="M64.353 3.719 64.175.724l.178 2.995Zm9.695 11.419 2.995-.178-2.995.178Zm-1.721 6.587-2.525-1.62a3 3 0 0 0-.47 1.799l2.995-.179Zm1.39 23.368 2.995-.178-2.995.178Zm-4.694 5.288.178 2.995-.178-2.995Zm-32.78 1.95.178 2.995-.178-2.995Zm-5.288-4.694-2.995.178 2.995-.178Zm-1.362-22.894 2.994-.178a3 3 0 0 0-.787-1.853l-2.207 2.031Zm-2.882-6.789-2.995.178 2.995-.178ZM36.98 5.347l-.179-2.994.178 2.994ZM64.352 3.72l.178 2.995a6 6 0 0 1 6.346 5.633l2.994-.178 2.995-.179C76.473 5.375 70.79.33 64.175.724l.178 2.995Zm9.518 8.45-2.994.178.176 2.969 2.995-.178 2.995-.178-.177-2.97-2.995.178Zm.177 2.969-2.995.178a7.949 7.949 0 0 1-1.25 4.789l2.524 1.62 2.524 1.621a13.947 13.947 0 0 0 2.192-8.386l-2.995.178Zm-1.721 6.587-2.995.178 1.39 23.368 2.995-.178 2.995-.178-1.39-23.368-2.995.178Zm1.39 23.368-2.995.178a2 2 0 0 1-1.877 2.116l.178 2.994.178 2.995a8 8 0 0 0 7.51-8.46l-2.994.177Zm-4.694 5.288-.178-2.994-32.78 1.95.178 2.994.178 2.995 32.78-1.95-.178-2.995Zm-32.78 1.95-.178-2.994a2 2 0 0 1-2.116-1.878l-2.994.178-2.995.179a8 8 0 0 0 8.46 7.51l-.177-2.995Zm-5.288-4.694 2.994-.178-1.361-22.894-2.995.178-2.995.178 1.362 22.894 2.995-.178Zm-1.362-22.894 2.207-2.031a7.954 7.954 0 0 1-2.094-4.936l-2.995.178-2.995.178a13.953 13.953 0 0 0 3.669 8.642l2.208-2.031Zm-2.882-6.789 2.995-.178-.058-.973-2.995.178-2.995.178.058.973 2.995-.178Zm-.058-.973 2.995-.178a8 8 0 0 1 7.51-8.461l-.178-2.995-.178-2.994C29.084 2.812 23.2 9.44 23.658 17.159l2.995-.178ZM36.98 5.347l.178 2.995 27.373-1.628-.178-2.995-.178-2.995-27.373 1.629.178 2.994Z" mask="url(#b)"/> <path stroke="#7F3412" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M49.28 31.137c2.615 1.848 5.61 1.67 7.488-.445"/> <g class="toast__eyes"> <ellipse cx="61.42" cy="25.123" fill="#7F3412" rx="2.5" ry="3.5" transform="rotate(-3.404 61.42 25.123)"/> <ellipse cx="42.994" cy="26.502" fill="#7F3412" rx="2.5" ry="3.5" transform="rotate(-3.404 42.994 26.502)"/> </g> </symbol> </svg> </div> <script src="./script.js"></script> </body> </html>
CSS :
This CSS styles a fun, animated toast character centered on the screen. It uses SVG
with animated wings (scale
to simulate flapping) and blinking eyes. The layout is fully centered using CSS Grid, wrapped in a brown-framed box. The toast is clickable, non-selectable, and visually playful with smooth, infinite animations.
:root { background-color: #7DC8CF; font-family: system-ui; font-variant-numeric: tabular-nums; } *, :after, :before { box-sizing: border-box; } svg { display: block; font-size: 1.5rem; font-weight: 900; max-width: 100%; height: auto; max-height: 100%; } body { height: 100vh; margin: 0; display: grid; place-items: center; background: lightblue; } .frame { border: 6px solid #67442b; border-radius: 16px; background: #67442b; } #game { border-radius: 10px; user-select: none; } .toast { cursor: pointer; } .toast__wings { animation: wings-flapping linear infinite 0.4s; transform-origin: center 85%; pointer-events: none; } .toast__eyes { animation: blink linear infinite 2s; transform-origin: 15px; } @keyframes wings-flapping { 0%, 100% { scale: 1 1; } 50% { scale: 1 0.8; } } @keyframes blink { 0%, 90% { scale: 1 1; } 100% { scale: 1 0; } }
JavaScript:
This JavaScript code defines a Game
class that creates a fun toast-catching game using SVG elements. Toasts animate in an arc and fall – the player must click them before they hit the bottom. Each click increases the score, and missing one decreases lives. The game ends when lives reach zero, showing a final score screen. Toasts spawn faster over time to increase difficulty.
class Game { constructor() { this.svg = document.getElementById('game') this.toastSymbolId = '#toast' this.scoreEl = document.getElementById('score') this.livesEl = document.getElementById('lives') this.finalScoreInfoEl = document.getElementById('final-score-info') this.gameOverScreenEl = document.getElementById('game-over-screen') this.toasts = [] this.score = 0 this.spawnInterval = 2000 this.remainingLives = 5 this.gameOver = false this.gameStartTime = performance.now() this.loop = this.loop.bind(this) this.spawnToast() this.startSpawnTimer() this.updateLives() requestAnimationFrame(this.loop) } startSpawnTimer() { if (this.spawnTimer) { clearInterval(this.spawnTimer) } const gameTimeSeconds = (performance.now() - this.gameStartTime) / 1000 this.spawnInterval = Math.max(500, 2000 - Math.floor(gameTimeSeconds / 10) * 100) this.spawnTimer = setInterval(() => { if (!this.gameOver) { this.spawnToast() this.startSpawnTimer() } }, this.spawnInterval) } spawnToast() { if (this.gameOver) return const startX = Math.random() * 350 + 25 const endX = Math.random() * 350 + 25 const peakY = 200 + Math.random() * 50 const toast = document.createElementNS('http://www.w3.org/2000/svg', 'use') toast.setAttribute('href', this.toastSymbolId) toast.setAttribute('class', 'toast') toast.setAttribute('x', startX) toast.setAttribute('y', 680) this.svg.appendChild(toast) const toastObj = { el: toast, startX, endX, startY: 680, peakY, startTime: performance.now(), duration: 3000, clicked: false, upwardSpeed: -8, reachedBottom: false } toast.addEventListener('pointerdown', () => { if (!this.gameOver && !toastObj.clicked) { this.score += 1 this.scoreEl.textContent = this.score.toString().padStart(8, '0') toastObj.clicked = true } }) this.toasts.push(toastObj) } checkGameOver() { if (this.remainingLives <= 0) { this.gameOver = true clearInterval(this.spawnTimer) this.gameOverScreenEl.setAttribute('visibility','visible') this.finalScoreInfoEl.textContent = `Final Score: ${this.score}` } } loop(timestamp) { if (this.gameOver) { requestAnimationFrame(this.loop) return } this.toasts = this.toasts.filter(toast => { const t = (timestamp - toast.startTime) / toast.duration if (toast.clicked) { const currentY = parseFloat(toast.el.getAttribute('y')) const newY = currentY + toast.upwardSpeed toast.el.setAttribute('y', newY) toast.el.setAttribute('pointer-events', 'none') if (newY < -50) { toast.el.remove() return false } } else { if (t > 1) { if (!toast.reachedBottom) { this.remainingLives-- this.updateLives() this.checkGameOver() toast.reachedBottom = true } toast.el.remove() return false } const x = toast.startX + (toast.endX - toast.startX) * t const y = toast.startY - (4 * t * (1 - t)) * (toast.startY - toast.peakY) toast.el.setAttribute('x', x) toast.el.setAttribute('y', y) } return true }) requestAnimationFrame(this.loop) } updateLives(){ this.livesEl.textContent = `${this.remainingLives}X` } } const game = new Game()
In conclusion, the Toast Catcher Game is a fun way to practice HTML, CSS, and JavaScript. With simple mechanics, cute visuals, and interactive gameplay, it’s a great project to improve your coding skills while having a good time. Keep creating and make your own fun games! 🕹️🍞
If your project has problems, don’t worry. Just click to download the source code and face your coding challenges with excitement. Have fun coding!