Hi! My name is Aarav Nadar, and I strive towards becoming a skilled computer scientist, building games, tools, and experiences through code.

Development Environment

Coding starts with tools, explore these tools and procedures with a click.


My Lessons

Foundations in Tech are essential, click to see some of my lesson creations.


Class Progress

Here is my game progress through coding, click to see these in the browser


My Projects

Here are some tools and apps I built, click to try them!

Challenge

Play the Maze Sub Level. Climb the staircase platforms to reach the Exit Warden and trigger a level transition!

Lines: 1 Characters: 0
Game Status: Not Started













About Escape the Tower ๐Ÿ—ผ

Escape the Tower is a multi-level platformer built with JavaScript using an object-oriented game engine. I contributed by building the Maze of Shadows sublevel.


CS 111 College Credit Evidence

CS 111 Course Alignment Rubric

Required Evidence for College Credit
Students must demonstrate competency in all CS 111 learning objectives through their game project.

Learning Objective Project Evidence Required Assessment Method Done Demo
Object-Oriented Programming ย  ย  โœ… ย 
Writing Classes Create minimum 2 custom character classes extending base classes Code review: Player.js, NPC.js, Enemy.js โœ… โ†“ snippet
Methods & Parameters Implement methods with parameters (e.g., collisionHandler(other, direction)) Code review: Method signatures with 2+ parameters โœ… โ†“ snippet
Instantiation & Objects Instantiate game objects in GameLevel configuration Code review: GameLevel setup objects โœ… โ†“ snippet
Inheritance (Basic) Create class hierarchy with 2+ levels (e.g., GameObject โ†’ Character โ†’ Player) Code review: extends keyword, inheritance chain โœ… โ†“ snippet
Method Overriding Override parent methods (update(), draw(), handleCollision()) Code review: Polymorphic implementations โœ… โ†“ snippet
Constructor Chaining Use super() to chain constructors Code review: super(data, gameEnv) calls โœ… โ†“ snippet
Control Structures ย  ย  โœ… ย 
Iteration Use loops for game object arrays, animation frames Code review: for, forEach, while loops โœ… โ†“ snippet
Conditionals Implement collision detection, state transitions Code review: if/else, nested conditions โœ… โ†“ snippet
Nested Conditions Complex game logic (e.g., power-up + collision + direction) Code review: Multi-level conditionals โœ… โ†“ snippet
Data Types ย  ย  โœ… ย 
Numbers Position, velocity, score tracking Code review: Numeric properties โœ… โ†“ snippet
Strings Character names, sprite paths, game states Code review: String manipulation โœ… โ†“ snippet
Booleans Flags (isJumping, isPaused, isVulnerable) Code review: Boolean logic โœ… โ†“ snippet
Arrays Game object collections, level data Code review: Array operations โœ… โ†“ snippet
Objects (JSON) Configuration objects, sprite data Code review: Object literals โœ… โ†“ snippet
Operators ย  ย  โœ… ย 
Mathematical Physics calculations (gravity, velocity, collision) Code review: +, -, *, / in physics โœ… โ†“ snippet
String Operations Path concatenation, text display Code review: Template literals, concatenation โœ… โ†“ snippet
Boolean Expressions Compound conditions in game logic Code review: &&, || โœ… โ†“ snippet
Input/Output ย  ย  โœ… ย 
Keyboard Input Arrow keys, space, WASD controls using event listeners Testing: Key event handlers respond correctly โœ… live demo only
Canvas Rendering Draw sprites, backgrounds, platforms using Canvas API Code review: draw() method implementations โœ… live demo only
GameEnv Configuration Set canvas size, difficulty levels, game settings Code review: GameEnv.create() and GameSetup.js โœ… โ†“ snippet
API Integration Implement Leaderboard API (POST/GET scores) Code review: Fetch calls with error handling โœ… โ†“ snippet
Asynchronous I/O Use async/await or promises for API calls Code review: async/await or .then() chains โœ… โ†“ snippet
JSON Parsing Parse API responses (leaderboard data, AI responses) Code review: JSON.parse(), object destructuring โœ… โ†“ snippet
Documentation ย  ย  โœ… ย 
Code Comments JSDoc comments for classes and methods Code review: Comment density >10% โœ… in portfolio
Mini-Lesson Documentation Create comic/visual post with embedded runtime game demo Portfolio review: Mini-lesson in personal portfolio โœ… in portfolio
Code Highlights Annotate key code snippets in documentation (OOP, APIs, collision) Portfolio review: Highlighted code examples with explanations โœ… in portfolio
Debugging ย  ย  โœ… ย 
Console Debugging Use console.log to track game state, variables, method calls Code review: Strategic logging in update/collision methods โœ… โ†“ snippet
Hit Box Visualization Draw/visualize collision boundaries to refine detection Demo: Toggle hit box display, adjust collision rectangles โœ… โ†“ snippet
Source-Level Debugging Set breakpoints in DevTools, step through code execution Demo: Use Sources tab to pause and inspect code flow โœ… DevTools demo
Network Debugging Examine Network tab for API calls, CORS errors, response status Demo: Inspect fetch requests, response data, error messages โœ… DevTools demo
Application Debugging Examine cookies, localStorage, session data for login/state Demo: Application tab inspection of stored data โœ… DevTools demo
Element Inspection Use Element Viewer to inspect canvas, DOM elements, styles Demo: Inspect element properties and game object state โœ… DevTools demo
Testing & Verification ย  ย  โœ… ย 
Gameplay Testing Test level completion, character interactions, collision detection Live demo: Play through level without critical bugs โœ… live demo only
Integration Testing Test API integration (Leaderboard, NPC AI) with live backend Demo: Successful score saving and AI responses โœ… โ†“ snippet
API Error Handling Try/catch blocks for API calls, network error handling Code review: Error handling for fetch failures โœ… โ†“ snippet

