The Tilemap Editor turns small, reusable graphics into level-building pieces. You edit the system's atomic tiles, assemble them into metatiles such as platforms or pickups, paint those metatiles into a map, and export the data for your game.
This guide covers the three supported tile workflows:
Not the Charset/Tile Editor. This tool edits map layouts — which tile IDs go where. The Charset/Tile Editor edits the 8 × 8 pictures themselves: the C64 charset glyphs and the Atari tile glyphs. Change a glyph there and every map cell that refers to it follows.
Tile maps live in the project's tiles/ folder and are listed in the manifest's assets.tilemaps array. The workshop keeps the map project separate from source code, so the same tile definitions can be reused by more than one game screen or include file.
| System | Atomic tile | Metatile | Exported data |
|---|---|---|---|
| C64 | An 8 × 8 glyph from the selected C64 charset | A rectangle of charset glyphs, with collision and gameplay metadata | Map, metatile definitions, collision, and gameplay roles |
| NES | An 8 × 8 2bpp CHR pattern | A rectangle of CHR tiles with one attribute palette | CHR pattern data, nametable map data, and attribute bytes |
| Atari 7800 | An 8 × 8 one-bit MARIA tile, drawn in the editor | None — stamps are authoring sugar, expanded to tile IDs as you paint | Tile pictures, the project's eight palettes, one map per screen with its palette runs, a collision table, and markers |
C64 and NES paint with metatile IDs rather than individual tiles. That is what makes a platform, wall, or pickup easy to place consistently across a scrolling level. The Atari 7800 has no metatile layer: its map is one byte per tile, because that is exactly what the hardware reads, and a stamp gives you the same convenience without a second layer to render.
The six steps below are common to all three editors. Where they say metatile, an Atari 7800 map uses a stamp instead, and its screens are one fixed tile area — see the 7800 section for what that changes.
Use New Tile Map to create a blank project. Give it a name that describes the screen or level, such as scrolling-background or cave-level-01.
Use Open to load a saved tile-map JSON file. Assets already inside the project can also be opened from the explorer.
Atomic tiles are the smallest graphics the target hardware can draw:
Select Metatile editor, create a metatile, choose its size, and fill each cell with an atomic tile. A 2 × 2 metatile is a useful starting point for a platform or block, while 1 × 1 is useful for a small pickup or decorative mark.
The map renderer only needs the graphic arrangement, but your game also needs to know what a placed piece means. Use the available collision, role, or palette fields to keep this information beside the art.
Switch to Map canvas, select a metatile, and click or drag across the grid. Use Erase to remove cells. The map grid can be larger than the visible game screen, which is useful for scrolling levels.
Save preserves the editable tile-map project. Export creates a .cbi include containing target-ready data. Include that file from your game source and use the generated constants and data tables in your renderer.
Yes: for a C64 character-mode tile map, the atomic tiles come from the charset you load.
The C64 Tilemap Editor does not copy a second set of pixels into every map cell. Instead, it stores references to charset glyph numbers. The selected charset supplies the 8 × 8 pixel shapes, while the tile map stores which glyphs belong in each metatile and where those metatiles are placed.
This gives the workflow a useful separation:
If you change the selected charset, the previews update to show that charset's glyphs. If you edit a glyph in the Charset/Tile Editor, any metatile using that glyph will use the updated shape when the charset is loaded by the game. Keep the charset path stable when you want the tile map to continue referring to the same source.
Grass Platform, Coin, or Goal Flag.C64 collision choices are Empty, Solid, One way, Ladder, and Hazard. Gameplay roles include Platform, Wall, Floor, Ceiling, Pickup, Checkpoint, Spawn, Goal, and Decoration.
The default C64 map is 40 × 25 metatiles, matching a standard character-mode screen when using 1 × 1 metatiles. Wider or taller maps are appropriate for scrolling games; the exported map remains a data source that your scrolling code can read as the camera moves.
The C64 include contains the metatile arrangements, map values, collision values, and gameplay-role values. Map cells refer to metatiles, and metatile cells refer to glyph numbers from the selected charset.
After exporting, include the generated .cbi file in the game source. Use its constants and tables when drawing the visible map and when deciding whether the player can stand on, climb, collect, or collide with a placed piece.
NES background graphics are stored as 8 × 8 CHR patterns. Each pixel has one of four values, called 2bpp values 0 through 3; those values are the two CHR bitplanes, not fixed colours. The workshop presents 256 editable CHR patterns, the complete 64-entry NES PPU colour table, and four editable background sub-palettes.
The NES workflow has three layers:
0, 1, 2, or 3, then click or drag over the 8 × 8 grid. The selected value sets the two bitplane bits in the CHR data.0 is the universal background colour shared by all four palettes.0, 1, 2, or 3.The default NES map is 32 × 30 metatiles, which corresponds to one 256 × 240 nametable-sized screen when each metatile is 1 × 1. For a scrolling background, increase the width so the map extends beyond the first screen.
The number of CHR patterns included in the exported CHR data is stored in the project, defaulting to 64 tiles ($00–$3F). There is no editor control for it: it changes only when you load a map project whose own chrStart/count says otherwise (and a map imported with a non-zero chrStart is re-saved from zero), so treat the range as fixed by the file you started from.
Keep the background range separate from the sprite range. The current Scroll Demo uses background tiles $00–$3F and sprites from $60, leaving a gap between them. If a metatile uses a tile outside the exported range, move that artwork into the exported background range or start from a project whose stored count is larger.
The NES include contains:
LOAD_<NAME>_CHR procedure for uploading the exported background patterns.The export is the data source for your renderer. It does not automatically stream the map into the PPU or replace a project's existing TILE_FOR_WORLD logic. Your scrolling code still needs to copy the appropriate map values into nametable memory and update the attribute table as new columns or rows enter the camera view.
For a horizontal scrolling game, a typical flow is:
.cbi file.Opened from Tools → Tilemap Editor in an Atari 7800 project. This editor is not a port of the C64 or NES one: the hardware has no character generator and no tile table, so the model is smaller and stricter.
One screen is the tile area the display gives you: 40 × 24 tiles, each 8 × 8 pixels, one bit per pixel, in MARIA_320A. A tile shows one colour. It cannot carry that colour itself, so the display list colours it a row at a time (below).
Tile 0 is blank and cannot be drawn on. An undefined slot in the character bank reads as background, and that is what makes an empty map cell empty. A screen can use up to 256 tiles, numbered from that blank tile.
The chip has eight 3-colour palettes, and both tiles and sprites read them, so the table is one value for the whole project: it lives in the project manifest (<project>.crusty, under atari7800ColourRam — eight rows of a shared background entry plus three palette colours, with the older atari7800Palettes still read) and the Sprite Workshop edits the same table. Change a colour in either editor and every 7800 asset in the project is stamped with it.
A 320A tile shows entry 2 — the middle of the three. Entries 1 and 3 are still stored and exported because a 160-mode object uses all three, so put the colour you care about in the middle slot. Palette 0 is normally the tile and text colour for the rest of the screen; leave it alone unless you mean to change everything using it.
A row of the map is not one palette: it is a sequence of runs, and the editor works them out from the palettes your tiles ask for. This is the number that decides whether a screen fits, because a row of the display list holds 26 bytes for tile and sprite objects together:
The Budget panel reports the busiest row, its byte cost and the sprite headroom left, and the canvas marks any row that needs more than one run with a colour band above it. Rows of a single palette stay clean.
Blank cells count towards the runs like any other cell, which is the one non-obvious rule here: the blank tile's palette decides the run structure of every row it appears in. Two consequences:
x, y, kind triples with a CONST per kind, and they are never written into the map cells. Use them for placement; keep score and fuel values in your own tables.solid is something a game scanning the map for ground will treat as floor. A game whose terrain is a height table can keep that table instead, but then the map and the table describe the same landscape twice and have to be kept in step.Export writes one .cbi include into the project's src/. Its symbols are named after the include file, as the sprite include's are — lunar-levels-tilemap.cbi gives LUNAR_LEVELS_TILEMAP_INSTALL and LUNAR_LEVELS_TILEMAP_LEVEL_1_SHOW — while the tile constants come from the asset's own name.
It carries the tile pictures as CONST glyphs bound with TILE_DEFINE, the eight palettes as data with an INSTALL procedure, one map per screen with its palette runs and marker table, and a SHOW_<SCREEN> procedure per screen. A game needs:
@OPTION TILE_ACTIVE_COUNT 6 ' the number the include reports
@INCLUDE "my-map-tilemap.cbi"
PROC MAIN
DISPLAY MARIA_320A
TILE_BEGIN 1, 1
MY_MAP_TILEMAP_INSTALL ' palettes + tile bank, once
MY_MAP_TILEMAP_LEVEL_1_SHOW ' runs + map for that screen
ENDPROC
The include cannot set a compile option, so TILE_ACTIVE_COUNT is yours to set, and it must cover every tile ID the bank uses.
One writer of the palette registers. If the program also includes the Sprite Workshop's output, call the tile map's INSTALL and not the sprite include's <INCLUDE>_SET_PALETTES: two loaders write the same eight registers, and the sprite one writes its own three entries for every palette, so whichever runs last decides the colours.
$0D is included for completeness but is marked as unstable on NTSC hardware; prefer the other entries for portable artwork.Choose a valid source in Loaded charset. The tile map needs a C64 charset for its glyph previews. If the art itself is wrong, open the source charset in the Charset/Tile Editor and check the glyph there.
Check that every CHR tile used by a metatile is inside the range the project stores for exported CHR (64 patterns by default). Also confirm that the game uploads the generated CHR data at the exported CHR start, writes the exported PALETTE_DATA bytes to $3F00, and interprets the map as metatile IDs rather than raw CHR IDs.
That is normally an attribute-table issue. The NES applies palette choices to attribute quadrants, not to every individual tile. Keep neighbouring artwork compatible with the palette boundaries, or split the design into metatiles whose palette transitions line up with the map's attribute grid.
That is the mode, not a bug. A 320A tile is one bit per pixel, and MARIA maps a lit pixel to entry 2 — the middle colour — of the palette the tile selects. Entries 1 and 3 are for 160-mode objects. Put the colour you want in the middle slot, and use a different palette rather than a different entry when you want another colour on a 320A screen.
Rows, not tiles, carry colour on the 7800: the editor splits each row into palette runs and a row has 26 bytes of display list. A flagged row needs more runs than fit. Either make the tiles in it agree on a palette, or move the odd tiles to a different row. Remember that blank cells count too — the blank tile's palette decides the run structure of every row it appears in.
Two palette loaders are running. The sprite include's <INCLUDE>_SET_PALETTES and the tile map's INSTALL write the same eight registers, and the sprite one flattens every entry to the middle colour. Call the tile map's INSTALL and not the sprite loader.
In the desktop app, look under the project's tiles/ folder. In a browser preview, Save downloads the project file; import that file into the desktop project when you want it to appear in the explorer.
Make the map wider than 32 NES metatiles, include the exported map data, and add the streaming step to the scrolling code. The workshop creates and exports the level data; the game code remains responsible for moving that data into the PPU as the camera advances.
LEVEL_GROUND_1 is read before it is introducedA game that kept its terrain as a height table (a value per column) alongside a 7800 tile map has had that table deleted or moved below the procedure that reads it. A tile map is drawing data only: it carries no collision for your game to fall back on, so a height table used by the collision test has to stay in the source and stay above its readers.
Three things have to be true: @OPTION TILE_ACTIVE_COUNT must be set to the bank size the include reports, the include's INSTALL must be called once before any screen, and the screen itself is drawn by its SHOW procedure. Also check tile 0: it is deliberately never defined, so anything painted with it is background by design.
For an Atari 7800 screen, create a map, make the small bank a terrain game needs (a blank tile, a ground tile, the two or three tiles that matter), paint one 40 × 24 screen, watch the Budget panel read 10 of 26 bytes per row, add a marker or two, export the include, and call INSTALL then SHOW from your game.
For the NES scrolling demo, create a scrolling-background map, keep its background CHR range at $00–$3F, build a few 2 × 2 metatiles, make the map wider than one screen, export the include, and wire its CHR loader and map/attribute tables into the existing scroll renderer.