Tiles: the Autotile asset is renamed to Tile, new kind None (1 × 1), older projects, check total 1013 (#131)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
adminandClaude Opus 5 committed 2026-09-18 08:01:10 +02:00
1 parent 310c6b8897
commit 60be8d9aff
6 files changed
+63 -49

No files matched your search

+3 -3
@@ -61,7 +61,7 @@
```
web/index.html Vite source page (dev) index.html built page (generated, served)
src/core/model/ Project (object holders), Asset + AssetTypes, SceneObject, Properties (value types), hierarchy, walk (generic parent/child walks), instance (container content resolved from its template), usages (where an asset is used), container (the cycle guard), placement (what may be dropped where), texture (frames and the slice grid), autotile (the two block kinds, which quarter tile a neighbourhood asks for, the 47/16 tiles a block produces), tilemap (the cells of a layer, which neighbours a cell is joined to, the cells a stroke or a rectangle covers), animation (which frame at time t, a row's value there, what a row may aim at, the players on an object; KeyRef and its lookups) + animationPreview (the root at a frame, written into copies), graphLookup (what a graph sees of the project: behaviors to run, state machines to read), Scope (where a state machine's current state lives: per instance or one for the run — variables are shared by living on a Variables asset instead)
src/core/model/ Project (object holders), Asset + AssetTypes, SceneObject, Properties (value types), hierarchy, walk (generic parent/child walks), instance (container content resolved from its template), usages (where an asset is used), container (the cycle guard), placement (what may be dropped where), texture (frames and the slice grid), tile (the three kinds and their block shapes, reading a tile's pictures, the animation step), autotile (which quarter tile a neighbourhood asks for, the 47/16 tiles a block produces, 1 for a plain tile), tilemap (the cells of a layer, which neighbours a cell is joined to, the cells a stroke or a rectangle covers), animation (which frame at time t, a row's value there, what a row may aim at, the players on an object; KeyRef and its lookups) + animationPreview (the root at a frame, written into copies), graphLookup (what a graph sees of the project: behaviors to run, state machines to read), Scope (where a state machine's current state lives: per instance or one for the run — variables are shared by living on a Variables asset instead)
src/core/properties/ PropertySchema, kinds (one row per value kind), listItems (an item's kind, read off its value), resolve (the only override merge), deviation (what is gold), collider/camera/bounds geometry, aspect, enabled, editorRun, assetRef/textureRef (how a reference reads), declaredRows (the row a Property node declares in a shader or particle graph, and the params that node has in both)
src/core/commands/ undoable commands, CommandStack, SetBagValueCommand base, RenameCommand base (undone by renaming back: variable, struct field, port), one import command shape for texture/font/sound, require.ts (validated lookups, and what an instance may not change), naming.ts
src/core/graph/ graph model, NodeRegistry/NodeContext/values, interpreter, dropTarget, nested (behaviors as nodes),
@@ -106,9 +106,9 @@ src/editor/texture/ TextureEditor (header + picker), TextureCanvas (picture +
src/editor/animation/ AnimationEditor (header + picker, preview over timeline), PreviewCanvas (the root at the playhead, a FreeViewport
over animationPreview.ts), TimelineCanvas (rows, keys, ruler, clipboard), timelineView (its geometry),
RowDialog + FramesDialog (FormDialogs)
src/editor/autotile/ AutotileEditor (header + picker + kind), AutotileCanvas (every tile of the block and a sample map, animated),
src/editor/tile/ TileEditor (header + picker + kind), TileCanvas (every tile of the block and a sample map, animated),
PictureStrip (the pictures as animation steps; dropIndex is the reorder maths)
src/editor/inspector/ … tilemapSection (tools, autotiles and layers of a placed tilemap; painting itself is SceneViewport)
src/editor/inspector/ … tilemapSection (tools, tiles and layers of a placed tilemap; painting itself is SceneViewport)
src/editor/statemachine/ StateMachineEditor (header + picker, on the graph canvas)
src/editor/particles/ ParticlesEditor (graph canvas left of a preview panel, splitter between them),
ParticlePreview (the panel: the asset's own particles, wearing its own rows)
+4 -4
@@ -12,7 +12,7 @@ npm run check # typecheck + lint + format:check + tests, the gate CI runs
# code is lost (tail's is reported), so a red run reads as green
npm run build # writes dist/ and regenerates index.html
./build.sh # the same under `set -o pipefail`, for callers that pipe the output
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1009 editor checks, screenshots in /tmp/gm-e2e-*.png
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1013 editor checks, screenshots in /tmp/gm-e2e-*.png
GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step
./e2e.sh start [GM_STEPS] # the same run detached, see below
./e2e.sh status # live progress, or the last run's result
@@ -64,7 +64,7 @@ The e2e run is a list of steps in `tools/e2e/` (hierarchy, inspector, play, asse
graph, parenting, colliders, containers, text/enabled, menus, textures, frames, overflow, aspect,
container tab, run-in-editor, pause, nested behaviors, key repeat, list tab, struct variable,
variable nodes, property nodes, animations, state machines, console, shaders, transforms, fonts,
particles, shared scope, render on change, sounds, load scene, graph groups, nine-slice, plugins, autotiles, tilemaps) that build on each other's
particles, shared scope, render on change, sounds, load scene, graph groups, nine-slice, plugins, tiles, tilemaps) that build on each other's
scene state and share the CDP driver in `tools/lib/harness.mjs` — `press`, `undo`, `play`,
`object(id)`, `world()`, `mutate(js)` and friends, so a check reads like the interaction it
exercises.
@@ -104,7 +104,7 @@ whole suite down the day the Particles tab was added.
The same holds for the **`+` menu**: it has one entry per asset type, and an entry below the mask
edge is still found by `locate` while a click on it lands on nothing. The fourteenth type
(Variables) pushed `Font` under that edge and took the font step down, because only the particles
step had carried a workaround of its own; sound is the fifteenth, the autotile the sixteenth and the tilemap the seventeenth. Since #43 a menu may grow to the
step had carried a workaround of its own; sound is the fifteenth, the tile the sixteenth and the tilemap the seventeenth. Since #43 a menu may grow to the
height of the canvas, so on the test window all seventeen stand on screen at once — the step still
picks a type with `pickAssetType(t, 'Font')` from the same file, which keeps the scroll as insurance
for a shorter window. The menu's own order is checked in the assets step through `__gm.menuRows()`:
@@ -232,4 +232,4 @@ widths to find click points. The **render device is not in this repo** — `/dev
and a 1 GB `/dev/shm` come from `container.options` in the runner's own `config.yaml`, which
applies to every job on that runner. Without them chromium falls back to llvmpipe, which gets
WebGL 1.0 only. Measured in the job container: `ANGLE (Intel, Vulkan 1.3.230, HD Graphics 630)`,
WebGL 2.0, and the same 1009 checks as here.
WebGL 2.0, and the same 1013 checks as here.
+1 -1
@@ -18,7 +18,7 @@ Live: <https://nockal.com/game-maker/> · Widget playground: <https://nockal.com
| [Fonts](Fonts) | Uploading a typeface, what a text wears, what the editor falls back to |
| [Sounds](Sounds) | Uploading a sound, what the asset says, `Play sound` and `Stop sound`, what a pause and a stop do to a voice |
| [Animations](Animations) | Animation assets, the Animation tab, how they run |
| [Autotiles](Autotiles) | The autotile asset, the two block kinds, the pictures as animation steps, the Autotile tab |
| [Tiles](Tiles) | The tile asset, plain tiles and the two autotile kinds, the pictures as animation steps, the Tile tab |
| [Tilemaps](Tilemaps) | The tilemap asset, painting in the scene view, layers, what it looks like in the game |
| [State machines](State-machines) | The state machine asset, its scope, named transitions, the start state, `State branch` and its `else`, `Set state`, `Set state by name`, `State transition`, the two state events and the live highlight |
| [Shaders](Shaders) | The shader asset, the Shader tab, the node set, the Adjust colors recipe, wearing a shader |
+16 -16
@@ -1,8 +1,8 @@
# Tilemaps
A **tilemap** is a grid painted with [autotiles](Autotiles), and it is what puts them into a scene:
an autotile is a tile, the tilemap is the ground it is laid on. It is an asset like any other, and
unlike an autotile it is **placed** — drag it from the asset panel into the scene, and it is drawn
A **tilemap** is a grid painted with [tiles](Tiles), and it is what puts them into a scene: a tile
is what lies in a cell, the tilemap is the ground it is laid on. It is an asset like any other, and
unlike a tile it is **placed** — drag it from the asset panel into the scene, and it is drawn
in the editor, in the running game and in the preview alike.
## The asset
@@ -12,16 +12,16 @@ in the editor, in the running game and in the preview alike.
| Row | What it means |
|---|---|
| Columns, Rows | How far the grid reaches. Cells outside are not drawn — and not thrown away either, so making the grid smaller and larger again brings the drawing back. |
| Tile size | The side of one cell in world units. An autotile's pictures are scaled onto it, so one map can mix autotiles drawn at different resolutions. |
| Tile size | The side of one cell in world units. A tile's pictures are scaled onto it, so one map can mix tiles drawn at different resolutions. |
Everything else is the usual: the switch, the position, scale, rotation and mirroring. The map is
centred on its position, as every other object is.
**Which tile a cell shows is never stored.** It follows from the neighbours and is worked out while
drawing, so painting one cell fixes the edges of the ones around it by itself. Only *which
autotile* lies in a cell is kept.
**Which quarters a cell shows are never stored.** For an autotile they follow from the neighbours
and are worked out while drawing, so painting one cell fixes the edges of the ones around it by
itself; a plain tile looks the same everywhere. Only *which tile* lies in a cell is kept.
Two different autotiles do **not** join: each one closes against everything else, which is how the
Two different tiles do **not** join: each one closes against everything else, which is how the
RPG-Maker sheets are drawn. Outside the grid counts as empty as well, so a map ends with a proper
edge.
@@ -31,7 +31,7 @@ Select a placed tilemap; the inspector then shows a **PAINTING** section under i
- **Select** leaves the scene view as it is: the map is picked up and dragged like any other object.
This is what a tilemap starts in — a map one cannot move would be worse than a click.
- **Brush** paints the chosen autotile. A drag paints every cell it passes, not only the ones the
- **Brush** paints the chosen tile. A drag paints every cell it passes, not only the ones the
pointer was reported at.
- **Erase** clears cells the same way.
- **Rect** fills the box a drag spans; while dragging, that box is outlined.
@@ -40,9 +40,9 @@ While any of the three is chosen, the map shows its cell grid, so one does not p
Shift-drag still pans the view, whatever the tool.
**One stroke is one undo step** — a line of twenty cells comes back with one Ctrl+Z, and a stroke
painted over another autotile puts *that* one back, not merely emptiness.
painted over another tile puts *that* one back, not merely emptiness.
Under **AUTOTILES** stands every autotile of the project; picking one reaches for the brush by
Under **TILES** stands every tile of the project; picking one reaches for the brush by
itself. Without one chosen, painting says so instead of quietly doing nothing.
## Layers
@@ -61,16 +61,16 @@ something to paint on.
## In the running game
A tilemap is scene content, not editor decoration: it is drawn in the game exactly as in the
editor, and an animated autotile keeps running there at its own rate. Every map showing the same
autotile is on the same step, so animated water does not run out of phase between two of them.
editor, and an animated tile keeps running there at its own rate. Every map showing the same
tile is on the same step, so animated water does not run out of phase between two of them.
Drawing is done with **one mesh per autotile and layer** rather than one sprite per cell, so a map
of a thousand tiles costs as many draw calls as it has autotiles on that layer.
Drawing is done with **one mesh per tile and layer** rather than one sprite per cell, so a map of a
thousand cells costs as many draw calls as it has tiles on that layer.
## What it does not do yet
- **No collision.** A tilemap is a picture; figures walk through it. Whether it should contribute
colliders is a question of its own and is not decided.
- Nothing fills an area by flooding it, and there is no picking up a tile off the map.
- The cells are stored one entry per painted cell (`"x,y"` → autotile), uncompressed. Big maps
- The cells are stored one entry per painted cell (`"x,y"` → tile), uncompressed. Big maps
therefore make big project files; the format leaves room to pack them later.
+38 -24
@@ -1,21 +1,26 @@
A tile that draws its own edges. Paint a patch of grass onto a map and the borders towards
everything else — the rounded corners, the straight edges, the notch where two edges meet — are
picked per tile from one hand-drawn **block**. That block is what an **autotile asset** holds.
# Tiles
The asset exists on its own, not inside a map: the same grass is used by several maps, the same
way a texture is worn by several sprites. Placing one is the tilemap, which is
[#128](https://git.nockal.com/meleki/game-maker/issues/128) and not built yet — until then an
autotile is visible in its own tab, where every tile it can produce is drawn.
A **tile** is what a [tilemap](Tilemaps) paints with. It is its own asset, not part of a map: the
same grass is used by several maps, the same way a texture is worn by several sprites. Until #131
the asset was called *autotile*; projects saved before that open unchanged (see below).
A tile is one of three **kinds**:
| Kind | Block | Tiles it produces | What it does |
|---|---|---|---|
| **None (1 × 1)** | 1 tile | 1 | the picture as it is, repeated in every painted cell — the default |
| **Floor (2 × 3)** | 2 tiles wide, 3 tall | 47 | an **autotile**: edges, convex corners and **notches** (inner corners) |
| **Wall (2 × 2)** | 2 tiles wide, 2 tall | 16 | an **autotile**: edges and convex corners, no notches |
A plain tile (*None*) ignores its neighbours. The two autotile kinds draw their own edges: paint a
patch of grass onto a map and the borders towards everything else — the rounded corners, the
straight edges, the notch where two edges meet — are picked per cell from one hand-drawn **block**.
## The block
A block is a picture cut into **quarter tiles**. Two kinds, the two shapes the classic RPG-Maker
sheets use:
| Kind | Block | Tiles it produces | Has |
|---|---|---|---|
| **Floor (2 × 3)** | 2 tiles wide, 3 tall | 47 | edges, convex corners and **notches** (inner corners) |
| **Wall (2 × 2)** | 2 tiles wide, 2 tall | 16 | edges and convex corners, no notches |
A block is a picture cut into **quarter tiles**. For a plain tile the block is the tile itself and
its four quarters are drawn where they are. The two autotile kinds are the two shapes the classic
RPG-Maker sheets use.
The bottom 2 × 2 tiles of either block are one fully bordered tile: its middle four quarters are
the inside, the ring around them the borders and the convex corners. A floor block has one tile row
@@ -31,20 +36,22 @@ in the sheet. The borders behave normally, left on the left and top on top. The
RPG Maker MZ (`Tilemap.FLOOR_AUTOTILE_TABLE`), and the tests check the editor against that table
row by row.
**The tile size comes from the picture**: a block is two tiles wide by definition, so a 96 px wide
block means 48 px tiles and 24 px quarters. There is no field for it — a second number could only
**The tile size comes from the picture**: the kind says how many tiles wide a block is, so a 96 px
wide floor block means 48 px tiles and 24 px quarters, and a 48 px square picture is a 48 px plain
tile. A plain tile only has to be square — an odd side is fine; an autotile block must split evenly
into its quarters. There is no field for it — a second number could only
ever disagree with the picture. What the tab does check is that the block has the shape its kind
asks for; a picture that does not fit is kept and named, never silently dropped.
## The asset
**+ → Autotile** makes an empty one. What it holds:
**+ → Tile** makes an empty one, of kind *None*. What it holds:
- **Pictures** — one block per animation step, in the order they run. A picture is either a
**texture** (a file that holds nothing but the one block) or a **frame** of a texture (one block
cut out of a sheet that holds many). Cutting them is the [Textures](Textures) tab, by hand or
with **Slice…** where the sheet is a regular grid.
- **Kind** — *Floor (2 × 3)* or *Wall (2 × 2)*. Chosen, not guessed: a sheet whose rows alternate
- **Kind** — *None (1 × 1)*, *Floor (2 × 3)* or *Wall (2 × 2)*. Chosen, not guessed: a sheet whose rows alternate
between the two shapes (`Outside_A4` in RPG Maker) would be read wrong either way, and the choice
is one click.
- **Frames per second** and **Playback** (*Loop* or *Ping-pong*) — how the pictures run. One
@@ -56,14 +63,15 @@ Kind, rate and playback are ordinary properties, so the inspector shows them lik
## The tab
- The **picker** in the header chooses the autotile, the one beside it the kind, **Fit** frames the
- The **picker** in the header chooses the tile, the one beside it the kind, **Fit** frames the
board. The readout on the right says kind, tile size, pictures, rate and how many tiles the block
produces — or *not usable yet* with the reason written under the board.
- The **board** shows every tile the block can produce, captioned with the neighbours that ask for
it: `NESW-nw` is "joined on all four sides, with a notch towards the north-west", `·` is a lone
tile. Below the grid a **sample map** is composed from the same quarters — a ring with a hole and
a step, which is where one sees whether the edges really continue across tile borders. Both run
the animation at the set rate.
a step, which is where one sees whether the edges really continue across tile borders. For a
plain tile the grid is the one tile and the sample map shows it repeated. Both run the animation
at the set rate.
- A drag pans the board, the wheel zooms it; nothing on it is edited.
- The **picture list** on the right is the animation: **+ Picture** adds a texture or a frame,
**Remove** takes the selected one out, and dragging a row to another place reorders the steps.
@@ -71,6 +79,12 @@ Kind, rate and playback are ordinary properties, so the inspector shows them lik
## Where they are placed
An autotile is never placed by itself: it is laid down by a [tilemap](Tilemaps), which is the asset
that carries a grid of cells and is placed in a scene. Two different autotiles do not join each
other there — each one closes against everything else, as the RPG-Maker sheets are drawn.
A tile is never placed by itself: it is laid down by a [tilemap](Tilemaps), which is the asset
that carries a grid of cells and is placed in a scene. Two different tiles do not join each other
there — each autotile closes against everything else, as the RPG-Maker sheets are drawn.
## Older projects
A project saved before #131 holds `autotile` assets. Loading it turns them into `tile` assets
without a word, and one that had no kind stored becomes a **Floor** — what it meant then — rather
than falling to the new default *None*. Nothing else changes; saving writes the new name.
+1 -1
@@ -9,7 +9,7 @@
- [Fonts](Fonts)
- [Sounds](Sounds)
- [Animations](Animations)
- [Autotiles](Autotiles)
- [Tiles](Tiles)
- [Tilemaps](Tilemaps)
- [State machines](State-machines)
- [Shaders](Shaders)