Writing Classes โ€” Create minimum 2 custom character classes extending base classes

// GameLevelMazeSub.js โ€” Player and Npc both extend base Character class
{ class: Player, data: sprite_data_octopus },
{ class: Npc,    data: sprite_data_shadow  },
{ class: Npc,    data: sprite_data_warden  },

Code Runner Challenge

Run this to see two custom classes โ€” Player and Npc โ€” both extending a shared Character base. This mirrors the exact pattern used in GameLevelMazeSub.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Inheritance (Basic) โ€” Create class hierarchy with 2+ levels

// 3-level chain: GameObject โ†’ Character โ†’ Player
class Player extends Character { ... }
class Character extends GameObject { ... }

Code Runner Challenge

Run this to see a 3-level inheritance chain โ€” the same depth used in the game engine (GameObject โ†’ Character โ†’ Player).

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Constructor Chaining โ€” Use super() to chain constructors

// GameLevelMazeSub.js โ€” every subclass calls super() to chain up
class GameLevelMazeSub extends GameLevel {
  constructor(gameEnv) {
    super(gameEnv); // chains to GameLevel constructor
    this.classes = [ ... ];
  }
}

Code Runner Challenge

Run this to see super() chain three constructors in sequence. Each level of the hierarchy initializes its own properties before the child adds its own.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Iteration โ€” Use loops for game object arrays, animation frames

// GameLevelMazeSub.js โ€” engine iterates this.classes to build every object
this.classes.forEach(entry => {
  const obj = new entry.class(entry.data);
});

Code Runner Challenge

Run this to see forEach and for...of iterating the classes array โ€” exactly how the game engine instantiates every object in a level.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Conditionals โ€” Implement collision detection, state transitions

// GameLevelMazeSub.js โ€” Exit Warden only triggers dialogue when player collides
interact: function() {
  if (this.dialogueSystem && this.dialogueSystem.isDialogueOpen()) {
    this.dialogueSystem.closeDialogue();
    return;
  }
  // ... show dialogue
}

Code Runner Challenge

Run this to see if/else conditionals controlling NPC state โ€” the same guard clause pattern used in every interact() method across all game levels.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Nested Conditions โ€” Complex game logic

// GameLevelForestSub.js โ€” nested checks before launching sublevel
for (const obj of this.classes) {
  if (obj.class === Npc) {
    if (obj.data.interact) {
      obj.data.interact();
    }
  }
}

Code Runner Challenge

Run this to see nested conditionals: outer checks the class type, inner checks for an interact method, deepest checks dialogue state. Same logic used in the Forest fork level.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Numbers โ€” Position, velocity, score tracking

// GameLevelMazeSub.js โ€” numeric properties on every sprite
const OCTOPUS_SCALE_FACTOR = 9;
STEP_FACTOR: 1000,
ANIMATION_RATE: 50,
INIT_POSITION: { x: 0.03, y: 0.88 },

Code Runner Challenge

Run this to see numbers used for position, scale, and speed โ€” the exact same properties set on the Octopus player in GameLevelMazeSub.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Strings โ€” Character names, sprite paths, game states

// GameLevelMazeSub.js โ€” strings for IDs, paths, and dialogue
id: 'Whispering Shadow',
src: path + "/images/gamify/tux.png",
greeting: "Keep going. The path winds upward.",

Code Runner Challenge

Run this to see string operations used in the game: path concatenation, template literals for dialogue, and string properties on NPC configs.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Booleans โ€” Flags (isJumping, isPaused, isVulnerable)

