Sprint View

Debugging

9 min read

Debugging

Table of Contents

Debugging is the process of finding and fixing problems in your code. Every developer spends a huge amount of time debugging β€” the key is knowing which tools to use and where to look.

Console Debugging

console.log is the most basic and most used debugging tool.

Code Runner Challenge

Console Debugging

View IPYNB Source
%%js

//CODE_RUNNER: Console Debugging


class Player {
    constructor(data) {
        this.x         = data.x;
        this.y         = data.y;
        this.velocityY = 0;
        this.health    = 100;
        this.isJumping = false;
        this.state     = "idle";
    }

    update() {
        // Strategic log β€” tracks position and velocity every frame
        console.log(`[update] x: ${this.x}, y: ${this.y.toFixed(1)}, velocityY: ${this.velocityY.toFixed(2)}, state: ${this.state}`);

        this.velocityY += 0.4;  // gravity
        this.y         += this.velocityY;
    }

    handleCollision(other, direction) {
        // Strategic log β€” tracks what was hit and from which direction
        console.log(`[collision] hit: ${other.label}, direction: ${direction}, health before: ${this.health}`);

        if (other.label === "Enemy" && direction === "side") {
            this.health -= other.damage;
            this.state   = "hurt";
        }

        // Strategic log β€” tracks outcome after collision logic runs
        console.log(`[collision] health after: ${this.health}, state: ${this.state}`);
    }
}

const player = new Player({ x: 100, y: 300 });

console.log("--- Simulating 3 frames ---");
player.update();
player.update();
player.update();

console.log("\n--- Simulating a collision ---");
player.handleCollision({ label: "Enemy", damage: 20 }, "side");
player.handleCollision({ label: "Platform", damage: 0 }, "top");
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Explanation β€” The logs are prefixed with [update] and [collision] so you can instantly see which method they came from in the console. Running this shows velocityY growing each frame as gravity accumulates, and then the collision log shows health dropping from 100 to 80 after hitting the enemy. Without these logs you would have no way to know what values the game had at the exact moment a bug occurred.

Hitbox visualization

A hit box is the invisible rectangle the game uses for collision detection. When collisions feel wrong β€” the player dies before touching an enemy, or walks through a platform β€” the hit box is usually misaligned. Visualizing it draws the rectangle on screen so you can see exactly what the game thinks.

Code Runner Challenge

Hitbox visualization

View IPYNB Source
%%js

//CODE_RUNNER: Hitbox visualization

// Run this to see hit box data being calculated and logged

class GameObject {
    constructor(data) {
        this.x      = data.x;
        this.y      = data.y;
        this.width  = data.width;
        this.height = data.height;
        this.label  = data.label;
        this.showHitBox = false; // toggle this to visualize
    }

    // Returns the collision rectangle
    getHitBox() {
        return {
            left:   this.x,
            right:  this.x + this.width,
            top:    this.y,
            bottom: this.y + this.height,
        };
    }

    // In a real game this draws a red rectangle on the canvas
    // Here we log what it would draw
    drawHitBox() {
        if (!this.showHitBox) return;
        const hb = this.getHitBox();
        console.log(`[hitbox] ${this.label} β€” left:${hb.left} right:${hb.right} top:${hb.top} bottom:${hb.bottom}`);
    }

    // Check overlap with another object's hit box
    isOverlapping(other) {
        const a = this.getHitBox();
        const b = other.getHitBox();
        return a.left < b.right &&
               a.right > b.left &&
               a.top < b.bottom &&
               a.bottom > b.top;
    }
}

const player = new GameObject({ x: 100, y: 300, width: 48, height: 48, label: "Player" });
const enemy  = new GameObject({ x: 130, y: 300, width: 40, height: 40, label: "Enemy"  });

// Toggle hit boxes on for debugging
player.showHitBox = true;
enemy.showHitBox  = true;

console.log("--- Hit box positions ---");
player.drawHitBox();
enemy.drawHitBox();

console.log("\n--- Overlap check ---");
const overlapping = player.isOverlapping(enemy);
console.log(`Player and enemy overlapping: ${overlapping}`);

// Move enemy away and check again
enemy.x = 300;
console.log(`\nAfter moving enemy to x=300 β€” overlapping: ${player.isOverlapping(enemy)}`);
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Explanation β€” getHitBox() returns the four edges of the collision rectangle as named values β€” left, right, top, bottom. drawHitBox() would normally draw a red rectangle on the canvas; here it logs the coordinates so you can verify the numbers match where the sprite appears on screen. isOverlapping() uses those four edges to check if two rectangles intersect.

Source Debugging

The DevTools Sources tab lets you pause execution at any line of code and step through it one line at a time. This is more powerful than console.log because you can inspect every variable at the exact moment the code is paused β€” without adding any extra logging.

// Run this β€” then open DevTools Sources tab and set a breakpoint on handleCollision

class Player {
    constructor(data) {
        this.x      = data.x;
        this.y      = data.y;
        this.health = 100;
        this.state  = "idle";
    }

    handleCollision(other, direction) {
        // Set your breakpoint on the line below in DevTools Sources tab
        // Execution will pause here and you can inspect: other, direction, this.health
        let tookDamage = false;

        if (other.label === "Enemy" && direction === "side") {
            this.health -= other.damage;
            this.state   = "hurt";
            tookDamage   = true;
        }

        // Step through to here and check tookDamage in the Scope panel
        console.log(`tookDamage: ${tookDamage}, health: ${this.health}`);
        return tookDamage;
    }
}

const player = new Player({ x: 100, y: 300 });
player.handleCollision({ label: "Enemy", damage: 20 }, "side");
player.handleCollision({ label: "Platform", damage: 0 }, "top");

