๐Ÿ“„ White Paper ยท v1.0

A Label-Driven
Procedural Tilemap Generator

Version 1.0Year 2026Reading time ~15 min

Abstract

Building 2D game levels from a tileset is slow and unintuitive. Existing tools demand that creators learn the vocabulary of tilemaps โ€” corners, caps, transitions, adjacency rules, Wang tiles, bitmasks โ€” before placing a single tile correctly. Mosaic removes that barrier. Instead of describing how tiles connect, the creator describes what each tile is ("this is ground surface," "this is a platform," "this is a background prop"). Mosaic infers the connection logic automatically and generates polished platformer and top-down levels, then exports them to mainstream engines including Godot, Unity, Phaser, and Tiled.

1Introduction

Mosaic is a browser-based tool for turning a tileset or spritesheet into finished 2D game levels. It pairs a visual labeling interface with a procedural generator and a multi-engine export layer. The entire workflow โ€” upload, label, generate, refine, export โ€” runs client-side in a single HTML application, with no installation and no server round-trips. Tilesets never leave the creator's machine.

A creator should be able to say what their art represents, not how it connects. The tool should be smart enough to do the rest.

2The Problem

A tileset is just an image cut into a grid of small squares (commonly 16ร—16 pixels). Turning that grid into a coherent level is deceptively hard, because tiles are not interchangeable โ€” a "ground" tile that works in the middle of a hill looks broken on a left edge, a right edge, an inside corner, or a one-tile-wide pillar.

To place tiles correctly, traditional tools require the creator to encode the relationships between tiles:

This is an upfront barrier. Learning how tiles connect is genuinely valuable craft โ€” but being required to master it before placing a single tile puts a wall between the creator and their intent. For hobbyists, students, jam participants, and artists, that wall is steep enough that many never finish a level. Even for professionals, re-encoding the same rules by hand is repetitive, error-prone busywork. The goal isn't to keep anyone from learning these concepts โ€” it's to remove them as a precondition for starting. Beyond rules, hand-authoring is slow: backgrounds must be tiled by hand, ground filled cell-by-cell to avoid gaps, props positioned so they don't float or sink, and platforms spaced so the level is playable. Mosaic targets all of these.

3Prior Art

ToolApproachThe catch
TiledManual painting + optional Wang/terrain setsPowerful, but the creator defines and maintains all terrain rules.
LDtkAuto-layers driven by IntGrid rulesExcellent for rule-based detail, but still rule-authoring; learning curve.
Wave Function CollapseConstraint-solving from an exampleEmergent but hard to direct; can contradict/fail; non-deterministic.
Engine editors (Godot, Unity)TileSet terrain + manual paintingTied to one engine; still require terrain/bitmask setup.

Each assumes the creator masters the underlying tile-relationship model before they can build. Mosaic's differentiator is that it doesn't require that upfront โ€” and because it generates correct, real examples, it doubles as a hands-on way to pick those concepts up by observation. It trades some unbounded flexibility for a dramatically gentler on-ramp and faster time-to-a-finished-level โ€” while still exporting into those same tools when deeper editing is desired.

4Design Philosophy

4.1 Label intent, not mechanics. The creator labels categories of meaning โ€” "Ground Surface," "Platform Base," "Large Background Prop" โ€” never "inner corner bitmask 13." Category names are human, not technical.
4.2 Infer everything inferable. Edge/corner selection, fill-down behavior, backing layers, prop anchoring, and platform spacing are all derived automatically from labels and terrain shape.
4.3 Only use what was labeled. Mosaic never injects hardcoded fallback tiles. If a category wasn't labeled, it isn't generated. The output is composed exclusively from the creator's own art.
4.4 Visual correctness over algorithmic cleverness. The product is judged by how the image looks: clean ground, no gaps, no floating or buried props, readable layers, well-spaced platforms. Ugly rules get changed, not defended.
4.5 Keep the human in the loop. Generation is a strong first draft, not a locked output. Creators repaint cells, hand-place props pixel-perfectly, manage layers, and re-roll seeds.

5System Architecture

Mosaic ships as a small set of cooperating parts, all client-side.

          index.html  (Mosaic landing site)
                 โ”‚ Launch App
                 โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚              tile_labeler.html                โ”‚
   โ”‚            (the Mosaic application)           โ”‚
   โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
   โ”‚  โ”‚ Label โ”‚ โ”‚ Place โ”‚ โ”‚  Edit  โ”‚ โ”‚ Generate โ”‚  โ”‚
   โ”‚  โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
   โ”‚      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜        โ”‚
   โ”‚      Shared state: labels ยท blocks ยท          โ”‚
   โ”‚      placements ยท sheets                      โ”‚
   โ”‚            โ”‚           โ”‚            โ”‚         โ”‚
   โ”‚       Generation   Save/Load     Export       โ”‚
   โ”‚        engine       (JSON)    (Phaser/TMX)    โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                 โ”‚
                 โ–ผ
     generate_level.py        (optional CLI generator)
     godot_level_loader.gd    (native Godot loader)

