A pixel-art RPG. A three-level apology. One real story. Built from scratch with nothing but JavaScript, a canvas, and way too many feelings.
This didn't start as a "project."
It started as a feeling โ that hollow, restless kind you get when words stop being enough. When you've said sorry in every way language allows and it still doesn't feel like it captures the weight of what you actually mean.
So instead of another text, another call, another conversation that goes in circles โ this happened. A game. A whole world built from scratch, where every pixel placed was a sentence that couldn't be spoken out loud.
Three levels. Each one a different chapter of something real:
- A sunlit park where you pick up pieces of yourself
- A storm you have to fight your way through
- A bridge you build, question by question, over a chasm you created
It's not a masterpiece of engineering. It's not the most technically complex thing ever written. But it was made with everything. And sometimes that's the most powerful language there is.
This project was built with the assistance of AI (Claude by Anthropic) โ for the logic, the patterns, the structure. But every story beat, every dialogue line, every design choice? That was entirely human. That part, no AI can write for you.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ ๐ฎ A complete 3-level RPG โ in a single HTML file โ
โ ๐ฑ Runs on any phone, tablet, or desktop โ
โ ๐จ Hand-drawn pixel art sprites on HTML5 Canvas โ
โ ๐ฌ Typewriter dialogue system with a character queue โ
โ ๐ A quiz mechanic that literally builds a bridge โ
โ ๐ A boss fight against your own ego โ
โ ๐ Two endings โ both honest, both beautiful โ
โ โก Zero dependencies. Zero installs. Zero excuses. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
On your phone (the whole point):
1. Download RPG.html
2. Tap to open it
3. It runs in your browser instantly
That's it. No app store. No install. No account. No loading screen that makes you question your life choices. Just download one file, tap it, and you're in.
Works on:
- ๐ฑ Android (Chrome, Firefox, Samsung Browser)
- ๐ iPhone & iPad (Safari, Chrome)
- ๐ป Any desktop browser
- ๐ฅ๏ธ Literally anything with a modern browser
"Picking up the pieces."
The world is still bright here. Walk through a park scattered with letters โ 14 of them, each one a fragment of something worth saving. Find the pink flower. Use it to melt the thorny vine that's been blocking the way forward.
A gentle level. The calm before everything else.
"Fighting through the noise."
The sky turns dark. Five storm clouds rage through a maze โ they represent everything ugly: the ego, the anger, the words said in the wrong moment. Shoot them down with heart projectiles. Clear the storm. Find what's waiting at the other end.
The hardest level to move through. That's intentional.
"Building something from nothing."
A chasm splits the world in two. The only way across is to answer honestly โ five questions, five chances to prove something. Each right answer lays another plank on the bridge. Then cross it. Face your own ego as a literal final boss. Watch it fall.
Make your choice. That part is real.
| Button | Does |
|---|---|
| โฌ๏ธ โฌ๏ธ โฌ ๏ธ โก๏ธ | Move the character |
| Talk ยท Interact ยท Shoot hearts ยท Advance dialogue | |
| โ HINT | Get a nudge when you're stuck |
| ๐ GUIDE | Full step-by-step level walkthrough |
| Key | Does |
|---|---|
Arrow Keys |
Move |
Space / Enter |
Action |
This game is fully customisable. Fork it. Change the names. Rewrite every line of dialogue. Make it your own love story, your own apology, your own celebration.
Here's where to look:
| What to change | Where to find it |
|---|---|
| Character names | Search [Male Character] and [Female Character] โ replace everywhere |
| Intro story text | game.init() โ the text variable at the top |
| All dialogue lines | Search 'Insert your custom dialogue' โ replace each one |
| MCQ questions | mcq.questions array โ write your own questions and answers |
| Ending messages | game.makeChoice() โ update both the forgive and wait endings |
| Player speed | this.speed = 1.6 in the Player constructor |
| Number of letters | Level 1 setup โ the letters and positions arrays |
Single HTML file (~1,700 lines)
โโโ CSS โ pixel-art rendering, responsive layout, animations
โโโ HTML โ canvas + UI overlays + on-screen controls
โโโ JavaScript
โโโ State machine (INTRO โ PLAYING โ DIALOGUE โ MCQ โ END)
โโโ Player class (movement, collision, animation, inventory)
โโโ Level class (world setup, enemies, collectibles, drawing)
โโโ Dialogue system (typewriter queue with cached DOM refs)
โโโ MCQ system (quiz โ bridge block counter)
โโโ Game loop (requestAnimationFrame + screen shake)
No frameworks. No bundler. No node_modules folder haunting your hard drive.
Just one file that does everything.
- Zero-jank dialogue โ DOM elements are cached once at init, written to once per character reveal. No per-frame
getElementByIdcalls causing reflow. - Axis-split collision โ X and Y collision checked independently so the character slides along walls instead of stopping dead.
- Diagonal normalisation โ movement vector is normalised so diagonal speed equals cardinal speed.
- State-preserving modals โ hint and guide overlays save the previous game state and restore it on close, so opening a hint mid-dialogue doesn't break the story.
- Anti-double-fire keyboard โ action key tracked with a
keydownguard flag so holding Enter doesn't flood the game with events.
MIT โ completely open source. Take it, break it, rebuild it. Make someone cry happy tears with it.
The only rule: don't use it to hurt anyone. This whole thing was built on the opposite of that.
| Thing | Why |
|---|---|
| HTML5 Canvas | Drawing every pixel of the game world |
| Vanilla JavaScript | Running every frame of logic |
| CSS | Making the UI look like it belongs |
| Claude (Anthropic) | AI assistance for logic patterns and code structure |
| One human heart | Everything else |