GAME BOY ADVANCE · NO CODE

Shimmer Engine Wiki

Everything about making Game Boy Advance games in Shimmer Engine: drawing maps and sprites, scripting with event blocks, music, cutscenes, and building a real .gba ROM.

What is Shimmer Engine?

Shimmer Engine is a game maker for the Game Boy Advance, inspired by GB Studio. You draw your maps, place characters, script what happens with event blocks, write music, and press Build ROM. The result is a real .gba file that runs in emulators like mGBA, and should run on real hardware too.

Everything a build needs is included in the installer. There's no compiler, Python or devkit to set up.

Shimmer Engine is an early alpha. Things change from version to version, and your feedback decides what gets fixed and added first. Report problems on r/ShimmerEngine.

Coming from GB Studio? Most ideas carry straight over: scenes, actors, triggers, event scripts, GB Studio fonts and .uge songs. The big differences come from the hardware: far more colors, bigger sprites, real background layers and 16 actors per scene.

Installing

SystemDownloadNotes
WindowsShimmer-Engine-Setup-<version>.exeRun it and Shimmer opens. Windows may ask you to confirm, since the installer isn't code-signed yet.
Linux.deb or .AppImageThe .deb installs with a double-click. On Ubuntu 22.04-based distros (Zorin 17, Mint 21), the AppImage first needs sudo apt install libfuse2. Runs natively, so no Wine needed.
Mac.dmgApple Silicon (M1 and newer). The first time, right-click the app and choose Open.

To play your game you also need a GBA emulator. mGBA is a good choice. Set it as the program that opens .gba files, or pick it in File → Emulator for Play.

Your first game

  1. New Project. On the start screen, type a name, press New Project and choose a folder. You get a project with one scene, a background and the default player.
  2. Look around the scene. The middle is the scene canvas. The left sidebar lists scenes and project data; the right panel shows whatever you've selected.
  3. Add an actor. Pick the actor tool in the canvas toolbar and click on the map. Give it a name in the right panel.
  4. Make it talk. With the actor selected, open its On Interact tab, press + Add Event and choose Display Text. Type a line.
  5. Paint some walls. Turn on the collision layer and paint solid tiles so the player can't walk through buildings.
  6. Press Play. Shimmer builds the ROM and opens it in your emulator. Walk up to the actor and press A.

From here: draw your own backgrounds and sprites in the Art Editor, add more scenes and connect them with doors, and pick a game mode if you're not making a top-down game.

Editor tour

The dropdown in the top-left switches between the editor's sections:

Game World

Scenes, actors, triggers and their scripts. Where most of the game gets made.

Sprites

Turn sprite sheets into animated characters: frames, states, directions and collision boxes.

Backgrounds

Your background images, with the numbers the GBA cares about: colors, tiles and size.

Art Editor

A built-in pixel art editor for every image in your project.

Music

A piano-roll editor for .uge songs, plus MIDI import.

Cutscenes

Turn a video into a full-screen GBA cutscene with sound.

Settings

Engine settings for each game mode, dialogue fonts and frames, controls and project options.

Menus

  • File: New Project, Open Project, Save (Ctrl+S), Save As (copies the project to a new folder), Reload Assets (F5), Emulator for Play.
  • View → Theme: Dark, Light, Midnight Blue or Classic Purple.
  • The toolbar has Asset Reload, Open Folder, Undo/Redo, Play and Build ROM.

Every change saves automatically. Save just writes everything immediately and confirms it in the status bar.

Project files

A project is a normal folder, so you can keep it anywhere and edit its art in other programs too. Press Asset Reload after changing files outside Shimmer.

my_game/
  project.json            flags, items, variables, settings, custom scripts
  scenes/                 one .json file per scene (subfolders = folders in the list)
  assets/
    backgrounds/          scene background PNGs
    sprites/              sprite sheet PNGs (+ .art.json layers from the Art Editor)
    fonts/  frames/  ui/  dialogue fonts, box frames, menu cursor
    music/                .uge songs
    sounds/               .wav sound effects
    cutscenes/            .cut video + .raw sound (made in the Cutscenes tab)
  ROM/                    your built .gba

