2048

A sleek mobile-friendly 2048 puzzle game with cyberpunk aesthetics, featuring touch controls, a top 10 leaderboard system, and local storage for player names.

Preview
Source CodeVersion 3
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    // API routes
    if (url.pathname.startsWith('/api/')) {
      if (url.pathname === '/api/leaderboard' && request.method === 'GET') {
        try {
          const result = await env.DB.prepare(
            'SELECT name, score FROM leaderboard ORDER BY score DESC LIMIT 10'
          ).all();
          
          return new Response(JSON.stringify({ data: result.results }), {
            headers: { 
              'Content-Type': 'application/json',
              'Access-Control-Allow-Origin': '*'
            }
          });
        } catch (error) {
          return new Response(JSON.stringify({ error: 'Failed to fetch leaderboard' }), {
            status: 500,
            headers: { 'Content-Type': 'application/json' }
          });
        }
      }

      if (url.pathname === '/api/submit-score' && request.method === 'POST') {
        try {
          const { name, score } = await request.json();
          
          if (!name || !score || score < 0) {
            return new Response(JSON.stringify({ error: 'Invalid data' }), {
              status: 400,
              headers: { 'Content-Type': 'application/json' }
            });
          }

          // Insert the score
          await env.DB.prepare(
            'INSERT INTO leaderboard (id, name, score, created_at) VALUES (?1, ?2, ?3, datetime("now"))'
          ).bind(crypto.randomUUID(), name, score).run();

          // Keep only top 10
          await env.DB.prepare(
            'DELETE FROM leaderboard WHERE score NOT IN (SELECT score FROM leaderboard ORDER BY score DESC LIMIT 10)'
          ).run();

          return new Response(JSON.stringify({ ok: true }), {
            headers: { 
              'Content-Type': 'application/json',
              'Access-Control-Allow-Origin': '*'
            }
          });
        } catch (error) {
          return new Response(JSON.stringify({ error: 'Failed to submit score' }), {
            status: 500,
            headers: { 'Content-Type': 'application/json' }
          });
        }
      }

      return new Response(JSON.stringify({ error: 'Not found' }), {
        status: 404,
        headers: { 'Content-Type': 'application/json' }
      });
    }

    // Serve HTML
    return new Response(getHTML(), {
      headers: { 'Content-Type': 'text/html' }
    });
  }
};

function getHTML() {
  return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>2048 - Epic Edition</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
  <style>
    body { font-family: 'Inter', sans-serif; }
    .game-cell {
      display: flex;
      align-items: center;
      justify-content: center;
      font-weight: 700;
      border-radius: 8px;
      transition: all 0.15s ease-in-out;
      aspect-ratio: 1;
      width: 100%;
    }
    .cell-2 { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
    .cell-4 { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); }
    .cell-8 { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); }
    .cell-16 { background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); }
    .cell-32 { background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); }
    .cell-64 { background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); }
    .cell-128 { background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%); }
    .cell-256 { background: linear-gradient(135deg, #a18cd1 0%, #fbc2eb 100%); }
    .cell-512 { background: linear-gradient(135deg, #fad0c4 0%, #ffd1ff 100%); }
    .cell-1024 { background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%); font-size: 0.75rem; }
    .cell-2048 { background: linear-gradient(135deg, #ffafbd 0%, #ffc3a0 100%); font-size: 0.75rem; }
    .shimmer {
      background: linear-gradient(90deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.1) 100%);
      background-size: 200% 100%;
      animation: shimmer 1.5s infinite;
    }
    @keyframes shimmer {
      0% { background-position: -200% 0; }
      100% { background-position: 200% 0; }
    }
    @keyframes pulse {
      0%, 100% { transform: scale(1); }
      50% { transform: scale(1.05); }
    }
    .pulse-animation { animation: pulse 0.3s ease-in-out; }
  </style>
</head>
<body class="bg-gray-900 text-white min-h-screen font-inter overflow-hidden">
  <div class="min-h-screen bg-gradient-to-br from-violet-900 via-purple-900 to-blue-900 p-4">
    <!-- Header -->
    <div class="max-w-md mx-auto mb-6">
      <h1 class="text-4xl font-bold text-center bg-gradient-to-r from-violet-400 to-blue-400 bg-clip-text text-trans
...

Comments (0)

No comments yet. Be the first!