The application (tile_labeler.html). A single self-contained HTML/CSS/JS file hosting four modes โ€” Label, Place, Edit Map, Generate โ€” over shared state. Rendering uses Canvas 2D with imageSmoothingEnabled = false for crisp pixel art. The base tile unit is 16ร—16 px.

The generator. A native-JavaScript generator runs in-browser for instant results; a parallel Python generator (generate_level.py) serves batch/CLI workflows. Both read the same labeled JSON.

The landing site & export artifacts. index.html introduces the product; the export layer emits engine-native files, with godot_level_loader.gd as the zero-plugin Godot companion.

6The Labeling System

Labeling is the heart of Mosaic. The creator works on the tileset image directly:

Internally the system stores labels (a map of tile index โ†’ category IDs) and blocks (rectangular definitions { category, startCol, startRow, w, h, sheet }).

6.1 The render stack

Mosaic composes a level back-to-front so layers read cleanly:

  1. Sky / Parallax Background
  2. Background Silhouette
  3. Ground Fill Backing
  4. Ground Surface
  5. Ground Body / Mid Fill
  6. Platforms
  7. Background Props / Buildings
  8. Small Decorative / Manually-Placed Props

A key invariant: the ground fill backing renders behind surface and body to eliminate transparency gaps, but never appears above a ground surface โ€” it starts at each column's own surface height and fills downward only.

7The Generation Engine

Mosaic supports three game-type modes โ€” Platformer, Top-Down, and High 3/4 (Zelda-style) โ€” each with its own generator reading the same labeled categories.

7.1 Platformer generation

  1. Terrain heightmap โ€” a seeded height per column defines the ground silhouette.
  2. Ground surface โ€” the top row uses automatic left/mid/right/solo edge selection inferred from labeled surface tiles.
  3. Ground body fill โ€” body/mid tiles fill to the bottom; no caps or corners inside; ground is fully solid.
  4. Ground fill backing โ€” a matched backing behind surface/body covers transparent pixels.
  5. Platforms โ€” top + base only, with enforced spacing and clearance, so the level stays playable.
  6. Props โ€” placed under strict support rules (ยง8).

7.2 Top-down generation

Both return a tile grid, a parallel category grid, and a prop overlay list.

7.3 Determinism

Every generator is seeded: same labels + same seed + same parameters always produce the same level, making results shareable and reproducible. Changing the seed re-rolls layout while keeping art and rules intact.

7.4 Natural-language steering

Generation can be nudged with a short design prompt. A lightweight keyword heuristic (no LLM required) maps descriptive words toward parameter adjustments โ€” an approachable way to bias output without exposing raw knobs.

8The Prop System

Props are the detail layer that makes a level feel alive โ€” and the easiest thing to get wrong. Props that float, sink, hang off ledges, or stack immediately break the illusion. Mosaic handles props two ways.

8.1 Automatic placement

8.2 Manual placement (Place mode)

  1. Label small props first.
  2. Switch to Place mode; the generated preview appears automatically.
  3. Pick a prop and click to stamp it exactly; erase and undo supported.
  4. Placements save into the same JSON.
  5. The generator stamps manual placements precisely on the next render.

Place mode renders pixel-perfectly and guards its handlers by mode, so labeling logic never fires during placement.

9The Dual-Sheet System

Real projects often keep terrain and props on separate spritesheets. Mosaic supports two: Sheet 0 (main tileset) and Sheet 1 (optional props sheet). Tile identity is unified by a simple encoding: indices โ‰ฅ 100000 (SHEET2_OFFSET) belong to the props sheet, with local index = index โˆ’ 100000. A decode helper resolves any index to { sourceImage, columns, localIndex }. This single convention flows through labeling, blocks, generation, rendering, placement, and export.

Label data is sheet-aware: saving records which sheets a file covers, and loading replaces only those sheets โ€” so a terrain-label file and a props-label file load together without overwriting each other. Game type is applied only from a file covering the main sheet, preventing a props file from silently switching the project's mode.

10The Export Pipeline