Put a / in a scene's name, like Forest/Cave 1, to put it in a folder. Scripts, palettes, prefabs and sprites can be organised in folders the same way.

Scenes

A scene is one map, or one screen like a title or a menu. Each has a background image, collision, actors, triggers and scripts.

Backgrounds

Any PNG up to 2048×2048 pixels, sized in multiples of 8. Maps bigger than 512×512 stream in as you walk. Every 8×8 tile can use 15 colors plus a shared backdrop color, from up to 15 palettes per scene, with up to 1024 unique tiles.

Painting the map

  • Collision: solid, water, damage, and one-way tiles that block from the top, bottom, left or right only.
  • Brushes: 8px, 16px, fill, magic (every matching tile) and area select with copy and paste.
  • Tiles: stamp tiles from the background onto the map without touching the original image.
  • Colors: assign palettes to tiles.

Layers and parallax

Each scene can have up to two extra background layers that scroll at their own speed, with optional drift for things like clouds. GB Studio-style parallax strips also work.

Things you place

  • Actors: characters and objects with sprites and scripts. 16 per scene at most.
  • Triggers: areas that run a script when the player walks in, and optionally when they leave.
  • Doors: triggers that take the player to another scene.
  • Notes: editor-only reminders on the map.
  • Prefabs: saved actors and triggers you can place again.

Right-click an actor, trigger or note on the canvas to delete it. Hovering shows the tile position as X= and Y=; an actor's position is its top-left tile.

Game modes

Every scene has a type that decides how the player moves:

ModeWhat it plays like
Top Down 2DClassic RPG movement. Free or grid-based (a full 8 or 16 px per step), with running and optional diagonals.
PlatformerGravity, variable jump height, coyote time, jump buffering, double jumps, wall jumps and slides, ladders, one-way platforms, dashing, crouching, and moving platforms you can ride.
AdventureFree 8-way movement with momentum, running, dashing and pushing.
Shoot 'Em UpThe screen scrolls by itself and the player stays on screen.
Point and ClickThe player is a cursor; hover over things and press A.
LogoNo player at all, for title cards and splash screens.

Each mode's settings are in Settings → Engine; see the engine settings reference. A scene can override settings just for itself, and Set Engine Setting changes them mid-game.

Sprites with animation states named jump, fall, run, climb or dash are picked up by the modes automatically.

Actors and the player

Actors have a sprite, a movement and animation speed, a collision group, and four scripts:

  • On Init: runs when the scene starts.
  • On Update: loops in the background every frame.
  • On Interact: runs when the player presses A on it.
  • On Hit: runs when a projectile in its group hits it.

Click the player's start position to give the player its own On Init, On Update and On Hit scripts, animation speed and collisions. Every actor event can target the Player, and Self means "this actor" inside its own scripts.

Actors can be pinned to the screen for HUD elements, and in platformer scenes an actor can be a platform you stand on and ride.

Event scripting

Scripts are lists of event blocks that run top to bottom. Press + Add Event and search, or browse by category. Drag blocks to reorder them, and hold Alt or Ctrl while dropping to copy instead.

Where scripts live

  • Scene On Init, On Player Hit and Timers.
  • Actor and player scripts (see Actors).
  • Trigger On Enter and On Leave.
  • Custom scripts: reusable scripts you call from anywhere with Call Script.
  • Attach Script To Button: runs whenever a button is pressed. It runs alongside play by default, so the player keeps moving. Tick Freeze player to stop everything until it finishes.

Data

KindHoldsLimit
FlagsOn/off switches32
ItemsInventory, have or don't have32
VariablesWhole numbers from −32768 to 32767256
ConstantsNamed fixed numbers for expressions—

Flags, items and variables are what the three save slots store.

Handy tools

  • Disable event: right-click a block to switch it off without deleting it. Blocks with an Else branch can also Disable else.
  • Expressions: If Expression and Set Variable To Expression take formulas using variables, flags, items, actors and math.
  • Background scripts: up to 8 scripts can run at once. Dialogue boxes wait their turn.
  • Pause the world during dialogue (an engine setting) freezes everything else while a box is open.

The full list is in the events reference.

Dialogue

Display Text shows a dialogue box. A new line starts a new page, and long text carries on to the next page automatically. The preview under the text shows exactly what the game will show.

Box options

  • Position: bottom, middle, top, or custom (X, Y and width in tiles; the screen is 30×20 tiles).
  • Rows: 1 to 4 lines of text.
  • Frame: turn it off for just the text, handy for one-line HUD text.

Text codes

CodeDoes
{score}Shows a variable's value.
!F:fontname!Switches font from here on.
!C:#ff4040!Colors the text from here on. !C! goes back to the font's own color.
!S2!Text speed in frames per letter. !S0! shows text instantly.

The Insert bar under the text box adds these for you.

Fonts and frames

Fonts use GB Studio's PNG format, so GB Studio fonts work as they are. There are 15 built-in fonts too. Fonts, frames and text colors share one 15-color dialogue palette.

Sprites

  • Sprites can be almost any size up to 256×256; the engine packs them into the GBA's hardware sprites for you.
  • Each sprite can use 15 colors plus transparency.
  • Animation states for standing, walking and custom animations, in four directions. Flip right to make left saves drawing.
  • Sheet slicing for GB Studio-style and RPG Maker-style sheets.
  • A live preview of the character walking, and a meter for how much sprite memory each frame uses.
  • Onion skin, frame copy and paste, mirroring and drag-to-reorder.

Art Editor

A pixel art editor for your project's images. Pick an image on the left, or make one with + New. Saving writes the PNG straight into your project.

Tools

ToolKeyNotes
PencilBBrush size, dither and pixel-perfect options. Shift+click draws a line from the last point.
EraserEErases to transparent.
FillGConnected area, or every pixel of that color with Global.
Line / Rectangle / EllipseL U OShift for 45° lines, squares and circles.
GradientDDithered, linear or radial, using only the colors you pick.
ShadingSLeft click lightens, right click darkens, stepping through the image's own colors.
StampKDraws a custom brush made with Image → Brush from selection.
Color pickerIOr Alt+click with any drawing tool.
Select / MoveM VCopy, cut, paste, flip, nudge with arrow keys.
HandHOr hold Space and drag.

Layers and animation

Layers can be hidden, locked, faded, reordered and merged; the game gets them flattened into one image. For sprite sheets, set a frame size in the Frames panel to get a timeline, a playing preview and onion skin.

GBA helpers

  • The palette bar warns when a sprite goes over 15 colors, or a background tile over 15 plus the backdrop.
  • Image → Reduce colors and Snap to GBA colors fix that for you.
  • Tile mode (T) repeats the image around itself for seamless tiles. # shows the 8×8 tile grid.

Music and sound

  • Music uses .uge songs, the same format as hUGETracker and GB Studio, played on the GBA's classic sound channels.
  • The Music section is a piano-roll editor with instruments, waves and effects.
  • MIDI import turns a MIDI file into a playable song.
  • Sound effects are WAV files in assets/sounds, played on the GBA's two digital sound channels at 16384 Hz. Built-in sounds cover jumping, landing and more.

Cutscenes

Turn a video into a full-screen GBA cutscene with sound, for intros and story moments.

  1. Open Cutscenes and press + Import video. MP4 (H.264) and WebM work best.
  2. Trim it with Start and End, and pick a size, frame rate, fit and quality. The dialog estimates the size before converting.
  3. Press Convert, then watch it in the preview player. It plays exactly as the GBA will show it.
  4. Add a Play Cutscene event where it should play. A or START can skip it, and the scene comes back as it was afterwards.
SizeLooksSpace
Full screen 240×160SharpestBiggest
Half 120×80, shown 2×Chunkier pixelsAbout 4× smaller

Sound takes about 16 KB per second. A cartridge holds 32 MB, so short cutscenes fit easily. Cartoon-style video compresses much better than live action.

Saving and the scene stack

  • Save Data, Load Data and Clear Data use three save slots that hold flags, items, variables and where the player is.
  • Store Current Scene remembers the scene and player position; Restore Previous Scene goes back. Good for menus and houses.
  • Tick Remember everything for a real pause. Actors, their states, running scripts and timers all come back exactly as they were, and the scene's On Init doesn't run again.

Building and playing

  • Play builds the game and opens it in your emulator. Pressing Play again closes the emulator it opened last, so windows don't pile up.
  • Build ROM builds without playing. The ROM goes in your project's ROM folder.
  • If something's wrong, the build window says which scene and event. Copy Log copies it for sharing.

Real hardware

The ROM is a standard GBA ROM with a fixed header, so it should run on flash carts. Please report how it goes on yours.

GBA limits at a glance

ThingLimitWhy
Screen240×160 px30×20 tiles of 8×8.
Background size2048×2048 pxBigger maps stream in as you walk.
Colors per background tile15 + backdropEach 8×8 tile uses one 16-color palette.
Background palettes15The 16th belongs to the dialogue box.
Unique background tiles1024Repeat tiles across big maps.
Colors per sprite15 + transparentOne sprite palette each.
Sprite sizeup to 256×256Packed into hardware sprites.
Actors per scene16Plus the player.
Dialogue palette15 colorsShared by all fonts, frames and text colors.
Running scripts1 + 8One main script plus background scripts.
Timers per scene8
Flags / items / variables32 / 32 / 256All saved with the game.
Save slots3
Cartridge32 MBWhat everything has to fit in.

How Shimmer Engine is built

Three parts work together. The editor writes plain files; the compiler turns them into C data; the engine is the GBA program that data is linked into.

PartLanguageJob
EditorTypeScript, React, ElectronEdits the project folder: JSON, PNG, UGE, WAV and cutscene files.
CompilerPythonChecks the project and writes C source: scenes, scripts, sprites, fonts, songs, sounds.
EngineC (devkitARM, libgba)The runtime: game loop, game modes, script machine, graphics, sound, saves.

