Sprite sheets & blit

GameTank carts don't have M8's fixed 8×8 tile sheet — instead they paint up to 8 sprite sheets of 256×256 pixels each, and draw rectangular regions of them onto the screen with a single primitive: blit. This tutorial tours the sheet editor, then blits a 16×16 sprite and moves it with the d-pad. Requires a GameTank cart — switch machines in the Cart tab first (see The GameTank machine).

1. The sheet editor

On a GameTank cart the Sprites tab is GtSheetEditor — a different tool than M8's tile grid:

ControlWhat it does
Thumbnail stripGrows on demand up to 8 sheets. Click a thumbnail to make it the active sheet; a + sheet control appears until you reach the cap.
Pencil / Rectangle / Fill / EyedropperThe four paint tools. Eyedropper picks the color under the cursor into the active color slot instead of painting.
256-color picker + recentsPick any of the 256 fixed LUT entries (see Palettes); a recent-colors row keeps your last few picks one click away.
PNG importDecodes a PNG, quantizes every pixel to the nearest of the 256 fixed colors, and pastes it into the active sheet at a chosen (x, y) — fully transparent source pixels are skipped rather than painted.
PNG exportExports the active sheet back out as a PNG, useful for editing in an external tool and re-importing.
Undo / RedoPer-active-sheet history, independent of the other 7 sheets.

Sheets round-trip through Compile and Export .sprite / Load .sprite byte-for-byte — paint, export, and re-import and you get the same pixels back.

2. The blit HCALL

blit ( sheet sx sy w h dx dy flags -- )

Copies a w×h rectangle from sprite sheet sheet (0–7) at source position (sx, sy) to the framebuffer at destination (dx, dy). flags is a bitfield:

BitValueEffect
01Horizontal flip — mirror the source rect left-right before drawing.
12Vertical flip — mirror the source rect top-bottom.
24Transparency — skip destination pixels wherever the source color index is 0.
38Fill mode — ignore the sheet entirely and paint every destination pixel with the color index carried in sx (so sheet/sy are unused). This is how rect is implemented under the hood.

Flags can combine — 3 is hflip+vflip (a 180° rotation), 5 is hflip with transparency, and so on. Bit 4 (16) is reserved for edge-clipping and has no effect either way — blit (and every other draw primitive) always clips to the screen bounds and the active clip rect unconditionally. There's nothing to opt in or out of; the bit stays defined only so a flags byte that sets it doesn't silently mean something else in a future version.

3. Worked example — blit a 16×16 sprite, move it with the d-pad

Paint anything you like into the top-left 16×16 pixels of sheet 0, then compile this cart:

\ Blit a 16x16 sprite from sheet 0 and move it with the d-pad.
variable px   variable py
: init  56 px !  56 py !  0 cls ;
: update
  0 cls
  0 btn if  py @ 1 - py !  then  \ up
  1 btn if  py @ 1 + py !  then  \ down
  2 btn if  px @ 1 - px !  then  \ left
  3 btn if  px @ 1 + px !  then  \ right
  \ blit ( sheet sx sy w h dx dy flags -- )
  0 0 0 16 16  px @  py @  0  blit ;