Explanation β€” When execution pauses at the breakpoint, the Scope panel on the right shows every variable in the current function β€” other, direction, this.health β€” with their live values. You can hover over any variable in the code and a tooltip shows its current value. This is how you catch bugs where a variable has the wrong value at the wrong time.

Network Debugging

The DevTools Network tab records every HTTP request the page makes. For the leaderboard, this shows you the fetch POST and GET calls, the exact data sent, the server’s response, and any errors like CORS or 404.

Code Runner Challenge

Network debugging

View IPYNB Source
%%js

//CODE_RUNNER: Network debugging

// Run this to simulate what the Network tab would show for a leaderboard POST

const requestDetails = {
    url:    "https://spring.opencodingsociety.com/api/events/SCORE_COUNTER",
    method: "POST",
    headers: { "Content-Type": "application/json" },
    payload: { payload: { user: "mario", score: 4500, gameName: "MarioGame" } }
};

console.log("=== What the Network tab shows ===");
console.log("URL:",     requestDetails.url);
console.log("Method:",  requestDetails.method);
console.log("Payload:", JSON.stringify(requestDetails.payload, null, 2));

// Simulating different status codes you might see
const statusCodes = [
    { code: 200, meaning: "OK β€” score saved successfully" },
    { code: 401, meaning: "Unauthorized β€” not logged in, check cookies" },
    { code: 403, meaning: "Forbidden β€” logged in but no permission" },
    { code: 404, meaning: "Not found β€” wrong URL, check the endpoint" },
    { code: 500, meaning: "Server error β€” backend crashed, check server logs" },
];

console.log("\n=== Common status codes and what they mean ===");
statusCodes.forEach(s => {
    console.log(`${s.code}: ${s.meaning}`);
});
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Explanation β€” The Network tab is essential for debugging API issues. If the leaderboard is not saving scores, the first place to look is the status code β€” 401 means you are not logged in, 404 means the URL is wrong, 500 means the backend has a problem. The Payload tab shows exactly what JSON was sent, so you can confirm the data shape matches what the server expects. CORS errors appear in red in the console and also show up as failed requests in the Network tab.

Aplication Debugging

The DevTools Application tab shows everything stored in the browser β€” localStorage, sessionStorage, and cookies. The leaderboard uses localStorage as a fallback when the backend is unavailable, so this tab lets you verify scores are actually being saved locally.

Code Runner Challenge

Application Debugging

View IPYNB Source
%%js

//CODE_RUNNER: Application Debugging

// Run this to write and read localStorage the same way Leaderboard.js does

const gameName   = "MarioGame";
const storageKey = `score_counter_${gameName}`;

// Write a score to localStorage (same as the fallback in Leaderboard.js)
const entry = {
    id:        `local-${Date.now()}`,
    payload:   { user: "mario", score: 4500, gameName: gameName },
    timestamp: new Date().toISOString()
};

const stored = JSON.parse(localStorage.getItem(storageKey) || "[]");
stored.push(entry);
localStorage.setItem(storageKey, JSON.stringify(stored));

console.log("Score saved to localStorage under key:", storageKey);

// Read it back (same as fetchLeaderboard fallback)
const retrieved = JSON.parse(localStorage.getItem(storageKey) || "[]");
console.log("Retrieved from localStorage:", retrieved.length, "entries");
retrieved.forEach((e, i) => {
    console.log(`${i + 1}. ${e.payload.user} β€” ${e.payload.score} pts`);
});

// In DevTools Application tab you can now see this key and its value
console.log("\nNow open DevTools β†’ Application β†’ Local Storage to see this data live");
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Explanation β€” localStorage.setItem(key, value) stores a string under a named key that persists even after the page is closed. localStorage.getItem(key) reads it back. Because localStorage only stores strings, JSON.stringify converts the object to text before saving and JSON.parse converts it back after reading. The Application tab in DevTools shows these keys and their raw values, so you can confirm the fallback is working and see exactly what data is stored.

Element Inspection

The DevTools Elements tab shows the full HTML structure of the page while the game runs. You can click on the canvas element or any game UI element and see its exact size, position, and CSS styles β€” useful for fixing layout issues or verifying the canvas is the right dimensions.

// Run this to log the same info the Elements tab shows about the canvas

// Simulating what DevTools Elements tab reveals about the canvas
const canvasInfo = {
    id:        "gameCanvas",
    tagName:   "CANVAS",
    width:     800,
    height:    450,
    className: "game-canvas",
    style: {
        display:  "block",
        margin:   "0 auto",
        border:   "2px solid #333"
    }
};

console.log("=== Element tab info for the canvas ===");
console.log("Tag:",    canvasInfo.tagName);
console.log("ID:",     canvasInfo.id);
console.log("Width:",  canvasInfo.width);
console.log("Height:", canvasInfo.height);
console.log("Styles:", JSON.stringify(canvasInfo.style, null, 2));

// In a real game you would use:
// const canvas = document.getElementById("gameCanvas");
// console.log("Actual width:", canvas.width);
// console.log("Actual height:", canvas.height);
// console.log("Position:", canvas.getBoundingClientRect());

console.log("\nOpen DevTools β†’ Elements tab β†’ click the canvas to see this live");

Explanation β€” The Elements tab is useful when the game canvas is the wrong size, positioned incorrectly, or not showing up at all. Clicking the canvas in DevTools highlights it on the page and shows the box model β€” margin, border, padding, and content size β€” as a coloured diagram. The Styles panel shows every CSS rule applied and where it came from, so you can see which rule is overriding another. The Properties panel shows JavaScript properties directly on the DOM element, including width and height.

Course Timeline