Created
December 30, 2025 02:01
-
-
Save wwtv127/05d8d031c0bec600bd19ce57b248ed33 to your computer and use it in GitHub Desktop.
R1 Artifact: My Project
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
| <title>Flappy R1</title> | |
| <style> | |
| body, html { | |
| margin: 0; | |
| padding: 0; | |
| width: 240px; | |
| height: 282px; | |
| overflow: hidden; | |
| background-color: #70c5ce; | |
| font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; | |
| touch-action: none; | |
| user-select: none; | |
| -webkit-user-select: none; | |
| } | |
| #game-container { | |
| position: relative; | |
| width: 240px; | |
| height: 282px; | |
| overflow: hidden; | |
| background: linear-gradient(#70c5ce, #4fb0ba); | |
| } | |
| #bird { | |
| position: absolute; | |
| width: 20px; | |
| height: 16px; | |
| background-color: #f7d302; | |
| border: 2px solid #000; | |
| border-radius: 4px; | |
| left: 40px; | |
| top: 133px; /* Center (282/2 - 8) */ | |
| z-index: 10; | |
| will-change: transform; | |
| transform: translateZ(0); | |
| } | |
| #bird::after { | |
| content: ''; | |
| position: absolute; | |
| right: 2px; | |
| top: 2px; | |
| width: 4px; | |
| height: 4px; | |
| background: black; | |
| border-radius: 50%; | |
| } | |
| .pipe { | |
| position: absolute; | |
| width: 30px; | |
| background-color: #73bf2e; | |
| border: 2px solid #000; | |
| z-index: 5; | |
| will-change: transform; | |
| transform: translateZ(0); | |
| } | |
| #score-display { | |
| position: absolute; | |
| top: 10px; | |
| width: 100%; | |
| text-align: center; | |
| font-size: 24px; | |
| font-weight: bold; | |
| color: white; | |
| text-shadow: 2px 2px #000; | |
| z-index: 20; | |
| pointer-events: none; | |
| } | |
| #overlay { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 240px; | |
| height: 282px; | |
| background: rgba(0,0,0,0.7); | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| color: white; | |
| z-index: 30; | |
| text-align: center; | |
| } | |
| .btn { | |
| background: #ff4d00; | |
| border: 2px solid white; | |
| padding: 12px 24px; | |
| color: white; | |
| border-radius: 8px; | |
| font-size: 18px; | |
| font-weight: bold; | |
| margin-top: 15px; | |
| cursor: pointer; | |
| box-shadow: 0 4px #992e00; | |
| touch-action: manipulation; | |
| } | |
| .btn:active { | |
| transform: translateY(2px); | |
| box-shadow: 0 2px #992e00; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="game-container"> | |
| <div id="score-display">0</div> | |
| <div id="bird"></div> | |
| <div id="overlay"> | |
| <h2 id="msg" style="margin: 0; font-size: 28px;">FLAPPY R1</h2> | |
| <p style="margin: 5px 0;">Tap Screen to Fly</p> | |
| <div class="btn" id="start-btn">START</div> | |
| </div> | |
| </div> | |
| <script> | |
| const bird = document.getElementById('bird'); | |
| const container = document.getElementById('game-container'); | |
| const scoreDisplay = document.getElementById('score-display'); | |
| const overlay = document.getElementById('overlay'); | |
| const msg = document.getElementById('msg'); | |
| const startBtn = document.getElementById('start-btn'); | |
| const GRAVITY = 0.22; | |
| const FLAP = -4.0; | |
| const SPAWN_RATE = 1600; | |
| const PIPE_SPEED = 2; | |
| const GAP = 95; | |
| let birdY = 133; | |
| let birdV = 0; | |
| let score = 0; | |
| let gameActive = false; | |
| let pipes = []; | |
| let lastTime = 0; | |
| let spawnTimer = 0; | |
| function resetGame() { | |
| // Clean existing pipes | |
| pipes.forEach(p => { | |
| if (p.top && p.top.parentNode) p.top.remove(); | |
| if (p.bottom && p.bottom.parentNode) p.bottom.remove(); | |
| }); | |
| pipes = []; | |
| birdY = 133; | |
| birdV = 0; | |
| score = 0; | |
| spawnTimer = 0; | |
| scoreDisplay.innerText = '0'; | |
| // Hide overlay | |
| overlay.style.display = 'none'; | |
| // Final prep before loop | |
| lastTime = performance.now(); | |
| gameActive = true; | |
| requestAnimationFrame(gameLoop); | |
| } | |
| function createPipe() { | |
| const minHeight = 40; | |
| const availableSpace = 282 - GAP; | |
| const topHeight = Math.floor(Math.random() * (availableSpace - 2 * minHeight)) + minHeight; | |
| const topPipe = document.createElement('div'); | |
| topPipe.className = 'pipe'; | |
| topPipe.style.height = topHeight + 'px'; | |
| topPipe.style.top = '0'; | |
| topPipe.style.left = '240px'; | |
| const bottomPipe = document.createElement('div'); | |
| bottomPipe.className = 'pipe'; | |
| bottomPipe.style.height = (282 - topHeight - GAP) + 'px'; | |
| bottomPipe.style.bottom = '0'; | |
| bottomPipe.style.left = '240px'; | |
| container.appendChild(topPipe); | |
| container.appendChild(bottomPipe); | |
| pipes.push({ | |
| x: 240, | |
| top: topPipe, | |
| bottom: bottomPipe, | |
| passed: false | |
| }); | |
| } | |
| function gameOver() { | |
| gameActive = false; | |
| msg.innerText = "GAME OVER"; | |
| overlay.style.display = 'flex'; | |
| } | |
| function gameLoop(timestamp) { | |
| if (!gameActive) return; | |
| const deltaTime = timestamp - lastTime; | |
| lastTime = timestamp; | |
| // Physics | |
| birdV += GRAVITY; | |
| birdY += birdV; | |
| // Visuals | |
| const rotation = Math.min(Math.max(birdV * 4, -25), 90); | |
| bird.style.transform = `translateY(${birdY - 133}px) rotate(${rotation}deg)`; | |
| // Collision: Floor/Ceiling | |
| if (birdY < -10 || birdY > 270) { | |
| gameOver(); | |
| return; | |
| } | |
| // Spawning | |
| spawnTimer += deltaTime; | |
| if (spawnTimer >= SPAWN_RATE) { | |
| createPipe(); | |
| spawnTimer = 0; | |
| } | |
| // Pipe movement and logic | |
| for (let i = pipes.length - 1; i >= 0; i--) { | |
| let p = pipes[i]; | |
| p.x -= PIPE_SPEED; | |
| p.top.style.transform = `translateX(${p.x - 240}px)`; | |
| p.bottom.style.transform = `translateX(${p.x - 240}px)`; | |
| // Collision Detection | |
| if (p.x < 60 && p.x > 10) { | |
| const topPipeBottom = parseInt(p.top.style.height); | |
| const bottomPipeTop = 282 - parseInt(p.bottom.style.height); | |
| if (birdY < topPipeBottom || (birdY + 16) > bottomPipeTop) { | |
| gameOver(); | |
| return; | |
| } | |
| } | |
| // Scoring | |
| if (!p.passed && p.x < 40) { | |
| p.passed = true; | |
| score++; | |
| scoreDisplay.innerText = score; | |
| } | |
| // GC | |
| if (p.x < -40) { | |
| p.top.remove(); | |
| p.bottom.remove(); | |
| pipes.splice(i, 1); | |
| } | |
| } | |
| requestAnimationFrame(gameLoop); | |
| } | |
| // High compatibility button handling | |
| const handleStart = (e) => { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| if (!gameActive) { | |
| resetGame(); | |
| } | |
| }; | |
| startBtn.addEventListener('touchstart', handleStart, { passive: false }); | |
| startBtn.addEventListener('mousedown', handleStart); | |
| // Global tap for jumping | |
| container.addEventListener('touchstart', (e) => { | |
| if (gameActive) { | |
| birdV = FLAP; | |
| } | |
| // Don't preventDefault here as it might block the start button touchstart | |
| }, { passive: true }); | |
| // Fallback for mouse | |
| container.addEventListener('mousedown', (e) => { | |
| if (gameActive && e.target !== startBtn) { | |
| birdV = FLAP; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment