Heaps.io is a 2D/3D game engine written in Haxe (used by Dead Cells and Northgard). The Haxe compiler targets JavaScript, producing a single .js bundle you can serve as static files alongside a tiny HTML shell.
Setup
Install Haxe and the heaps library once:
# brew install haxe / apt install haxe / etc.
haxelib install heaps
Minimal project layout:
my-game/
├── build.hxml
├── src/
│ └── Main.hx
├── bin/
│ └── index.html
└── wavedash.toml
src/Main.hx:
class Main extends hxd.App {
override function init() {
var box = new h2d.Graphics(s2d);
box.beginFill(0xFFFFFF);
box.drawRect(0, 0, 40, 40);
box.endFill();
}
override function update(dt:Float) {
// per-frame logic
}
static function main() { new Main(); }
}
build.hxml:
-cp src
-main Main
-lib heaps
-js bin/main.js
-D js-es6
bin/index.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<style>html, body { margin: 0; height: 100%; } canvas { display: block; width: 100vw; height: 100vh; }</style>
</head>
<body>
<canvas id="webgl"></canvas>
<script src="./main.js"></script>
</body>
</html>
Heaps auto-attaches to <canvas id="webgl">.
Build
haxe build.hxml
Produces bin/main.js. Point upload_dir at ./bin.
SDK integration
Wavedash is injected by the platform on window. Call it from Haxe via js.Syntax.code (or js.Lib.eval):
Calling Wavedash.init() is required. Your game stays hidden behind the Wavedash loading screen until you do. Call it once your game is ready to play.
override function init() {
js.Syntax.code("Wavedash.updateLoadProgressZeroToOne(1.0)");
js.Syntax.code("Wavedash.init({ debug: false })");
// ...rest of your game setup
}
Wavedash is the live SDK instance — calls run synchronously. If you need full type safety, write an extern binding — but for the load-complete signal, the inline JS is enough.
wavedash.toml
game_id = "YOUR_GAME_ID_HERE"
upload_dir = "./bin"
entrypoint = "index.html"
Heaps ships its own JS and assets from your bin/ folder — everything is same-origin, so there are no cross-origin / CORP concerns inside the Wavedash sandbox.