2D side-scrolling platformer written in C using SDL2 -- browser-playable via WebAssembly
Super Mango is a 2D side-scrolling platformer built in C11 with SDL2, designed as an educational project with well-commented source code that can be read as a learning resource for C + SDL2 game development. The game features multi-screen TOML levels with parallax backgrounds, one-way platforms, floating platforms, crumble bridges, floor gaps, collectible coins, climbable vines/ladders/ropes, six enemy types, seven hazard types, bouncepads, animated water, fog overlays, a start menu, HUD, level-completion summary, and next-phase flow. Levels are defined in TOML and loaded at runtime, with a standalone visual level editor for creating and editing levels. It renders at a 400x300 logical resolution scaled 2x to an 800x600 window for a chunky pixel-art look, with frame-rate-independent movement via delta-time physics. The project builds natively on macOS, Linux, and Windows, and compiles to WebAssembly via Emscripten for browser play.
| Technology | Version | Purpose |
|---|---|---|
| C | C11 | Language standard (clang -std=c11) |
| SDL2 | 2.x | Window, renderer, input, events, timing |
| SDL2_image | 2.x | PNG texture loading |
| SDL2_ttf | 2.x | TrueType font rendering |
| SDL2_mixer | 2.x | Sound effects and music |
| tomlc17 | vendored | TOML v1.1 parser for level definitions |
| Emscripten | latest | WebAssembly compilation for browser play |
- 2D side-scrolling platformer with dynamic multi-screen TOML worlds, from the 4-screen sandbox to longer volcanic stages
- 32 render layers drawn back-to-front: parallax background, platforms, floor, enemies, player, fog, HUD, debug overlay
- Delta-time physics for frame-rate-independent movement at 60 FPS (VSync + manual fallback)
- Six enemy types: spiders, jumping spiders, birds, faster birds, fish, faster fish
- Seven hazard types: spike rows, spike blocks, spike platforms, circular saws, axe traps, blue flames, fire flames
- Collectibles: coins (100 pts each, 3 coins restore a heart), star yellow, star green, star red health pickups, end-of-level last star
- Climbable vines, ladders, and ropes; three bouncepad variants (small, medium, high)
- TOML-based level format with runtime level loading (
--level path/to/level.toml) andnext_phasetransitions - Pause, game-over, and end-of-level overlays: Esc/Start pauses or resumes gameplay, game over waits for Enter/Space/Start before restarting, Enter/Space/Start continues to the next phase when a completion overlay is shown, and Esc/Back exits terminal overlays
- Start menu, HUD (hearts/lives/score), lives system, invincibility blink on damage
- Keyboard and gamepad (hot-plug) controls
- Debug overlay (
--debugflag): FPS counter, CPU frame time, memory usage, collision hitbox visualization, scrolling event log - Builds natively on macOS, Linux, and Windows; WebAssembly build via Emscripten
Super Mango includes a standalone visual level editor built with C11 and SDL2. The editor lets you create and edit levels with a point-and-click interface, then save them as TOML files or export them as C source for embedding.
Editor features:
- Scrollable canvas with zoom, grid snapping, and select/place/delete tools
- Entity palette with all game objects: platforms, enemies, hazards, collectibles, surfaces, effects
- Per-entity property editing (position, size, speed, animation, behavior)
- TOML serialization (save/load
.tomllevel files) - C code exporter (generates
.c/.hfiles for compiled-in levels) - Undo/redo history, copy/paste, recent files, autosave, and dirty-state indicators
- Validation status for the active level; validation errors block save, export, and playtest
- Native file dialogs
- Headless smoke mode for CI (
--smoke-test)
Build and run the editor:
make editor # build the editor binary into out/
make run-editor # build and run the editorSuper Mango is developed with the help of four specialized Claude Code agents, each owning a distinct part of the project. Call them by name with slash commands in any Claude Code session inside this repository.
| Agent | Command | Role | Owns |
|---|---|---|---|
| Bosser | /bosser-engineer |
Chief Engineer | C source, SDL2 engine, editor, Makefile, architecture, bug fixes |
| Lugio | /lugio-creator |
Level Builder | TOML level files, entity placement, theming, difficulty balancing |
| Goobma | /goobma-designer |
Pixel Art Designer | Sprite assets, palette remapping, frame layout analysis |
| Warro | /warro-inscriber |
Documentation Inscriber | README, CLAUDE.md, wiki, GitHub Pages docs, cross-referencing |
| You want to... | Call |
|---|---|
| Add a new enemy, surface, or hazard type | /bosser-engineer |
| Fix a bug or refactor engine code | /bosser-engineer |
| Create a new level or redesign an existing one | /lugio-creator |
| Design a new sprite or create a theme variant | /goobma-designer |
| Update documentation or audit for accuracy | /warro-inscriber |
- Be specific about what you want. "Add a spider that jumps higher" gives Bosser a clear target. "Make the game better" does not.
- One agent at a time. Each agent stays in their lane. If you ask Lugio to fix a bug, he'll tell you to call Bosser. That's by design.
- Bosser delegates. If you're unsure who to call, start with
/bosser-engineer-- he'll route the work to the right crew member or handle it himself. - Lugio needs a theme. When requesting a level, tell him the theme (forest, volcanic, sky), difficulty (easy/medium/hard), and length (number of screens). He'll ask if you don't.
- Goobma needs a reference. When requesting a sprite, point him at an existing asset in the same category. He matches dimensions, palette, and style automatically.
- Warro verifies against code. He reads source files and runs analysis tools before writing a single word. If the docs say one thing and the code says another, Warro trusts the code.
A C11-compatible compiler (clang or gcc), make, and the SDL2 development libraries.
macOS:
brew install sdl2 sdl2_image sdl2_ttf sdl2_mixer
xcode-select --install # provides clang and makeLinux (Debian/Ubuntu):
sudo apt update
sudo apt install build-essential clang \
libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-devWindows (MSYS2 UCRT64):
pacman -S mingw-w64-ucrt-x86_64-clang \
mingw-w64-ucrt-x86_64-make \
mingw-w64-ucrt-x86_64-SDL2 \
mingw-w64-ucrt-x86_64-SDL2_image \
mingw-w64-ucrt-x86_64-SDL2_ttf \
mingw-w64-ucrt-x86_64-SDL2_mixerWebAssembly: Install the Emscripten SDK and ensure emcc is on PATH.
make CC=clang # build the game binary into out/
make run CC=clang # build and run
make run-debug CC=clang # build and run with debug overlay
make run-level CC=clang LEVEL=levels/00_sandbox_01.toml # run a specific TOML level
make run-level-debug CC=clang LEVEL=levels/00_sandbox_01.toml # run a level with debug overlay
make editor CC=clang # build the level editor
make run-editor CC=clang # build and run the level editor
make test CC=clang # build and run 13 native regression tests
make validate-levels # validate all levels/*.toml files
make web # build to WebAssembly (requires Emscripten)
make clean # remove all build artifactsFor local/CI parity, pass
CC=clangexplicitly. GNU Make has a built-inCC=cc, so the Makefile'sCC ?= clangdefault may not select clang on every machine unless overridden.
Or just play in your browser -- no build required. Full project documentation is available at the docs site.
super-mango-editor/
├── Makefile Build system (clang, sdl2-config, ad-hoc codesign)
├── levels/ TOML level definitions
│ ├── 00_sandbox_01.toml Level data loaded at runtime
│ ├── 01_lugio_01.toml Level data loaded at runtime
│ └── 02_lugio_02.toml Level data loaded at runtime
├── src/ C source files and headers
│ ├── main.c Entry point: SDL init/teardown
│ ├── game.h Shared GameState/constants declarations
│ ├── collectibles/ Pickup items
│ │ ├── coin.h / .c Coin (100 pts, 3 restore a heart)
│ │ ├── star_yellow.h / .c Yellow star health pickup
│ │ ├── star_green.h / .c Green star health pickup
│ │ ├── star_red.h / .c Red star health pickup
│ │ └── last_star.h / .c End-of-level star
│ ├── collision/ Gameplay collision and damage passes
│ ├── core/ Runtime lifecycle, window/timing/resources, update, camera, checkpoint, completion, overlay, actor/hazard helpers
│ │ ├── debug.h / .c Debug overlay (FPS, CPU, memory, hitboxes, event log)
│ │ ├── game_lifecycle.c game_init / game_cleanup orchestration
│ │ ├── game_loop.c Main native/WebAssembly frame loop
│ │ ├── game_update.h / .c Top-level update orchestration
│ │ └── game_* helpers Window, resources, timing, camera, checkpoint, overlay, actors, hazards, surfaces
│ ├── editor/ Standalone visual level editor
│ │ ├── editor_main.c Editor entry point
│ │ ├── editor.h / .c Editor state and high-level glue
│ │ ├── canvas/palette/properties/tools/ui modules
│ │ ├── editor_frame/events/chrome/panels/layout/textures modules
│ │ ├── editor_files/session/playtest/clipboard/validation modules
│ │ ├── serializer*.h / .c TOML save/load orchestration and staged parsers
│ │ ├── exporter.h / .c C code export (.c/.h generation)
│ │ ├── file_dialog.h / .c Native file dialogs
│ │ └── undo*.h / .c Undo/redo history and operation application
│ ├── effects/ Visual effects
│ │ ├── fog.h / .c Fog overlay
│ │ ├── parallax.h / .c Multi-layer scrolling background
│ │ └── water.h / .c Animated water strip
│ ├── entities/ Enemies
│ │ ├── spider.h / .c Spider (ground patrol)
│ │ ├── jumping_spider.h / .c Jumping spider
│ │ ├── bird.h / .c Bird (sine-wave sky patrol)
│ │ ├── faster_bird.h / .c Fast bird
│ │ ├── fish.h / .c Fish (jumping water patrol)
│ │ └── faster_fish.h / .c Fast fish
│ ├── hazards/ Damaging obstacles
│ │ ├── spike.h / .c Ground spike rows
│ │ ├── spike_block.h / .c Rail-riding spike
│ │ ├── spike_platform.h / .c Elevated spike
│ │ ├── circular_saw.h / .c Rotating saw
│ │ ├── axe_trap.h / .c Swinging axe
│ │ └── blue_flame.h / .c Blue flame / fire flame
│ ├── input/ SDL keyboard/gamepad events, browser input bridge, deterministic replay injection
│ ├── levels/ Level system
│ │ ├── level.h Shared level definitions (LevelDef struct)
│ │ ├── level_loader.h / .c TOML level loading and switching
│ │ ├── level_path/resources/session/physics helpers
│ │ ├── phase_transition.h / .c next_phase resolution and progress helpers
│ │ ├── level_validate.c LevelDef count validation
│ │ └── exported/ Auto-generated C level data
│ ├── player/ Player module split into lifecycle, input, motion, jump, climb, surface, and animation files
│ ├── render/ `game_render` frame order and `render_overlay` foreground/overlay helpers
│ ├── screens/ Game screens
│ │ ├── start_menu.h / .c Start menu
│ │ └── hud.h / .c HUD (hearts, lives, score)
│ └── surfaces/ Traversable objects
│ ├── platform.h / .c One-way platform pillars (9-slice)
│ ├── float_platform.h / .c Hovering platforms (static/crumble/rail)
│ ├── bridge.h / .c Crumble walkways
│ ├── bouncepad.h / .c Bouncepad base + 3 variants (small/medium/high)
│ ├── rail.h / .c Rail path system
│ ├── vine.h / .c Climbable vine
│ ├── ladder.h / .c Climbable ladder
│ └── rope.h / .c Climbable rope
├── assets/ All game assets
│ ├── sprites/ PNG sprites and tilesets
│ │ ├── backgrounds/ Parallax background layers
│ │ ├── foregrounds/ Fog and foreground overlays
│ │ ├── collectibles/ Coins, stars
│ │ ├── entities/ Enemy sprite sheets
│ │ ├── hazards/ Hazard sprite sheets
│ │ ├── levels/ Floor tiles and level-specific assets
│ │ ├── player/ Player sprite sheet
│ │ ├── screens/ Menu and HUD sprites
│ │ ├── surfaces/ Platforms, bridges, vines, ladders, ropes
│ │ └── unused/ Reserve assets from asset pack
│ ├── sounds/ WAV sound effects
│ │ ├── collectibles/ Pickup sounds
│ │ ├── entities/ Enemy sounds
│ │ ├── hazards/ Hazard sounds
│ │ ├── levels/ Level music and ambient
│ │ ├── player/ Player action sounds
│ │ ├── screens/ Menu sounds
│ │ ├── surfaces/ Surface interaction sounds
│ │ └── unused/ Reserve sound files
│ └── fonts/ TrueType fonts
│ └── round9x13.ttf Debug overlay font
├── vendor/ Vendored third-party libraries
│ └── tomlc17/ TOML v1.1 parser (tomlc17.c/.h)
├── tests/ Native regression test harnesses
├── docs/ Astro GitHub Pages documentation site
├── web/ Emscripten shell template
└── .github/workflows/ CI/CD pipelines
├── build.yml Build check (PRs) + release creation (main)
├── codeql.yml Code security analysis
├── docs.yml Docs lint/build checks
└── deploy.yml GitHub Pages deployment
Four GitHub Actions workflows:
| Workflow | File | Trigger | Purpose |
|---|---|---|---|
| Build & Release | build.yml |
Push to main, pull requests |
Multi-platform build (Linux x86_64, macOS arm64, Windows x86_64, WebAssembly); on main push: GitHub Release creation |
| Docs | docs.yml |
Docs pull requests, manual | Bun install, docs lint, and Astro docs build |
| CodeQL | codeql.yml |
Push/PR to main, weekly |
Automated code security and quality analysis |
| Deploy Pages | deploy.yml |
Successful main Build & Release workflow | Builds docs, copies WebAssembly artifacts, and deploys GitHub Pages |
The Build & Release workflow runs make, make test, make validate-levels, make editor, dummy-SDL smoke tests, scripted replay smoke on Linux, WebAssembly build, WebAssembly artifact checks, and release creation on main. The Docs workflow runs bun run lint and bun run build for PRs touching docs/. The Deploy Pages workflow publishes the Astro docs output plus WebAssembly artifacts to GitHub Pages.
MIT -- see LICENSE