Portfolio Home
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!
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 andcleanAndTransition()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/messagesshows 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
#gameContainerand its child canvases during sublevel transitions (GameLevelMaze โ GameLevelMazeSub). Confirmed z-index stacking and canvas cleanup by watching DOM nodes appear/disappear duringcleanAndTransition().
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.
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.
ENDOFFILE echo โdoneโ