Current version: 0.7.0
MiniPixels is a pixel-oriented 2D game engine prototype for MiniLang. It uses the existing MiniLangCompilerPy compiler and builds native Windows x64 executables.
MiniPixels focuses on a small but working 2D engine slice: a Win32 window, fixed logical framebuffer, optional OpenGL/WGL presentation, nearest-neighbor scaling, focus-aware keyboard input, sprites, MiniPixels asset packs with runtime PNG decoding, runtime file assets, tilemaps, camera scrolling, simple collision, bitmap text, basic audio, headless tests, and example projects.
- Windows
- A checkout of
MiniLangCompilerPynext to this repository, or a path passed with--compiler - Python 3 for the MiniPixels CLI
Expected sibling layout during local development:
MiniLangCompilerPy/
MiniPixels/
Build and run the Moving Sprite example:
cd MiniPixels
python tools\minipixels.py run examples\moving-sprite\minipixels.json --compiler ..\MiniLangCompilerPy\mlc_win64.pyBuild without running:
python tools\minipixels.py build examples\moving-sprite\minipixels.json --compiler ..\MiniLangCompilerPy\mlc_win64.pyBuild the native MiniLang CLI:
python ..\MiniLangCompilerPy\mlc_win64.py tools\minipixels_cli.ml build\tools\minipixels.exe -I src -I ..\MiniLangCompilerPy
build\tools\minipixels.exe info
build\tools\minipixels.exe validate examples\moving-sprite\minipixels.json
build\tools\minipixels.exe info examples\moving-sprite\minipixels.json
build\tools\minipixels.exe generate examples\pixel-effects\minipixels.json
build\tools\minipixels.exe generate examples\jump-and-run\minipixels.json examples\jump-and-run\build\generated\generated
build\tools\minipixels.exe new my-game platformerThe native CLI currently provides info, doctor, validate, generate, and new. Native generate writes importable generated.assets and generated.levels modules, supports procedural sprites, emits sheet helpers, and imports MiniPixels levels.json. The full image asset pack pipeline, Tiled/TMJ import, runtime asset copying, build, run, and package still live in the Python tool while those pieces are moved into MiniLang.
Tooling split:
| Task | Native MiniLang CLI | Python CLI |
|---|---|---|
| Create a project | new |
new |
| Inspect/validate manifests | info, doctor, validate |
info, doctor, validate |
Generate generated.assets |
procedural sprites and placeholder image sprites |
procedural sprites plus image loaders backed by assets.mpx |
Generate generated.levels |
MiniPixels levels.json |
MiniPixels levels.json and Tiled JSON/TMJ |
| Create/copy runtime assets | Not yet | assets.mpx for images/audio/files |
| Build/run/package | Not yet | build, run, package, pack |
Run tests:
python tests\run_tests.pyOptional window renderer smoke test:
python ..\MiniLangCompilerPy\mlc_win64.py tests\window_renderer_smoke.ml build\tests\window_renderer_smoke.exe -I src -I ..\MiniLangCompilerPy
build\tests\window_renderer_smoke.exeOptional renderer benchmark:
python ..\MiniLangCompilerPy\mlc_win64.py benchmarks\renderer_bench.ml build\benchmarks\renderer_bench.exe -I src -I ..\MiniLangCompilerPy
build\benchmarks\renderer_bench.exeBuild all examples:
python tools\build_examples.pyCreate the SDK bundle:
python tools\package_sdk.pyimport minipixels as mp
x = 40
y = 40
function update(game, dt)
global x, y
if game.input.left then x = x - (90 * dt) end if
if game.input.right then x = x + (90 * dt) end if
if game.input.up then y = y - (90 * dt) end if
if game.input.down then y = y + (90 * dt) end if
end function
function render(game, canvas)
canvas.clear(mp.rgb(20, 20, 30))
canvas.fillRect(x, y, 16, 16, mp.rgb(255, 128, 0))
end function
function main(args)
cfg = mp.createConfig("MiniPixels Game", 320, 180, 4)
mp.useGpuRenderer(cfg)
return mp.run(cfg, void, update, render, void)
end functioncreateConfig uses renderer = "auto" by default. On Windows that tries the OpenGL/WGL presenter first and falls back to the classic GDI presenter if GPU initialization is unavailable. Use mp.useCpuRenderer(cfg) when you want the old GDI path explicitly.
Presentation scaling can be selected per game:
mp.useStretchScale(cfg) # fill the whole window
mp.useFitScale(cfg) # keep aspect ratio
mp.useIntegerScale(cfg) # pixel-perfect integer scaling
mp.setSmoothing(cfg, false)game/
minipixels.json
src/
main.ml
assets/
player.png
Example project file:
{
"name": "moving-sprite",
"main": "src/main.ml",
"window": {
"title": "MiniPixels Moving Sprite",
"width": 320,
"height": 180,
"scale": 4
},
"assets": [
{
"id": "player",
"type": "image",
"path": "assets/player.png",
"sheet": {
"frameWidth": 32,
"frameHeight": 32,
"spacing": 0,
"margin": 0
}
},
{
"id": "jumpSound",
"type": "audio",
"path": "assets/audio/jump.wav"
}
]
}python tools\minipixels.py run examples\moving-sprite\minipixels.json --compiler ..\MiniLangCompilerPy\mlc_win64.pyDemonstrates a PNG sprite, keyboard movement, pixel snapping, FPS in the window title, and framebuffer scaling.
python tools\minipixels.py run examples\scrolling-world\minipixels.json --compiler ..\MiniLangCompilerPy\mlc_win64.pyDemonstrates tilemaps, camera scrolling, simple platform collision, world-edge clamping, parallax bands, and jump movement.
python tools\minipixels.py run examples\jump-and-run\minipixels.json --compiler ..\MiniLangCompilerPy\mlc_win64.pyDemonstrates a complete small platform game with a main menu, three levels, coins, enemies, stomp combat, exit gates, scrolling camera, sounds, animation, and compact runtime assets adapted from the GandalfHardcore 32x32 sidescroller pack.
python tools\minipixels.py run examples\pixel-effects\minipixels.json --compiler ..\MiniLangCompilerPy\mlc_win64.pyDemonstrates direct per-pixel framebuffer manipulation from MiniLang.
python tools\minipixels.py run examples\tiled-platformer\minipixels.json --compiler ..\MiniLangCompilerPy\mlc_win64.pyDemonstrates the Python build pipeline's Tiled JSON/TMJ importer with a solid tile layer and object-layer spawn, exit, coins, and enemy patrol data. The native MiniLang generator currently writes a level stub for Tiled maps until native Tiled import is added.
python tools\minipixels.py new MyGame
python tools\minipixels.py info examples\moving-sprite\minipixels.json
python tools\minipixels.py doctor examples\tiled-platformer\minipixels.json
python tools\minipixels.py validate examples\moving-sprite\minipixels.json
python tools\minipixels.py generate examples\moving-sprite\minipixels.json
python tools\minipixels.py pack examples\moving-sprite\minipixels.json
python tools\minipixels.py build examples\moving-sprite\minipixels.json --compiler ..\MiniLangCompilerPy\mlc_win64.py
python tools\minipixels.py run examples\moving-sprite\minipixels.json --compiler ..\MiniLangCompilerPy\mlc_win64.py
python tools\minipixels.py packageThe Python CLI validates project JSON, reads 8-bit RGB/RGBA image assets at build time, writes a deterministic MiniPixels asset container (assets.mpx), generates deterministic MiniLang asset modules, emits SpriteSheet helper factories for assets with sheet metadata, includes runtime assets such as type: "audio" or type: "file" in the pack, generates generated.levels from MiniPixels or Tiled JSON when levels.path is present, writes asset-report.json, and invokes the regular MiniLang compiler. Image payloads inside assets.mpx are PNG-encoded in the MiniPixels runtime profile and decoded by MiniLang code through mp.loadPngFromPack(...). Audio payloads can be loaded as bytes and played directly from memory through WinMM SND_MEMORY clips, so example builds no longer need loose WAV files next to the executable. The native MiniLang CLI can already validate manifests and generate importable modules for procedural sprites and MiniPixels levels.json.
Windowed games built through tools\minipixels.py build or run use the Windows GUI PE subsystem by default, so double-clicking the executable opens only the game window and no companion console. Use --headless for console-subsystem builds that are meant to print test or tool output.
assets.mpx is MiniPixels' deterministic runtime asset container. It is intentionally simple: a fixed header, a compact entry table, and contiguous payload bytes.
All multi-byte integers are unsigned little-endian values.
offset size field
0 4 magic bytes: "MPX1"
4 4 entry count: u32
8 variable entry table
... variable payload bytes
Each entry table record is:
size field
2 asset id byte length: u16
N asset id as UTF-8 bytes, no terminator
1 kind: u8
1 flags: u8, currently 0
4 payload offset from start of file: u32
4 payload size in bytes: u32
Current kind values:
| Kind | Asset type | Payload |
|---|---|---|
1 |
image |
MiniPixels PNG-profile bytes |
2 |
audio |
Original audio file bytes, usually WAV |
3 |
file |
Original file bytes |
Image assets are transcoded by the Python CLI into the MiniPixels PNG profile before they are written to the pack. That profile is deliberately narrow so the MiniLang runtime decoder stays small: 8-bit RGBA, PNG filter type 0, non-interlaced, and a zlib stream made of stored Deflate blocks. Audio and file assets are stored byte-for-byte.
Runtime APIs:
pack = mp.openAssetPack("assets.mpx")
img = mp.loadPngFromPack(pack, "player")
raw = mp.loadBytesFromPack(pack, "coin_sfx")
kind = mp.assetKindFromPack(pack, "coin_sfx")Text:
mp.drawText(canvas, "LEVEL 1", 8, 8, 1, mp.rgb(255, 255, 255))
mp.drawTextCentered(canvas, "READY", 72, 2, mp.rgb(255, 220, 80))Animation:
sheet = gen.sheet_player()
run = mp.animationFromSheet(sheet, 2, 4, 0.08)
run.play()
run.update(dt)
canvas.drawSprite(run.currentSprite(), x, y)Camera-space drawing:
mp.drawSpriteWorld(canvas, camera, playerSprite, player.x, player.y)
mp.fillRectWorld(canvas, camera, coin.x, coin.y, 4, 4, mp.rgb(255, 220, 80))Input and audio:
coin = mp.audioClip("assets\\audio\\coin.wav", "coin")
mixer = mp.audioMixer(4)
if mp.inputPressed(game.input, "jump") then
mixer.playSfx(coin)
end if
mixer.setSfxVolume(80)
mixer.playMusic(mp.musicClip("assets\\audio\\theme.wav", "theme"))
mixer.stopAll()Packed audio:
clip = gen.audio_coin_sfx()
mp.playAudio(game.audio, clip)minipixels: public facade and game loopminipixels.graphics.canvas: framebuffer, primitives, sprite drawingminipixels.graphics.font: 5x7 bitmap text helpersminipixels.graphics.sprite: images, sprites, sprite sheetsminipixels.assets.pack: MiniPixels.mpxasset container readerminipixels.assets.png: MiniPixels PNG-profile decoder for packed RGBA imagesminipixels.platform.windows: Win32 window, input, DIB rendererminipixels.input.input: keyboard snapshot and action helpersminipixels.world.camera: pixel-snapped 2D cameraminipixels.world.tilemap: tile rendering and AABB tile collisionsminipixels.animation.animation: frame-duration sprite animationsminipixels.assets.assets: generated asset registryminipixels.debug.debug: counters and framebuffer hash helpers
Implemented:
- Native Win32 window
- Fixed logical resolution and resize stretch
- CPU RGBA8888 framebuffer
- Nearest-neighbor GDI presentation and optional OpenGL/WGL presentation
- Keyboard input only while the game window has focus
- FPS in the window title
- Safe pixel operations and primitive drawing
- MiniPixels
.mpxasset container generation in the Python pipeline - Runtime PNG decoding in MiniLang for packed RGBA image assets
- Native MiniLang generation for procedural sprites and MiniPixels
levels.json - Runtime asset packing for image/audio/file assets
- Sprites, sprite sheets, animation
- Facade helpers for world drawing, text, input edges, animation-from-sheet, and audio state/loop/stop
- Build-time SpriteSheet metadata and
asset-report.json - Build-time level JSON generation through
generated.levels - Camera, scrolling, parallax bands
- Tilemap culling and simple collision
- Headless and framehash regression tests
- GitHub Actions CI for tests and example builds
- SDK ZIP packaging with SHA256 checksum and release upload on
v*tags - Version file, changelog, and first-game guide
Not yet implemented:
- General-purpose PNG hot-loading outside MiniPixels asset packs
- Native asset-pack generation and native Tiled/TMJ import
- Cross-platform audio mixer beyond the WinMM hook
- Full editor tooling
- Advanced physics or ECS
More detail is in docs/getting-started.md, docs/first-game.md, docs/manifest-reference.md, docs/examples.md, and docs/minipixels-architecture.md. Release notes are in CHANGELOG.md.