Mini Kong Tower

HTML

<div id="wrap">
    <canvas id="c" width="640" height="480"></canvas>
    <div id="hud">
      <div class="pill" id="controls-hint">
        <strong>Contrôles</strong> :
        <kbd>←</kbd><kbd>→</kbd> bouger,
        <kbd>↑</kbd><kbd>↓</kbd> échelles,
        <kbd>Espace</kbd> sauter,
        <kbd>Entrée</kbd> jouer
      </div>
      <div class="pill" id="stats">Score: 00000 · Vies: 3 · Niveau: 1</div>
    </div>
  </div>

CSS

:root {
      --bg1: #0a0b18;
      --bg2: #130a1e;
      --ink: #ffe9c7;
      --panel: #00000055;
    }
    * { box-sizing: border-box; margin: 0; padding: 0; user-select: none; -webkit-user-select: none; }
    html, body { height: 100%; overflow: hidden; }
    body {
      display: flex; align-items: center; justify-content: center;
      background: radial-gradient(1200px 800px at 20% 10%, #1f2a6b33 0%, transparent 60%),
                  radial-gradient(900px 700px at 80% 20%, #b31b5a33 0%, transparent 55%),
                  linear-gradient(135deg, var(--bg1), var(--bg2));
      font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
      color: var(--ink);
    }
    #wrap {
      display: flex; flex-direction: column; gap: 10px; align-items: center;
      width: 100%; max-width: 920px;
    }
    canvas {
      width: 100%;
      height: auto;
      aspect-ratio: 4/3;
      max-height: 80vh;
      border-radius: 14px;
      border: 2px solid #ffcc66;
      background: linear-gradient(#070816, #04040a);
      box-shadow: 0 20px 60px #000000aa;
      image-rendering: pixelated;
    }
    #hud {
      width: 100%;
      display: flex; gap: 12px; flex-wrap: wrap; justify-content: space-between; align-items: center;
      padding: 10px 16px; border-radius: 12px; background: var(--panel);
      border: 1px solid #ffffff22;
      font-size: 14px;
      backdrop-filter: blur(4px);
    }
    kbd {
      display: inline-block; min-width: 22px; text-align: center;
      padding: 2px 7px; margin: 0 2px;
      border-radius: 6px;
      background: linear-gradient(#2a2a2a, #161616);
      border: 1px solid #666;
      color: #fff;
      font-family: monospace; font-weight: 700;
      box-shadow: inset 0 1px 0 #ffffff22;
      font-size: 0.9em;
    }
    .pill {
      padding: 4px 10px; border-radius: 999px; background: #ffffff12; border: 1px solid #ffffff1f;
    }
    @media (hover: none) and (pointer:...

JavaScript

(() => {
  const canvas = document.getElementById("c" );
  const ctx = canvas.getContext("2d", { alpha: false });
 
  const W = 640;
  const H = 480;
 
  const COL = {
    red: "#c43e5c", red2: "#ff8fa3",
    cyan: "#62d7ff", cyan2: "#2aa7d3",
    gold: "#ffd36b", gold2: "#ffb700",
    ink: "#ffe9c7",
    ladder: "#62d7ff", ladderRung: "#2aa7d3",
    barrel: "#c2843a", barrelBorder: "#f5d19b",
    barrelRed: "#e62e2e", barrelRedBorder: "#ff8888",
    kong: "#ff5e3a", kongStroke: "#ffb199",
    princess: "#ffc0f5",
    hammerHead: "#ddd", hammerHandle: "#8b5a2b"
  };
 
  const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
  const aabb = (a, b) => (a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y);
 
  const keys = Object.create(null);
  window.addEventListener("keydown", (e) => {
    if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", " "].includes(e.key)) {
      e.preventDefault();
    }
    keys[e.key] = true;
    if (e.key === "Enter" ) keys.__enterTap = true;
  }, { passive: false });
  window.addEventListener("keyup", (e) => keys[e.key] = false);
 
  const touchState = { left: false, right: false, up: false, down: false, jump: false };
  canvas.addEventListener("touchstart", handleTouch, { passive: false });
  canvas.addEventListener("touchmove", handleTouch, { passive: false });
  canvas.addEventListener("touchend", (e) => {
    e.preventDefault();
    if(e.touches.length === 0) {
        touchState.left = touchState.right = touchState.up = touchState.down = touchState.jump = false;
    }
  });
 
  function handleTouch(e) {
    e.preventDefault();
    const rect = canvas.getBoundingClientRect();
    touchState.left = touchState.right = touchState.up = touchState.down = touchState.jump = false;
     
    if(state !== "playing" ) {
        if(e.type === "touchstart" ) keys.__enterTap = true;
        return;
    }
 
    for (let i = 0; i < e.touches.length; i++) {
   ...