// GameLevelMazeSub.js + GameLevelForest.js โ€” booleans control game state
GRAVITY: true,
isPaused: false,
if (this.dialogueSystem && this.dialogueSystem.isDialogueOpen()) { ... }

Code Runner Challenge

Run this to see booleans used as game state flags โ€” GRAVITY, isPaused, dialogueOpen โ€” and how they control branching logic throughout the engine.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Arrays โ€” Game object collections, level data

// GameLevelMazeSub.js โ€” this.classes array holds every object in the level
this.classes = [
  { class: GameEnvBackground, data: image_data_cave },
  { class: Player,            data: sprite_data_octopus },
  { class: SplineBarrier,     data: seg1 },
  { class: Npc,               data: sprite_data_shadow },
];

Code Runner Challenge

Run this to see arrays used to store level objects and spline path data โ€” the two most critical array structures in the Maze of Shadows level.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Objects (JSON) โ€” Configuration objects, sprite data

// GameLevelMazeSub.js โ€” full sprite config object literal for the player
const sprite_data_octopus = {
  id: 'Octopus',
  SCALE_FACTOR: 9,
  STEP_FACTOR: 1000,
  INIT_POSITION: { x: 0.03, y: 0.88 },
  hitbox: { widthPercentage: 0.45, heightPercentage: 0.2 },
  keypress: { up: 87, left: 65, down: 83, right: 68 }
};

Code Runner Challenge

Run this to see nested object literals โ€” the sprite config pattern used for every character in the game. Includes dot notation and destructuring access.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Mathematical Operators โ€” Physics calculations

// GameLevelMazeSub.js โ€” spline() uses math to convert relative coords to pixels
x: Math.round(px * width),
y: Math.round(py * height)
// Sprite render size: pixels.width / SCALE_FACTOR

Code Runner Challenge

Run this to see all four arithmetic operators plus Math.round() used exactly as they appear in the spline helper and sprite sizing calculations.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

String Operations โ€” Path concatenation, text display

// GameLevelDesert.js / all levels โ€” template literals and concatenation
const src = path + "/images/gamify/tux.png";
const line = `${npc.id} says: "${npc.greeting}"`;

Code Runner Challenge

Run this to see string concatenation, template literals, and string methods โ€” all used across the game levels for building asset paths and dialogue text.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Boolean Expressions โ€” Compound conditions in game logic

// GameLevelForest.js โ€” compound boolean expressions controlling state
const canAct = !isPaused && !dialogueOpen;
if (isAlive && !isPaused) { ... }
if (dialogueSystem && dialogueSystem.isDialogueOpen()) { ... }

Code Runner Challenge

Run this to see &&, ||, and ! compound expressions โ€” the exact patterns used throughout all interact() and reaction() methods in the game.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Canvas Rendering โ€” Draw sprites, backgrounds, platforms

// Game engine draw() pattern โ€” used by every GameObject
draw() {
  this.ctx.drawImage(
    this.spriteSheet, sx, sy, sw, sh,
    this.position.x, this.position.y, this.width, this.height
  );
}
// SplineBarrier rendering:
this.ctx.strokeStyle = '#8B4513';
this.ctx.lineWidth = 22;
this.ctx.stroke();

Canvas rendering requires a live DOM โ€” proven in the playable game at Escape the Tower. The draw() pattern above is from the engineโ€™s base GameObject class.


GameEnv Configuration โ€” Set canvas size, difficulty levels

// GameLevelMazeSub.js โ€” gameEnv provides canvas dimensions used throughout
let width  = gameEnv.innerWidth;
let height = gameEnv.innerHeight;
let path   = gameEnv.path;

// All positions scale to the canvas:
INIT_POSITION: { x: 0.03, y: 0.88 }  // 3% from left, 88% from top

Code Runner Challenge

Run this to see how GameEnv configuration drives all object placement โ€” every position in the game is relative to the canvas size set in GameEnv.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

API Integration โ€” Implement Leaderboard API (POST/GET scores)

// Fetch with POST โ€” leaderboard score saving
const response = await fetch('/api/leaderboard', {
  method: 'POST',
  body: JSON.stringify({ score, player })
});
const data = await response.json();

Code Runner Challenge

Run this to see async fetch with POST and error handling โ€” simulated since we can't hit a real API here, but using the exact same pattern from the game.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

JSON Parsing โ€” Parse API responses

// Parse leaderboard API response
const res  = await fetch('/api/leaderboard');
const data = await res.json();
const topScore = data.scores[0].value;

Code Runner Challenge

Run this to see JSON.stringify and JSON.parse used on a leaderboard response โ€” the same structure returned by the game's backend API.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Console Debugging โ€” Use console.log to track game state