The installer bundles a frozen copy of the compiler, the engine source and a trimmed devkitARM (GCC for the GBA's ARM7TDMI), which is why nothing else needs installing. The Linux version uses Arm's own GCC with devkitPro's GBA support files, because devkitPro's Linux compiler needs a newer glibc than Ubuntu 22.04-based distros have.

Project file format

Everything is plain JSON, so projects diff well in Git and can be edited by hand or generated by tools.

project.json

{
  "name": "My Game",
  "start_scene": "title",
  "flags": ["met_elder", "door_open"],        // up to 32
  "items": ["Old Key"],                       // up to 32
  "variables": ["gold", "hp"],                // up to 256, int16
  "constants": [{ "name": "MAX_HP", "value": 99 }],
  "customScripts": [{ "id": "...", "name": "Heal", "script": [ ...events ] }],
  "ui": { "font": "default", "frame": "default", "textSpeed": 1 },
  "palettes": [ ... ], "prefabs": [ ... ],
  "playerSprite": "player",
  "spriteSheets": [ ...sprite definitions ],
  "engine": { "pl_walk_vel": 2, ... }          // engine settings by key
}

scenes/<name>.json

{
  "name": "town",
  "type": "topdown",                          // or platform, adventure, shmup, pointnclick, logo
  "background": "../assets/backgrounds/town.png",
  "music": "town",
  "player_start": { "x": 14, "y": 9 },        // tiles
  "collision": ["....####", "....#..."],      // one string per tile row
  "npcs": [{ "name": "elder", "x": 4, "y": 4, "sprite": "elder",
             "on_interact": [ ...events ], "on_update": [ ... ] }],
  "doors": [{ "x": 10, "y": 0, "width": 2, "height": 1,
              "target_scene": "forest", "target_x": 3, "target_y": 18 }],
  "on_init": [ ...events ],
  "layers": [ ...parallax layers ],
  "tile_overrides": { "3,4": [12, 0] },       // map tile ← background tile
  "engine": { ... }                           // this scene's own settings
}

Collision characters

CharMeaning
.Walkable
#Solid
~Water
!Damage
^ v < >One-way: solid only from the top, bottom, left or right edge
HLadder (platformer)

Events

An event is an object with a type and its options, and branches are nested lists:

{ "type": "if_flag", "flag": "met_elder",
  "then": [ { "type": "text", "text": "Welcome back!" } ],
  "else": [ { "type": "text", "text": "Hello, stranger.", "position": "top" } ] }

Any event can carry "__disabled": true, and an event with an Else can carry "__disableElse": true; the compiler skips them.

The build pipeline

  1. Compile the project. build_project.py validates everything and writes scenes_data.c, ui_data.c, uge_songs.c, sounds_data.c, mode_settings.h and the cutscene files into <project>/build/rom/data/. Errors name the scene, script and event.
  2. Compile C. Each engine and data source is compiled with arm-none-eabi-gcc -mthumb -mcpu=arm7tdmi -O2, in parallel, skipping files whose sources haven't changed.
  3. Link with gba.specs and libgba, objcopy to a raw ROM, and gbafix the header (title, checksum).
  4. Copy the ROM to <project>/ROM/.

Building from the command line

python3 compiler/build_rom.py <project folder> [--engine DIR] [--devkitpro DIR] [--out FILE]

It needs devkitARM, taken from $DEVKITPRO or /opt/devkitpro. The installed app runs the same tool, frozen as shimmer-build, from its resources/toolchain folder.

Big data

Cutscene video and sound go into the ROM through the assembler's .incbin rather than giant C arrays, so even multi-megabyte cutscenes build quickly.

The script machine

Event blocks compile to a flat list of instructions. Each one is a small struct:

typedef struct ScriptEvent {
    uint8_t     op;          // what to do (SCRIPT_TEXT, SCRIPT_IF_FLAG, ...)
    int16_t     a, b, c, d;  // operands: indices, numbers, jump targets
    const void *ptr;         // an expression or a sub-script
    const char *str;         // dialogue text
} ScriptEvent;
  • Threads. One main script plus up to 8 background threads. Each keeps its own position and whatever it's waiting on (a text box, a wait, a moving actor, a camera pan, a button).
  • Running. Every frame each thread runs instructions until one blocks, then picks up from there next frame. Branches and loops are jumps inside the list.
  • Expressions compile to reverse-Polish arrays the engine evaluates on a small stack: variables, flags, items, actor positions, math and comparisons.
  • The player stands still while the main script runs (talking to an actor, a trigger). Background threads, timers and button scripts run alongside play.
  • Real pause. Store Current Scene with Remember everything copies every thread, timer and button script plus each actor's state, and puts them back when the scene is restored.

Graphics on the GBA

Video memory layout

AreaUsed for
BG char blocks 0-1Scene tiles (up to 1024, 4bpp)
BG screen blocks 28-31Scene map on BG0, up to 64×64 tiles
BG screen blocks 24-27Parallax layer maps on BG2 and BG3
BG char block 2, screen block 23Dialogue box and text on BG1
BG palette banks 0-14 / 15Scene colors / dialogue colors
OBJ VRAM (0x06010000)Sprite tiles, streamed in per animation frame
OBJ palette banksAssigned per scene; the player always gets bank 0

Big maps

Maps up to 64×64 tiles (512×512 px) sit in VRAM whole. Bigger ones, up to 256×256 tiles, stream: as the camera moves, the engine copies in the row or column that's about to appear.

Sprites

The GBA draws sprites from hardware objects (OBJs) of fixed sizes, 8×8 up to 64×64. The compiler covers each frame of a sprite with as few OBJs as it can, removes duplicate tiles, and makes "flip left" frames from flipped OBJs instead of new pixels. Each actor reserves OAM slots and VRAM for its largest frame and streams the current frame in.

Dialogue

Text isn't made of font tiles. It's drawn pixel by pixel into a RAM canvas the size of the box (variable-width fonts, colors and all) and copied to BG1 when it changes.

Cutscenes

Full-size cutscenes use BG0 with 256-color (8bpp) tiles; half-size ones use an affine BG2 scaled 2×. Each frame updates only the tiles that changed.

Sound on the GBA

  • Music plays on the four classic PSG channels (two pulse, wave, noise) through a C port of hUGEDriver, so .uge songs sound as they do in GB Studio. The editor's player is a TypeScript port of the same driver feeding a PSG synth.
  • WAV sounds use the two Direct Sound channels. Samples are signed 8-bit mono at 16384 Hz, streamed from ROM by DMA 1 and 2 and clocked by timer 0, so they cost almost no CPU. They mix over the music.
  • Cutscene sound is a WAV on channel A, started with the first video frame; video timing comes from the same hardware clock, so they stay in sync.

Save data

Saves go to the cartridge's battery-backed SRAM: 32 KB at 0x0E000000, read and written a byte at a time. Each of the 3 slots gets a 1 KB stripe holding:

typedef struct {
    uint32_t magic;            // marks a slot as written
    uint32_t flags;            // one bit per flag
    uint32_t inventory;        // one bit per item
    uint8_t  scene_index;
    int16_t  player_x, player_y;
    uint8_t  player_direction;
    int16_t  variables[256];
    uint8_t  checksum;
} SaveData;

The ROM carries the SRAM_V113 marker so emulators and flash carts know which save type to give it.

Cutscene file format (.cut)

Little-endian. The editor writes it; engine/source/cutscene.c plays it.

OffsetContents
0"SHCV"
4u16 version (1)
6u8 mode: 0 = full 240×160, 1 = half 120×80 shown 2×
7u8 frames per second
8u16 frame count
10u8 tiles across, u8 tiles down
12u16 palette[256], GBA BGR555
524u32 frame offsets[count + 1]
…Frames: GBA LZ77 streams, 4-byte aligned

Unpacked, a frame is a bitmap with one bit per tile (rounded up to 4 bytes) followed by 64 bytes of 8bpp pixels for each tile whose bit is set. Frame 0 sets every tile. The BIOS LZ77UnCompWram call unpacks each frame into work RAM before the changed tiles are copied to VRAM. The .raw file beside it is the sound: signed 8-bit mono at 16384 Hz.

Building from source

cd editor
npm ci
npm run dev        # editor with hot reload
npm run dist       # package an installer for this system

Development builds of ROMs run compiler/build_rom.py through bash (WSL on Windows) with your own devkitARM. The GitHub Actions workflow builds the Windows, Linux and Mac installers, and test-builds a ROM with each bundled toolchain.

The source layout is described in ARCHITECTURE.md in the repository.

Events reference

Every event block, generated from the editor's own list. Search above to filter, or pick a category.

Engine settings reference

From Settings → Engine. Settings marked GBA are extras GB Studio doesn't have.

Troubleshooting

Play does nothing, or says it can't open the ROM

Install an emulator like mGBA and set it to open .gba files, or choose it in File → Emulator for Play.

"Too many colors"

Open the image in the Art Editor. The palette bar shows how far over you are; use Image → Reduce colors.

An actor ends up a tile lower than expected

Positions are the actor's top-left tile, but a 16×16 actor covers four tiles. Use the Pick button, which shows the whole actor. In a platformer, gravity also pulls a player placed in mid-air down.

My button script freezes the player

Untick Freeze player while it runs on Attach Script To Button. Unticked, the script runs alongside the game.

A video won't import

Use MP4 (H.264) or WebM. Other formats can be converted with a free video converter first.

The Linux AppImage won't start

Run sudo apt install libfuse2, or use the .deb instead.