Modding
Modding in 2D Tower uses data-only content packs. A pack can add room variants by inheriting one of the game's built-in room behaviours and changing the supported data fields. Mods cannot include scripts, so they cannot replace game code or add a wholly new runtime behaviour.
Create or install a pack
For a local mod, place one pack folder inside the game's local mods directory:
user://mods/
└── my_record_store/
├── manifest.json
├── rooms/
│ └── record_store.json
├── textures/
│ └── records.png
├── i18n/
│ ├── en_US.json
│ └── de_DE.json
└── icon.png
user:// is Godot's per-user data folder. From the title screen, use Mods → Publish → Open local mods folder to open the correct location; on a standard Windows installation it is normally %APPDATA%\Godot\app_userdata\2D Tower\mods\. Development builds also discover packs in res://mods/. The game discovers only direct subfolders of these directories that contain manifest.json.
The example pack at examples/mods/records/ is a working reference. To use it locally, copy its whole folder to user://mods/records/; examples are not discovered automatically in release builds.
Manifest
manifest.json is at the root of the pack folder. Paths in the manifest are relative to that folder and may not escape it.
{
"pack_id": "my_record_store",
"version": "1.0.0",
"enabled": true,
"dependencies": ["base"],
"rooms": ["rooms/record_store.json"],
"translations": {
"en_US": "i18n/en_US.json",
"de_DE": "i18n/de_DE.json"
}
}
- pack_id is the pack's permanent identifier. It must start with a lowercase letter and otherwise use only lowercase letters, numbers, periods, underscores and hyphens. Keep it stable after publishing because saves refer to it.
- version identifies the compatible pack revision saved with games. Use a new version when a change would make old saves incompatible.
- enabled is optional and sets the initial state for a local pack. The Mods window stores the player's final selection in
user://mods.cfg. - dependencies lists required pack IDs. Most packs depend on
base. - rooms is an ordered list of room-definition JSON files.
- translations is optional. Each key is a locale and each value is a JSON translation file.
Pack folders are scanned in a stable order. Duplicate IDs are rejected; a user pack cannot replace a shipped pack.
Room definitions
Every room JSON file inherits a registered built-in room. The file name supplies the room's local ID unless it has an explicit id. For example, rooms/record_store.json in the my_record_store pack becomes my_record_store:room:record_store. Moving the file to another subfolder does not change that ID.
{
"extends": "base:room:store",
"occupancy_mode": "immediate",
"overrides": {
"display_name": "Record Store",
"description": "A specialist shop selling vinyl records.",
"width": 24,
"height": 1,
"entrance_offset": [6, 0],
"construction_cost": 125000,
"maintenance_cost": 100,
"worker_count": 2
},
"icon": "icon.png",
"visual": {
"texture": "textures/records.png",
"region": [0, 0, 768, 258]
}
}
extends must name an existing room. The loader makes an independent copy of that parent, so a mod never changes the original room. The supported general overrides are the display name and description, category and palette order, size and entrance, construction/demolition/maintenance costs, worker count, visit duration and custom-entrance setting. Values have to use the required data type; dimensions, coordinates and texture regions are integers.
Depending on the inherited runtime, a room may also use supported profiles such as commercial, residential, stock, garbage, demand and evaluation. Unsupported fields or profiles cause validation to fail rather than being silently ignored. The title-screen templates for Store, Restaurant, Residential and Office create valid starting packs for their respective parent rooms.
Artwork and translations
icon is a PNG path inside the pack. A custom visual uses a texture and region in the form [x, y, width, height]. The selected region contains two equal-height rows: the open appearance first and the closed appearance second. Without a custom visual, the room keeps its parent's artwork, footprint and appearance definitions.
Optional appearances entries define stable cosmetic IDs and their zero-based open-row sprite frame. A custom texture clears inherited appearances unless the mod provides its own entries. Translation files supply localized text; a short appearance display_name_key is scoped automatically to that room's ID.
Enable, publish and save
Open Mods on the title screen to enable or disable local packs. Restart the game after installing, removing, enabling, disabling or editing a pack because the content catalog is built at startup.
Steam Workshop packs use the same layout: manifest.json sits at the root of the uploaded folder. Workshop installations stay in Steam's managed directory, not in user://mods. New subscriptions start disabled; enable them in Mods and restart. The Publish tab can create a template, validate a selected pack folder and publish it privately. Its Workshop sidecar file is stored beside the pack folder; keep it to update the same Workshop item later.
Saves record the enabled pack IDs, versions and Workshop IDs. To open a save, its required packs must be installed, enabled and at matching versions. The game reports missing, disabled and version-mismatched packs instead of silently substituting different content.