TipTap Games

Your first game

A real, playable game — from a blank file to the feed — in five steps. Copy each block, run it, change it. No build step, no framework, one HTML file.

  • ~15 minutes
  • One HTML file
  • Ends published

A TipTap game is a single self-contained HTML file that runs in one panel of a swipeable feed. The platform injects window.TipTap for you — there is nothing to install and nothing to import. We'll build Tap Rush: tap the dot before the clock runs out. Each step is a small change on the one before it.

  1. A page that plays

    Start with a game and no platform at all — a canvas, a loop, and a dot you can tap. Paste this into a file called index.html and open it in a browser. It runs anywhere; the platform is just where it will live.

    index.html — a complete, runnable game

    <!doctype html>
    <html>
    <head>
      <meta charset="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1" />
      <title>Tap Rush</title>
      <style>
        html, body { margin: 0; height: 100%; background: #12101c; overflow: hidden; touch-action: none; }
        canvas { display: block; }
      </style>
    </head>
    <body>
      <canvas id="c"></canvas>
      <script>
        // window.TipTap is injected for you on the platform — no import, no build step.
        const canvas = document.getElementById("c");
        const ctx = canvas.getContext("2d");
        let W, H;
        function fit() { W = canvas.width = innerWidth; H = canvas.height = innerHeight; }
        fit();
        addEventListener("resize", fit);
    
        let score = 0;
        let target = spawn();
        function spawn() {
          return {
            x: 40 + Math.random() * (innerWidth - 80),
            y: 90 + Math.random() * (innerHeight - 180),
            r: 34,
          };
        }
    
        // Tap the dot: score goes up and it jumps somewhere new.
        canvas.addEventListener("pointerdown", (e) => {
          const dx = e.clientX - target.x;
          const dy = e.clientY - target.y;
          if (dx * dx + dy * dy < target.r * target.r) {
            score++;
            target = spawn();
          }
        });
    
        function frame() {
          ctx.clearRect(0, 0, W, H);
          ctx.fillStyle = "#7c5cff";
          ctx.beginPath();
          ctx.arc(target.x, target.y, target.r, 0, Math.PI * 2);
          ctx.fill();
          ctx.fillStyle = "#fff";
          ctx.font = "bold 28px system-ui, sans-serif";
          ctx.fillText(String(score), 20, 46);
          requestAnimationFrame(frame);
        }
        frame();
      </script>
    </body>
    </html>

    ✓ You have a game that runs. No SDK yet — that's next.

  2. Keep score

    Now put it on the board. Add a countdown so a run ends, then two calls: updateScore shows a live score in the platform's top bar during play, and submitScore writes the final number to the leaderboard. submitScore is silent — it shows no UI of its own, so we pass { showLeaderboard: true } to raise the board when the run is over.

    The changes — a clock, and the two score calls

    let time = 15;      // seconds on the clock
    let over = false;
    let last = performance.now();
    
    function endGame() {
      over = true;
      // Silent write to the leaderboard, and raise it in the same call.
      TipTap.submitScore(score, { showLeaderboard: true });
    }
    
    // In your pointerdown handler, after score++:
    TipTap.updateScore(score);   // live score in the platform's top bar
    
    // In frame(), before you draw — advance the clock:
    const now = performance.now();
    time -= (now - last) / 1000;
    last = now;
    if (time <= 0 && !over) endGame();
    
    // ...and draw the timer next to the score:
    ctx.fillText(Math.max(0, Math.ceil(time)) + "s", W - 70, 46);

    ✓ Your score lands on the leaderboard. See Scores & leaderboards for challenges and daily seeds.

  3. React to the result

    When submitScore is processed, onResult hands you the standing this run earned — rank, percentile, whether it was a personal best. Show it, celebrate a best, and let the player go again when they close the board.

    Register these once, near the top of your script

    TipTap.onResult((r) => {
      // Fires after submitScore is processed, with the standing this run earned.
      message = "Rank #" + r.rank + " — top " + Math.round(r.percentile) + "%";
      if (r.personalBest) message = "New best! " + message;
    });
    
    // Let the player go again when they close the leaderboard.
    TipTap.onLeaderboardClose(() => {
      score = 0;
      time = 15;
      over = false;
      last = performance.now();
      target = spawn();
    });

    ✓ The round-trip works: play → submit → result → play again.

  4. Behave in the feed

    Your game lives in a feed the player swipes through, so it has to be a good citizen when it is not the one on screen. The platform pauses your game as it scrolls away — honour that so the clock doesn't drain in the background — and never play a sound unless canPlayAudio() says you may.

    Pause with the platform; gate your audio

    let running = true;
    
    // The platform pauses your game when it scrolls out of the feed. Respect it:
    // stop advancing the clock and the loop, resume exactly where you were.
    TipTap.onPauseChange((paused) => { running = paused ? false : true; });
    
    // At the top of frame(), before anything moves:
    if (!running) { requestAnimationFrame(frame); return; }
    
    // And before you ever play a sound:
    if (TipTap.canPlayAudio()) hitSound.play();

    ✓ It pauses when swiped away and resumes where it left off. Full detail on Game lifecycle.

  5. Publish it

    You have a real game. To get it into the feed:

    1. Go to Upload a game and drop in your HTML file.
    2. Set a realistic scoreMax — the highest score a legitimate run could reach. A submission above it is refused, which is how the leaderboard stays honest.
    3. Send it for review. A human checks every game before it reaches the feed — how review works walks through what they look for and how long it takes.

    ✓ It's in the queue. Once approved, it's live in the feed.

Where to go next

You now know the shape of a TipTap game. Everything else is going deeper.