A zero-dependency 2D platformer built with pure JavaScript, HTML Canvas, and ECS (Entity-Component-System) architecture. No external librariesโjust hand-crafted game engine fundamentals.
๐ฎ Play Demo
- Pure Vanilla JS: No Phaser, Pixi, or any runtime libraries
- ECS Architecture: Data-driven design with modular components and systems
- Tiled Integration: Level loading from Tiled JSON exports
- Fixed Timestep: Deterministic 60Hz physics simulation
- AABB Collision: Per-axis collision resolution
- Educational: Learn game engine fundamentals from scratch
# Clone the repository
git clone https://github.com/your-username/vanilla-platformer-js.git
cd vanilla-platformer-js
# Serve locally (required for asset loading)
python -m http.server 8000
# OR
npx http-server
# Open http://localhost:8000
Input | Action |
---|---|
WASD / Arrow Keys | Move left/right, look up/down |
Space | Jump |
F1 | Toggle debug overlay |
F2 | Toggle hitboxes |
F3 | Slow motion (0.25x speed) |
F4 | Toggle tile grid |
` (Backtick) | Pause/unpause |
. (Period) | Frame step (when paused) |
- Entities: Unique IDs with component bitmasks
- Components: Pure data structures (
Transform
,Velocity
,AABB
, etc.) - Systems: Single-responsibility logic processors
Input โ Physics โ Collision โ AI โ Camera โ Render
- InputSystem: Keyboard state management
- PhysicsSystem: Semi-implicit Euler integration
- CollisionSystem: Per-axis AABB resolution
- RenderSystem: Canvas drawing with layers
- LevelSystem: Tiled JSON loading pipeline
vanilla-platformer-js/
โโโ index.html # Main entry point
โโโ styles.css # Base styling
โโโ src/
โ โโโ main.js # Game bootstrap & loop
โ โโโ config.js # Physics constants & tunables
โ โโโ debug.js # Debug flags & profiler
โ โโโ input.js # Keyboard input management
โ โโโ core/ # Engine utilities
โ โ โโโ math.js # AABB, clamp, lerp functions
โ โ โโโ events.js # Event bus (pub/sub)
โ โ โโโ ...
โ โโโ ecs/ # ECS framework
โ โ โโโ world.js # Entity registry & queries
โ โ โโโ components.js # Component definitions
โ โ โโโ systems.js # Base system class
โ โโโ systems/ # Game logic systems
โ โ โโโ input-system.js
โ โ โโโ physics-system.js
โ โ โโโ collision-system.js
โ โ โโโ render-system.js
โ โ โโโ ...
โ โโโ entities/ # Entity factories
โ โโโ render/ # Rendering utilities
โโโ assets/
โโโ maps/ # Tiled JSON levels
โโโ tilesets/ # Tileset JSON + PNG
โโโ characters/ # Character manifests & sprites
โโโ items/ # Collectibles & props
โโโ backgrounds/ # Parallax layers
โโโ audio/ # SFX & music
Create levels using Tiled Map Editor:
-
Required Layers:
TilesBG
- Background decorationTilesSolids
- Collision layerTilesFG
- Foreground decorationObjects
- Entity spawn points
-
Tileset Properties:
{ "name": "solid", "type": "bool", "value": true }
-
Object Types:
PlayerSpawn
- Player starting positionEnemyBasic
- Patrolling enemyCoin
- Collectible itemGoal
- Level exitHazard
- Damage zone
Per-action image approach with manifest files:
{
"name": "hero",
"aabb": { "w": 16, "h": 24 },
"actions": {
"idle": { "image": "idle.png", "origin": [8, 24] },
"run": { "image": "run.png", "origin": [8, 24] },
"jump": { "image": "jump.png", "origin": [8, 24] },
"fall": { "image": "fall.png", "origin": [8, 24] }
}
}
Physics parameters in src/config.js
:
export const PHYSICS = {
GRAVITY_Y: 1800, // Gravity acceleration
MOVE_ACCEL: 1500, // Horizontal acceleration
MAX_RUN_SPEED: 180, // Maximum run speed
JUMP_VELOCITY: -520, // Jump initial velocity
COYOTE_TIME: 0.08, // Edge jump tolerance
JUMP_BUFFER: 0.08 // Jump input buffer
};
- FPS and frame time
- System performance profiling
- Entity counts and collision stats
- Player position and velocity
- Physics flags (onGround, hitWall, etc.)
- F2: Entity hitboxes and collision bounds
- F3: Slow motion for collision analysis
- F4: Tile grid overlay
- `: Pause simulation, . step frame-by-frame
// Available in browser console
debug.tp(x, y) // Teleport player
debug.seed(12345) // Set random seed
debug.replayExport() // Export input recording
debug.give('coin', 5) // Give items
Current implementation follows a staged approach:
- Stage 0: Scaffold & ECS foundation
- Stage 1: Player movement & physics
- Stage 2: AABB collision system โ
- Stage 3: Camera follow & scrolling
- Stage 4: Tiled JSON level loading
- Stage 5: Collectibles & HUD
- Stage 6: Enemies & health system
- Stage 7: Visual & audio polish
- Stage 8: Build & deployment
# Feature development
git checkout -b feature/stage3-camera-follow
git commit -m "feat(camera): add dead zone following"
# Stage completion
git checkout develop
git merge --no-ff feature/stage3-camera-follow
git tag v0.1.0 -m "Stage 3: Camera system complete"
# Simple HTTP server (required for CORS)
python -m http.server 8000
# Build script copies files and disables debug
rm -rf dist && mkdir -p dist
cp index.html styles.css dist/
cp -R src assets dist/
sed -i 's/export const DEBUG = true/export const DEBUG = false/' dist/src/debug.js
Automated via .github/workflows/pages.yml
:
- Triggers on version tags (
v*
) - Builds static files to
dist/
- Deploys to GitHub Pages
- Smooth acceleration/deceleration
- Consistent jump height
- Proper gravity feel
- No penetration through platforms
- Edge jump behavior (coyote time)
- No wall sticking at high speeds
- Proper ground detection
- Ceiling collision stops upward movement
- Per-axis resolution prevents tunneling
- Dead zone prevents jitter
- Map boundary clamping
- No visual tearing at pixel boundaries
- Tiled JSON loads without errors
- Objects spawn at correct positions
- Unknown object types log warnings only
- Tileset properties correctly parsed
- 60 FPS on desktop browsers (Chrome, Firefox, Edge)
- <16.6ms total frame time
- <4ms collision system overhead
- <8ms rendering system overhead
- Zero garbage collection spikes during gameplay
- All code and comments in English
- Conventional Commits:
feat(collision): add per-axis resolution
- ES Modules with explicit imports/exports
- PascalCase for classes, camelCase for variables
- UPPER_SNAKE_CASE for constants
Comprehensive documentation available in /docs/
:
- Project Architecture
- Level Format & Tools
- Roadmap & Milestones
- Coding Standards
- QA & Playtest Plan
- Debug & Instrumentation
- ECS architecture foundation
- Fixed timestep game loop (60Hz)
- Keyboard input system
- Semi-implicit Euler physics
- Per-axis AABB collision resolution
- Debug overlay with profiling
- Tile-based collision detection
- Camera follow system with dead zones
- Tiled JSON level loading pipeline
- Character animation state machine
- Collectible items & HUD system
- Basic enemy AI with patrol behavior
- Health/damage system with respawn
- Audio system (SFX & background music)
- Build pipeline & GitHub Pages deployment
Compatible with Tiled Map Editor:
- Create orthogonal maps with 16ร16 tile size
- Use named layers:
TilesBG
,TilesSolids
,TilesFG
,Objects
- Set tileset properties for collision detection
- Export as JSON format (not TMX)
- Place objects with appropriate
type
properties
Black screen with console errors:
- Ensure you're serving via HTTP (not file://)
- Check browser console for CORS errors
- Verify asset paths use relative URLs
Stuttering or low FPS:
- Open debug overlay (F1) to check system profiling
- Try slow motion (F3) to analyze performance bottlenecks
- Reduce tile density or visible area
Collision glitches:
- Enable hitbox visualization (F2)
- Use frame stepping (` then .) to analyze collision resolution
- Check MTV clamping and per-axis ordering
MIT License - see LICENSE file for details.