// GameLevelMazeSub.js โ€” strategic logging at level init and key transitions
console.log("Initializing GameLevelMazeSub...");
console.log('Correct door this run:', doorConfigs[correctIndex].id);

Code Runner Challenge

Run this to see strategic console.log placement โ€” the same debugging pattern used at the top of every level constructor and inside transition handlers.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Hit Box Visualization โ€” Draw/visualize collision boundaries

// Game engine hitbox debug rendering
this.ctx.strokeStyle = 'red';
this.ctx.lineWidth = 2;
this.ctx.strokeRect(
  this.position.x, this.position.y,
  this.width * hitbox.widthPercentage,
  this.height * hitbox.heightPercentage
);
// From sprite config:
hitbox: { widthPercentage: 0.45, heightPercentage: 0.2 }

Code Runner Challenge

Run this to see hitbox calculation from the Octopus sprite config โ€” the exact widthPercentage and heightPercentage values that define the collision boundary.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Source-Level Debugging โ€” Set breakpoints in DevTools

// Key breakpoint locations used during development:
// 1. interact() โ€” step through NPC dialogue logic
// 2. cleanAndTransition() โ€” inspect fade + level swap sequence
// 3. spline() โ€” verify pixel coordinate conversion
interact: function() {
  // โ† breakpoint here to inspect this.dialogueSystem state
  if (this.dialogueSystem && this.dialogueSystem.isDialogueOpen()) { ... }
}

Breakpoints set in the DevTools Sources tab during development โ€” proven by stepping through interact() in GameLevelMazeSub and cleanAndTransition() in GameLevelDoors. Open DevTools โ†’ Sources โ†’ set a breakpoint on any interact() line to replay.


Network Debugging โ€” Examine Network tab for API calls

// GameLevelForestWin.js โ€” NpcAiChat makes this fetch call, visible in Network tab
const res = await fetch('https://api.anthropic.com/v1/messages', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ model: 'claude-sonnet-4-20250514', ... })
});

Inspected in DevTools โ†’ Network tab during R2D2 AI chat in GameLevelForestWin. The POST to /v1/messages shows request headers, payload, and response โ€” used to debug CORS errors and confirm the AI response shape.


Application Debugging โ€” Examine cookies, localStorage

// Checked in DevTools โ†’ Application tab during development
// Login state stored in localStorage/cookies:
localStorage.getItem('user');
document.cookie; // session token

Inspected via DevTools โ†’ Application โ†’ Local Storage and Cookies to verify login state persisted correctly across level transitions, and to debug cases where the player was logged out unexpectedly mid-game.


Element Inspection โ€” Use Element Viewer to inspect canvas

// The game renders into #gameContainer โ†’ canvas#gameCanvas
// Inspected in DevTools โ†’ Elements to check:
document.getElementById('gameContainer');
// canvas position, z-index, and dimensions verified via Elements tab

Used DevTools โ†’ Elements to inspect #gameContainer and its child canvases during sublevel transitions (GameLevelMaze โ†’ GameLevelMazeSub). Confirmed z-index stacking and canvas cleanup by watching DOM nodes appear/disappear during cleanAndTransition().


Gameplay Testing โ€” Test level completion, character interactions

Live demo: full Maze of Shadows walkthrough โ€” player navigates the spline path, triggers Shadow and Lantern Keeper dialogue, reaches Exit Warden, and transitions to GameLevelDoors. Playable at Escape the Tower.


Integration Testing โ€” Test API integration with live backend

// GameLevelForestWin.js โ€” NpcAiChat tested end-to-end with live Anthropic API
const res = await fetch('https://api.anthropic.com/v1/messages', { ... });
if (!res.ok) throw new Error(`API ${res.status}`);
const data = await res.json();
return data.content.find(b => b.type === 'text')?.text ?? '...';

Code Runner Challenge

Run this to see the full API response handling pattern โ€” simulated to show how the game processes the Anthropic API reply and extracts the text content block.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

API Error Handling โ€” Try/catch blocks for API calls

// GameLevelForestWin.js โ€” NpcAiChat wraps every fetch in try/catch
try {
  const res = await fetch('https://api.anthropic.com/v1/messages', { ... });
  if (!res.ok) throw new Error(`API ${res.status}`);
  const data = await res.json();
  return data.content.find(b => b.type === 'text')?.text ?? '...';
} catch (e) {
  console.error('NPC AI error:', e);
}

Code Runner Challenge

Run this to see try/catch wrapping an async API call โ€” one succeeds, one throws a network error, one throws a bad status. The game continues normally after each failure.

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

ENDOFFILE echo โ€œdoneโ€