๐ŸŸจ My First Browser Game ยท Episode 6 of 6 ยท See All Episodes
๐ŸŒฒ Episode 6 ยท Series Finale ยท Extends the Episode 5 Builder

Beyond the Builder!
Platformer Part 2

You built a platformer in the Episode 5 live builder, now take the training wheels off. Write the whole thing yourself in one file, then add double jump, wall slide, a parallax camera and your own level format.

๐Ÿ‘ถ Ages 10+ โฑ๏ธ ~2 Hours ๐ŸŸจ JavaScript โœ“ Free
๐Ÿฆ˜ Double jump ๐Ÿง— Wall slide ๐ŸŽฅ Parallax camera ๐Ÿ—บ๏ธ Level strings ๐Ÿ‘พ Enemies ๐Ÿ Timer & goals
โญ
0 XP
Level 1
๐Ÿ”ฅ0
Your Progress 0 / 6 steps
1
๐Ÿ—๏ธ
Your Own Engine File
Rebuild the core loop from memory, no builder
Active
๐ŸŽฏ
Goal for this step

Write the complete platformer core in a fresh file, unassisted.

  • 1New platformer2.html: canvas 800ร—480, rAF loop, player object {x, y, vx, vy, onGround}.
  • 2Gravity 0.5/frame, arrows set vx ยฑ4, jump sets vy โˆ’11 when grounded. Platform landing: the falling-only rule.
  • 3This time write it WITHOUT looking at the builder. Stuck? Peek, close the tab, write from memory. That struggle is the learning.
  • 4Working core in one sitting = you have genuinely internalised the platformer.
platformer2.html
const player = { x: 100, y: 380, vx: 0, vy: 0, w: 30, h: 40, onGround: false };
const keys = {};
document.addEventListener("keydown", e => keys[e.key] = true);
document.addEventListener("keyup",   e => keys[e.key] = false);

function update() {
    player.vx = 0;
    if (keys["ArrowLeft"])  player.vx = -4;
    if (keys["ArrowRight"]) player.vx = 4;
    player.vy += 0.5;
    player.x += player.vx;
    player.y += player.vy;
    // ... platform landing (you know this!) ...
}
โœ๏ธ
Fill in the Blanks
+15 XP
The keys object tracks held keys: keydown sets a key , keyup sets it . Gravity adds 0.5 to every frame.
๐Ÿง 
Knowledge Check
+15 XP
Why rebuild from memory instead of copying the builderโ€™s output?
ACopying is cheating
BRecall is how skills stick, code you can rebuild is code you truly own
CThe builder code is wrong
2
๐Ÿฆ˜
Double Jump
A jump counter instead of a boolean
Locked
๐ŸŽฏ
Goal for this step

Allow exactly two jumps: ground jump plus one air jump.

  • 1Replace the onGround-only jump gate with a counter: jumpsLeft.
  • 2Landing resets it to 2; each jump consumes 1; jump allowed while > 0.
  • 3Make the air jump slightly weaker (โˆ’9 vs โˆ’11), it reads as a "flip" and keeps level design sane.
  • 4Jump on keydown EVENT (not the held-keys object) so each press is one jump.
platformer2.html
let jumpsLeft = 2;

// on landing:
player.onGround = true;
jumpsLeft = 2;

// keydown handler:
if (e.key === "ArrowUp" && jumpsLeft > 0) {
    player.vy = (jumpsLeft === 2) ? -11 : -9;
    jumpsLeft--;
    player.onGround = false;
}
โŒจ๏ธ
Code Challenge
+20 XP
Implement the two-stage jump:
platformer2.html
if (e.key === "ArrowUp" && jumpsLeft > ) {
    player.vy = (jumpsLeft === 2) ? -11 : ;
    jumpsLeft;
}
๐Ÿ’ก Hint: Any remaining jump allows a press; the second (air) jump is the weaker value; then spend one.
๐Ÿง 
Knowledge Check
+15 XP
Generalising onGround (bool) to jumpsLeft (number) means triple jump isโ€ฆ
AA rewrite
BChanging the 2 to a 3, good abstractions make features one-number cheap
CImpossible
3
๐Ÿง—
Wall Slide & Wall Jump
Cling to walls, kick off them
Locked
๐ŸŽฏ
Goal for this step

Add the wall slide and the wall jump, advanced movement.

  • 1Detect wall contact: horizontal collision with a platform side while airborne โ†’ onWall = ยฑ1 (which side).
  • 2While on a wall and falling: cap vy at 1.5, the slide.
  • 3Wall jump: jump while onWall โ†’ vy = โˆ’10, vx = โˆ’onWall * 6 (kick AWAY), and refresh jumpsLeft to 1.
  • 4Suddenly your level design vocabulary includes shafts and climbs. Sketch a tower level to feel it.
platformer2.html
let onWall = 0;    // -1 left wall, 1 right wall, 0 none

// during horizontal collision resolution:
if (hitLeftSide)  onWall = 1;
if (hitRightSide) onWall = -1;

// the slide (after gravity):
if (onWall !== 0 && !player.onGround && player.vy > 1.5)
    player.vy = 1.5;

// wall jump in the keydown handler:
if (e.key === "ArrowUp" && onWall !== 0 && !player.onGround) {
    player.vy = -10;
    player.vx = -onWall * 6;    // kick away from the wall
    jumpsLeft = 1;
}
โœ๏ธ
Fill in the Blanks
+15 XP
The slide caps falling speed at while touching a wall. A wall jump kicks AWAY by setting vx to -onWall ร— .
๐Ÿง 
Knowledge Check
+15 XP
Why does the wall jump push AWAY from the wall?
ATo look cool
BPhysics-fiction that creates the zig-zag climb, jumping INTO the wall would glue you to it
CJavaScript sign rules
4
๐ŸŽฅ
Parallax Camera
Layered backgrounds moving at different speeds
Locked
๐ŸŽฏ
Goal for this step

