The last step of the learning path is the one that never ends: put the map in front of people, find out what it actually does, and change it without breaking it.
The learning path so far:
- Your First Map.
- Your First Win Condition.
- Your First Custom Unit.
- Your First Mod.
- Publish and iterate (this page).
Publish earlier than feels comfortable
A map that one person can win and lose is worth more than a map with nine waves that nobody has played. Publishing is not a commitment: the map updates in place, the link never changes, and you can unpublish it in one click.
The short pre-flight, in full detail on Publishing:
- Validation clean, with any warnings read and dismissed on purpose.
- Tested from a seat other than seat 0.
- Every wave, objective and cutscene fired at least once. The Trigger Debug
panel (
Ctrl+Shift+F9) shows exactly which ones did. - Debug text removed.
- Starting resources and fog set to what you actually want, not what was convenient while testing.
- The name and description say what the map is.
Then File → Publish to Custom Games…, and Copy Share Link. The link works for anyone, signed in or not.
What comes back
Three things, and they arrive at different speeds.
Ratings. Signed-in players rate other people's maps from one to five stars in the map browser, and the gallery shows the average.
Plays. Starting a single-player match on your map counts as a play, at most once an hour per player. Opening the map's details page is not a play, and matches started from a multiplayer lobby are not counted, so the number is a floor rather than a total.
Reports. Players can report a map as offensive, spam, broken, a copyright problem, cheating or other. A map with three open reports is hidden automatically until a moderator looks at it. "Broken" is the one that should concern you, and the fastest way to earn it is a map that cannot be finished.
None of this tells you why. For that, watch someone play, or play it yourself from a seat you did not design around.
Updating without losing the old version
Open the map in The Forge and Save. The published map updates in place: same id, same share link, and players get the new version the next time they load it. The server validates again, and refuses the update if the new version has errors. Your browser draft is still saved either way.
Three things to know before you change a published map:
- There is no version history. If you want the current version to stay playable, File → Save As Copy first, and publish the copy under its own name.
- Saving does not refresh the player count the gallery shows. If you change how many seats the map takes, publish it again through the Publish dialog.
- A rewrite should be a new map. When the new version is a different game, the ratings and the plays on the old one are describing something that no longer exists.
Iterate on measurements, not on hunches
This is the part that separates a map that improves from one that oscillates.
Every balance change you make has a number attached, whether or not you look at it: how long the map takes, how many waves a default build survives, how much health the objective has left at the end. Write the number down before you change anything, and check it after.
The fastest way to do that is the headless runner, from a checkout of the repository. It plays the whole match with no window and no player, and prints the result:
npx tsx packages/modkit/src/cli.ts play my-map.json \
--ticks 3000 --seed 1 \
--assert 'state=victory' --assert 'winner=0' --assert 'var:hold_ticks>=400'ended victory — winner seat 0 at tick 381 (19s) [trigger]
vars hold_ticks=400
fires Count shrine control ×20, Setup ×1, Objective complete ×1
caps 0
broken 0
errors 0
asserts:
PASS state=victory (actual: victory)
PASS winner=0 (actual: 0)
PASS var:hold_ticks>=400 (actual: 400)
RESULT OKKeep that command in a file next to the map and run it after every change. It is a regression test for your own design, and it catches the class of mistake that playtesting misses: the change that still works, just not the way it used to.
Four habits that make it worth the effort:
Assert the progress, not just the outcome. winner=0 also passes on a map
that won for the wrong reason. var:lives>0 says the defence actually held.
This is why the previous pages kept insisting every objective gets a variable.
Assert both endings. A win run and a loss run. A map only one of whose endings has ever executed is a map with one ending.
Watch the caps line. A non-empty caps means a trigger overran a budget
and was switched off. Real players see that as stutter, and it will not show up
in the outcome at all.
Read ended before anything else. A run that stops one tick short prints
still running, which reads exactly like a dead trigger. The shipped tower
defence showcase, run for 600 ticks, prints still running after 600 ticks;
run for 6000 it prints defeat — winner none at tick 2056. Same map, same seed,
two completely different conclusions.
Measuring a difficulty curve
"Wave 7 feels hard" is not a measurement. What the shipped example maps do instead is record the curve through the real spawner and check that it rises.
The lane-race example's creep count at each round's peak, measured rather than read off the design table:
10 → 14 → 18 → 22 → 28 → 30 → 32 → 40 → 43 → 48The siege example's besiegers on the field at each wave's peak:
5 → 8 → 11 → 22 → 21Notice the second one falls at the end. That is the sort of thing a table of intended numbers hides and a measurement does not. Wave 5 is smaller than wave 4 and still harder, because of what is in it rather than how much.
You do not need a test harness for this. Run the map headlessly, read the counter your triggers already keep, and write the numbers down. The walkthroughs for the example maps show the numbers each one was tuned against.
When the map is for other people to build on
If your map is a template rather than a destination, two extra things help:
- Say what the decision is. Every good custom map asks the player one question over and over. Write it in the description.
- Keep the ids and the regions tidy. Somebody is going to open your map in
The Forge and change it, and
region_7tells them nothing.
Common mistakes at this stage
| What you see | What it usually is |
|---|---|
| Ratings drop after an update | The update changed the game rather than fixing it. Save As Copy exists for this |
| The gallery still shows the old player count | Saving does not refresh it. Publish again through the dialog |
| The map is hidden | Three open reports hide a map automatically until a moderator reviews it |
| The publish is refused | The server validates again on receipt. The dialog says which rule |
| A balance change broke a wave | No assertion covered it. Add one for the number that moved |
| It plays fine for you and stutters for others | Check the caps line on a long headless run |
Where to go next
You have finished the learning path. From here the docs stop being a sequence and start being a reference:
- The Genre Cookbook: a recipe for each of the common shapes, with a command per recipe.
- Testing and Validation & Tooling: everything the game can check for you.
- Performance and limits: every budget, with its live value.
- Frequently asked questions and the Glossary for anything that did not have a home.
Next: The Genre Cookbook.