🐸 FROG JUMP
Tap anywhere or press Spacebar to jump over obstacles and help the frog travel safely! 🌸
💀 GAME OVER
You bumped into an obstacle! Try again?
Final Score: 0 🌸
🎮 How to Play
- Tap/Click the screen or press **Spacebar / Up Arrow** to make the frog jump.
- Avoid running into obstacles like ladybugs 🐞 and spikes 🌵.
- Earn points for every obstacle you successfully jump over!
// {
(function() {
const canvas = document.getElementById(‘frogCanvas’);
const ctx = canvas.getContext(‘2d’);
const gameCard = document.getElementById(‘frogGameCard’);
const fullscreenBtn = document.getElementById(‘frog-fullscreen-btn’);
const startOverlay = document.getElementById(‘frogStartOverlay’);
const startBtn = document.getElementById(‘frogStartBtn’);
const overOverlay = document.getElementById(‘frogOverOverlay’);
const restartBtn = document.getElementById(‘frogRestartBtn’);
const scoreVal = document.getElementById(‘frog-score’);
const bestVal = document.getElementById(‘frog-best’);
const finalScoreVal = document.getElementById(‘finalFrogScore’);
let score = 0;
let highScore = parseInt(localStorage.getItem(‘ff_frog_best’) || ‘0’, 10);
bestVal.textContent = highScore;
let gameStarted = false;
let gameOver = false;
let obstacles = [];
let obstacleTimer = 0;
let speed = 4;
// Physics
const gravity = 0.6;
const frog = {
x: 80,
y: 320,
w: 44,
h: 44,
vy: 0,
jumpPower: -13,
groundY: 320,
isJumping: false
};
// Web Audio Synthesizer
let audioCtx = null;
function playSound(type) {
try {
if (!audioCtx) {
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
}
if (audioCtx.state === ‘suspended’) {
audioCtx.resume();
}
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.connect(gain);
gain.connect(audioCtx.destination);
if (type === ‘jump’) {
osc.type = ‘triangle’;
osc.frequency.setValueAtTime(150, audioCtx.currentTime);
osc.frequency.exponentialRampToValueAtTime(400, audioCtx.currentTime + 0.15);
gain.gain.setValueAtTime(0.15, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.18);
osc.start();
osc.stop(audioCtx.currentTime + 0.18);
} else if (type === ‘score’) {
osc.type = ‘sine’;
osc.frequency.setValueAtTime(523.25, audioCtx.currentTime); // C5
osc.frequency.setValueAtTime(659.25, audioCtx.currentTime + 0.08); // E5
gain.gain.setValueAtTime(0.1, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.2);
osc.start();
osc.stop(audioCtx.currentTime + 0.2);
} else if (type === ‘crash’) {
osc.type = ‘sawtooth’;
osc.frequency.setValueAtTime(180, audioCtx.currentTime);
osc.frequency.linearRampToValueAtTime(60, audioCtx.currentTime + 0.4);
gain.gain.setValueAtTime(0.2, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.45);
osc.start();
osc.stop(audioCtx.currentTime + 0.45);
}
} catch (e) {
// Audio context failed
}
}
function jump() {
if (!gameStarted || gameOver) return;
if (!frog.isJumping) {
frog.vy = frog.jumpPower;
frog.isJumping = true;
playSound(‘jump’);
}
}
// Input handlers
canvas.addEventListener(‘click’, (e) => {
e.preventDefault();
jump();
});
canvas.addEventListener(‘touchstart’, (e) => {
e.preventDefault();
jump();
}, { passive: false });
window.addEventListener(‘keydown’, (e) => {
if (e.code === ‘Space’ || e.code === ‘ArrowUp’) {
if (gameStarted && !gameOver) {
e.preventDefault();
jump();
}
}
});
// Start buttons
startBtn.addEventListener(‘click’, () => {
enterFullscreen();
startOverlay.style.display = ‘none’;
gameStarted = true;
resetGame();
});
restartBtn.addEventListener(‘click’, () => {
enterFullscreen();
overOverlay.style.display = ‘none’;
gameOver = false;
gameStarted = true;
resetGame();
});
// Fullscreen Mode
const container = canvas.parentElement;
function applyFSStyles() {
const s = gameCard.style;
s.setProperty(‘display’, ‘flex’, ‘important’);
s.setProperty(‘flex-direction’, ‘column’, ‘important’);
s.setProperty(‘overflow’, ‘visible’, ‘important’);
s.setProperty(‘width’, ‘100vw’, ‘important’);
s.setProperty(‘max-width’, ‘100vw’, ‘important’);
s.setProperty(‘height’, ‘100vh’, ‘important’);
s.setProperty(‘max-height’, ‘100vh’, ‘important’);
s.setProperty(‘padding’, ’12px’, ‘important’);
s.setProperty(‘margin’, ‘0’, ‘important’);
s.setProperty(‘box-sizing’, ‘border-box’, ‘important’);
s.setProperty(‘border’, ‘none’, ‘important’);
s.setProperty(‘border-radius’, ‘0’, ‘important’);
s.setProperty(‘box-shadow’, ‘none’, ‘important’);
s.setProperty(‘background’, ‘#bae6fd’, ‘important’);
const cs = container.style;
cs.setProperty(‘flex’, ‘1 1 0’, ‘important’);
cs.setProperty(‘min-height’, ‘0’, ‘important’);
cs.setProperty(‘height’, ‘0’, ‘important’);
cs.setProperty(‘width’, ‘100%’, ‘important’);
cs.setProperty(‘display’, ‘flex’, ‘important’);
cs.setProperty(‘align-items’, ‘center’, ‘important’);
cs.setProperty(‘justify-content’, ‘center’, ‘important’);
cs.setProperty(‘overflow’, ‘hidden’, ‘important’);
canvas.style.setProperty(‘width’, ‘auto’, ‘important’);
canvas.style.setProperty(‘height’, ‘100%’, ‘important’);
canvas.style.setProperty(‘max-width’, ‘100%’, ‘important’);
canvas.style.setProperty(‘max-height’, ‘100%’, ‘important’);
canvas.style.setProperty(‘margin’, ‘0 auto’, ‘important’);
document.body.classList.add(‘funful-scroll-locked’);
if (fullscreenBtn) fullscreenBtn.innerHTML = ‘✕ Exit’;
}
function removeFSStyles() {
gameCard.style.cssText = ”;
container.style.cssText = ”;
canvas.style.cssText = ”;
if (fullscreenBtn) {
fullscreenBtn.style.cssText = ”;
fullscreenBtn.innerHTML = ‘📱’;
}
document.body.classList.remove(‘funful-scroll-locked’);
}
function enterFullscreen() {
if (!document.fullscreenElement && !document.webkitFullscreenElement) {
if (gameCard.requestFullscreen) {
gameCard.requestFullscreen().catch(() => { applyFSStyles(); });
} else if (gameCard.webkitRequestFullscreen) {
gameCard.webkitRequestFullscreen();
} else {
applyFSStyles();
}
}
}
function toggleFullscreen() {
const isFull = document.fullscreenElement || document.webkitFullscreenElement;
if (!isFull) {
enterFullscreen();
} else {
if (document.exitFullscreen) document.exitFullscreen().catch(() => {});
else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
removeFSStyles();
}
}
if (fullscreenBtn) fullscreenBtn.onclick = toggleFullscreen;
[‘fullscreenchange’, ‘webkitfullscreenchange’].forEach(evt => {
document.addEventListener(evt, () => {
if (document.fullscreenElement || document.webkitFullscreenElement) {
requestAnimationFrame(() => applyFSStyles());
} else {
removeFSStyles();
}
});
});
function resetGame() {
score = 0;
scoreVal.textContent = ‘0’;
speed = 4.5;
obstacles = [];
obstacleTimer = 0;
frog.y = frog.groundY;
frog.vy = 0;
frog.isJumping = false;
}
function spawnObstacle() {
const types = [‘🐞’, ‘🌵’, ‘🍄’, ‘🌸’];
const type = types[Math.floor(Math.random() * 4)];
obstacles.push({
x: canvas.width,
y: frog.groundY + 12,
w: 32,
h: 32,
type: type,
passed: false
});
}
function update() {
if (!gameStarted || gameOver) return;
// Apply gravity
frog.vy += gravity;
frog.y += frog.vy;
// Ground constraint
if (frog.y >= frog.groundY) {
frog.y = frog.groundY;
frog.vy = 0;
frog.isJumping = false;
}
// Spawn obstacles
obstacleTimer++;
if (obstacleTimer > 85 + Math.random() * 40) {
spawnObstacle();
obstacleTimer = 0;
}
// Move obstacles
for (let i = obstacles.length – 1; i >= 0; i–) {
const obs = obstacles[i];
obs.x -= speed;
// Score point
if (obs.x + obs.w highScore) {
highScore = score;
bestVal.textContent = highScore;
localStorage.setItem(‘ff_frog_best’, highScore.toString());
}
// Gradually increase speed
if (score % 5 === 0) {
speed += 0.5;
}
}
// Remove off-screen obstacles
if (obs.x + obs.w < 0) {
obstacles.splice(i, 1);
continue;
}
// Simple box collision
const padding = 6;
if (frog.x + padding obs.x + padding &&
frog.y + padding obs.y + padding) {
gameOver = true;
playSound(‘crash’);
finalScoreVal.textContent = score;
overOverlay.style.display = ‘flex’;
}
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Sky background gradient
const skyGrad = ctx.createLinearGradient(0, 0, 0, canvas.height);
skyGrad.addColorStop(0, ‘#bae6fd’);
skyGrad.addColorStop(1, ‘#e0f2fe’);
ctx.fillStyle = skyGrad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Ground
ctx.fillStyle = ‘#10b981’;
ctx.fillRect(0, 360, canvas.width, 40);
ctx.fillStyle = ‘#059669′;
ctx.fillRect(0, 360, canvas.width, 6);
// Draw Frog Player
ctx.save();
ctx.font = ’40px sans-serif’;
ctx.textAlign = ‘center’;
ctx.textBaseline = ‘middle’;
ctx.fillText(‘🐸’, frog.x + frog.w/2, frog.y + frog.h/2);
ctx.restore();
// Draw Obstacles
obstacles.forEach(obs => {
ctx.save();
ctx.font = ’30px sans-serif’;
ctx.textAlign = ‘center’;
ctx.textBaseline = ‘middle’;
ctx.fillText(obs.type, obs.x + obs.w/2, obs.y + obs.h/2);
ctx.restore();
});
}
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
loop();
})();
};
if (document.readyState === ‘loading’) {
document.addEventListener(‘DOMContentLoaded’, initFrogGame);
} else {
initFrogGame();
}
// ]]>