Add a camera plus depth illusion with parallax layers.

  • 1Camera: camX = player.x โˆ’ 400, clamped to the level (your Python skill, back again).
  • 2Parallax: draw 2-3 background layers offset by camX ร— factor, hills at 0.3, clouds at 0.1. Slower = further away.
  • 3The brain reads different scroll speeds as DEPTH, a flat canvas becomes a world.
  • 4Foreground world subtracts full camX as usual.
platformer2.html
const camX = Math.max(0, Math.min(LEVEL_W - 800, player.x - 400));

// far clouds (barely move):
drawClouds(-camX * 0.1);
// mid hills:
drawHills(-camX * 0.3);
// world (full speed):
ctx.save();
ctx.translate(-camX, 0);
drawWorld();
ctx.restore();
๐Ÿ’ก
ctx.translate inside save/restore shifts EVERYTHING you draw, it is sf::View for the browser. No per-draw offsets needed.
โŒจ๏ธ
Code Challenge
+20 XP
Draw the world through a translated camera:
platformer2.html
ctx.();
ctx.translate(, 0);
drawWorld();
ctx.();
๐Ÿ’ก Hint: Snapshot the canvas state, shift the origin left by the camera, draw, then restore the state.
๐Ÿง 
Knowledge Check
+15 XP
Clouds at 0.1ร— scroll look further away than hills at 0.3ร— becauseโ€ฆ
AThey are drawn smaller
BParallax: in real life distant objects shift less as you move, the brain decodes speed as depth
CCanvas blurs them
5
๐Ÿ—บ๏ธ
Levels as Text
Design levels with ASCII strings
Locked
๐ŸŽฏ
Goal for this step

Define your world as strings and parse them into platforms.

  • 1A level is an array of strings: # ground, = platform, ^ spike, o coin, E enemy, F flag, each char one 40px tile.
  • 2A parse function walks rows/columns and fills your arrays (platforms, spikes, coins, enemies, flag).
  • 3Now design in your editor: type a mountain! (This is Python Breakoutโ€™s pattern idea, expanded.)
  • 4Adjacent # cells can merge into wide rects for performance, optional polish.
platformer2.html
const LEVEL = [
    "                            F ",
    "                        ====  ",
    "            o     E           ",
    "     o    =====  =====   ^^   ",
    "   ====                ====== ",
    "        ^^    E               ",
    "##############################",
];

function parse(level) {
    for (let r = 0; r < level.length; r++)
        for (let c = 0; c < level[r].length; c++) {
            const ch = level[r][c];
            const x = c * 40, y = r * 40;
            if (ch === "#" || ch === "=")
                platforms.push({ x: x, y: y, w: 40, h: 40 });
            if (ch === "o") coins.push({ x: x + 11, y: y + 11 });
            if (ch === "^") spikes.push({ x: x, y: y + 20 });
            if (ch === "E") enemies.push(makeEnemy(x, y));
            if (ch === "F") flag = { x: x, y: y };
        }
}
โœ๏ธ
Fill in the Blanks
+15 XP
Each character maps to one px tile. The parser turns text into the platforms, coins, spikes, enemies and arrays.
๐Ÿง 
Knowledge Check
+15 XP
The biggest win of ASCII levels isโ€ฆ
ASmaller files
BYou SEE the level shape in the code and can edit it like a drawing, design speed goes way up
CFaster collision
6
๐Ÿ
Enemies, Timer & The Wrap
Stomp enemies, race the clock, finish the series
Locked
๐ŸŽฏ
Goal for this step

Wire in patrol enemies, a speedrun timer, and complete the series.

  • 1Patrol enemies + stomp: your Python Part 2 logic, JavaScript spelling, you can port it without help now (that is the test!).
  • 2Speedrun timer: performance.now() at level start; show elapsed; save the best per level in localStorage.
  • 3Series review, you have used: canvas & DOM, rAF, events, arrays & objects, algorithms (Fisher-Yates!), localStorage, touch input, parallax and a level format.
  • 4You can now build almost ANY 2D idea in a single HTML file people open with a click. That is a superpower. Use it. ๐Ÿ†
platformer2.html
const startTime = performance.now();

// on reaching the flag:
const secs = ((performance.now() - startTime) / 1000).toFixed(1);
const key = "plat2-best-" + levelIndex;
const best = Number(localStorage.getItem(key) || 9999);
if (secs < best) localStorage.setItem(key, secs);
msg = "Level clear in " + secs + "s (best " +
      Math.min(secs, best) + "s)";
โŒจ๏ธ
Code Challenge
+20 XP
Time the run with the high-precision clock:
platformer2.html
const secs = ((performance.() - startTime) / ).toFixed(1);
๐Ÿ’ก Hint: The browserโ€™s precise timer returns milliseconds, divide to get seconds, one decimal place.
๐Ÿง 
Knowledge Check
+15 XP
Six episodes of browser games. What makes JavaScript games uniquely shareable?
AThey are smaller
BZero install: one file or one link and ANY device with a browser plays it instantly
CThey run faster than C++
๐ŸŽ‰๐Ÿ†๐ŸŽฎโœจ๐ŸŽ‰
Workshop Complete!
Double jumps, wall slides, parallax and hand-written levels, six episodes and the browser is your game console. Build something original next! ๐ŸŸจ๐Ÿ†
0
Total XP
1
Level
0
Best Streak
0%
Accuracy
โญ View My Progress & Certificates

This workshop was free and took many hours to build. If it helped you learn something new, consider supporting the project.

☕ Support on Ko-fi