Title of State:

Add Scrolling Ability on Maps

Goal of Change:

PATCH 1 — Add camera + key state to S

Code to Remove

232 - 
const S = {
  paused:false,
  view:"TITLE",        // "TITLE" | "MENU" | "GAME"
  mapKey:null,         // "GRASS" | "SAND" | "SNOW"
  mouseX:0, mouseY:0,
  fps:0, _acc:0, _frames:0,
  last: performance.now(),
};

Code to Add

232 - 
const S = {
  paused:false,
  view:"TITLE",        // "TITLE" | "MENU" | "GAME"
  mapKey:null,         // "GRASS" | "SAND" | "SNOW"
  mouseX:0, mouseY:0,

  camX:0, camY:0,      // viewport top-left in map pixels
  keys:{},             // pressed keys map

  fps:0, _acc:0, _frames:0,
  last: performance.now(),
};


PATCH 2 — Add camera constants + clamp helper

Code to Remove

246 - 
function setHUD(lines){ hud.textContent = lines; }

Code to Add

246 - 
function setHUD(lines){ hud.textContent = lines; }

const MAP_SIZE = 5120;
const TILE = 2560;
const VIEW = 1500;

const EDGE = 40;          // edge zone thickness (px)
const PAN_SPEED = 1400;   // px/sec for both arrows + edge pan

function clamp(v, a, b){ return Math.max(a, Math.min(b, v)); }


PATCH 3 — Replace keydown handler to track held keys + keep Space/P behavior

Code to Remove

270 - 
window.addEventListener("keydown", (e)=>{
  if(e.code==="KeyP"){ togglePause(); }
  if(e.code==="Space"){ e.preventDefault(); onSpace(); }
});

Code to Add

270 - 
window.addEventListener("keydown", (e)=>{
  S.keys[e.code] = true;

  if(e.code==="KeyP"){ togglePause(); }
  if(e.code==="Space"){ e.preventDefault(); onSpace(); }
});

window.addEventListener("keyup", (e)=>{
  S.keys[e.code] = false;
});


PATCH 4 — Reset camera when a map is selected (so it starts top-left)

Code to Remove

357 - 
function setSelectedMap(key){
  S.mapKey = key;

  mapGrassBtn.classList.toggle("selected", key === "GRASS");
  mapSandBtn.classList.toggle("selected",  key === "SAND");
  mapSnowBtn.classList.toggle("selected",  key === "SNOW");

  btnStartGame.disabled = false;
}

Code to Add

357 - 
function setSelectedMap(key){
  S.mapKey = key;

  // reset camera at selection
  S.camX = 0;
  S.camY = 0;

  mapGrassBtn.classList.toggle("selected", key === "GRASS");
  mapSandBtn.classList.toggle("selected",  key === "SAND");
  mapSnowBtn.classList.toggle("selected",  key === "SNOW");

  btnStartGame.disabled = false;
}


PATCH 5 — Replace update(dt) with arrows + edge-pan camera movement

Code to Remove

384 - 
function update(dt){
  // your game logic goes here
}

Code to Add

384 - 
function update(dt){
  if(S.view !== "GAME") return;
  if(!S.mapKey) return;

  let dx = 0, dy = 0;

  // --- Arrow keys (held down) ---
  if(S.keys["ArrowLeft"])  dx -= 1;
  if(S.keys["ArrowRight"]) dx += 1;
  if(S.keys["ArrowUp"])    dy -= 1;
  if(S.keys["ArrowDown"])  dy += 1;

  // --- Edge panning (mouse near canvas border) ---
  if(S.mouseX <= EDGE) dx -= 1;
  else if(S.mouseX >= (VIEW - EDGE)) dx += 1;

  if(S.mouseY <= EDGE) dy -= 1;
  else if(S.mouseY >= (VIEW - EDGE)) dy += 1;

  // Apply motion
  if(dx !== 0 || dy !== 0){
    S.camX += dx * PAN_SPEED * dt;
    S.camY += dy * PAN_SPEED * dt;
  }

  // Clamp to map bounds
  const maxCam = MAP_SIZE - VIEW;
  S.camX = clamp(S.camX, 0, maxCam);
  S.camY = clamp(S.camY, 0, maxCam);
}


PATCH 6 — Replace drawMapNative() to use the camera offset (no scaling)

Code to Remove

415 - 
function drawMapNative(){
  if(S.view !== "GAME") return;
  if(!S.mapKey) return;

  const tiles = MapImages[S.mapKey];
  const t1 = tiles[0], t2 = tiles[1], t3 = tiles[2], t4 = tiles[3];

  // NO SCALING.
  // Each tile is 2560×2560. We draw them at native pixel coordinates.
  // The 1500×1500 canvas will clip what doesnt fit.
  if(t1) ctx.drawImage(t1, 0,    0);
  if(t2) ctx.drawImage(t2, 2560, 0);
  if(t3) ctx.drawImage(t3, 0,    2560);
  if(t4) ctx.drawImage(t4, 2560, 2560);
}

Code to Add

415 - 
function drawMapNative(){
  if(S.view !== "GAME") return;
  if(!S.mapKey) return;

  const tiles = MapImages[S.mapKey];
  const t1 = tiles[0], t2 = tiles[1], t3 = tiles[2], t4 = tiles[3];

  // Camera offset (NO SCALING)
  const ox = -S.camX;
  const oy = -S.camY;

  if(t1) ctx.drawImage(t1, ox + 0,     oy + 0);
  if(t2) ctx.drawImage(t2, ox + TILE,  oy + 0);
  if(t3) ctx.drawImage(t3, ox + 0,     oy + TILE);
  if(t4) ctx.drawImage(t4, ox + TILE,  oy + TILE);
}


PATCH 7 — Add CAM line to your existing HUD block

Code to Remove

472 - 
  setHUD(
    (S.paused ? "PAUSED" : "READY") +
    `\\nFPS: ${S.fps}` +
    `\\nM: ${Math.floor(S.mouseX)},${Math.floor(S.mouseY)}`
  );

Code to Add

472 - 
setHUD(
  (S.paused ? "PAUSED" : "READY") +
  `\\nFPS: ${S.fps}` +
  `\\nM: ${Math.floor(S.mouseX)},${Math.floor(S.mouseY)}` +
  `\\nCAM: ${Math.floor(S.camX)},${Math.floor(S.camY)}`
);


Result