A finished Mosaic level is, at its core, a 2D grid of tile indices plus a parallel category grid and a prop overlay list. Because that grid is the universal currency of every tile engine, using a Mosaic level in an engine reduces to reformatting the grid and shipping the tileset image.

10.1 Shared Tiled model

Exports are built from one shared Tiled-format model: one tileset entry per spritesheet (with correct dimensions, columns, tile counts, and firstgid offsets), a ground tile layer mapping each cell to a GID (index + 1, 0 = empty), and a props tile layer where each placed prop block is expanded back into its constituent tiles.

10.2 Phaser

A Tiled-format JSON (level_phaser.json) consumed directly by Phaser's load.tilemapTiledJSON. Both sheets become tilesets; ground and props become layers.

10.3 Tiled .tmx

A standard Tiled XML map (level.tmx) with CSV layer data โ€” the universal bridge: Unity via SuperTiled2Unity, Godot via the Tiled importer, and the Tiled editor itself.

10.4 Native Godot

For a zero-plugin path, godot_level_loader.gd reads the level JSON, converts each index to atlas coordinates (index % columns, index / columns), routes any index โ‰ฅ 100000 to the props sheet, and rebuilds the level at runtime.

10.5 Raw data

A raw level-data JSON and rendered PNG are always available for custom engines.

11Data Formats

Mosaic uses three human-readable JSON documents (full schemas in Appendix B): a label file, the generated level data, and the engine export. The parallel categories grid is significant โ€” by recording which category placed each tile, Mosaic preserves semantic meaning that a flat index grid would lose, enabling reliable layer splitting and planned features like automatic collision flagging.

12Use Cases

13Roadmap

Near term

Medium term

Long term

14Conclusion

Mosaic reframes level creation around intent instead of mechanics. By asking creators only to label what their tiles represent โ€” and inferring edges, fill, backing, spacing, and prop placement automatically โ€” it collapses the distance between a raw spritesheet and a polished, exportable level. The output uses only the creator's own art, stays under their control through editing and manual placement, and lands cleanly in the engines they already use.

Label what pieces are. Let Mosaic make the smart placement decisions.

AAppendix โ€” Category Reference

CategoryPurposeKey rules
Sky / Parallax BackgroundFull-image backdrop behind everythingComposed as one block image; repeats horizontally (never stretched); never scattered.
BG SilhouetteMid-background strip between sky and groundBlocks join into one wide image; repeats; bottom-anchored to lowest ground; never overpowers foreground.
Ground SurfaceTop walkable rowAutomatic left/mid/right/solo edges; sits on ground body; creator never labels corners.
Ground Body / Mid FillSolid fill below the surfaceMid/fill tiles only; fills to the bottom; no caps/corners inside.
Ground Fill BackingBacking to prevent transparency gapsMatches body; behind surface/body; starts at each column's surface and fills downward only.
Platform Surface / BaseFloating platformsTop + base only; minimum spacing; ground clearance; not bunched.
Large Background PropBig structures (ruins, buildings)Flat run โ‰ฅ prop width; never hang off ledges or sink; never stack; avoid platform columns.
Small Decorative PropDetail sprites (rocks, signs, plants)Auto-placed on valid background (off paths), or hand-placed; stamped exactly; transparent overlay.
Top-down floor / edges / cornersfloor_mid, floor_edge_*, floor_corner_*, floor_inner_corner_*Drive blob / corner-blend autotiling so landmasses and paths tile seamlessly.

BAppendix โ€” JSON Schemas

B.1 Label file

{
  "game_type": "platformer | topdown | hightopdown",
  "cols2": 32,                      // columns in the props sheet (if used)
  "tiles": {                        // category -> [tile indices]
    "sky_bg": [32],
    "floor_mid": [8],
    "floor_edge_top": [2]
  },
  "blocks": {                       // category -> [rectangular blocks]
    "bg_prop": [
      { "start": 128, "w": 3, "h": 4, "sheet": 1 }
    ]
  },
  "placements": [                   // manual prop placements (Place mode)
    { "idx": 100128, "x": 24, "y": 17 }
  ]
}

B.2 Generated level data

{
  "seed": 12345,
  "width": 64, "height": 24, "scale": 3,
  "game_type": "topdown",
  "shape": "blob | paths",
  "ground_y": [ /* per-column ground heights (platformer) */ ],
  "tiles":      [ [ /* tile index per cell, -1 = empty */ ] ],
  "categories": [ [ /* category string per cell, "" = empty */ ] ],
  "props": [
    { "startIdx": 100128, "bw": 3, "bh": 4, "x0": 12, "y0": 9 }
  ]
}

B.3 Tile-index conventions