This is the guide that ships inside the product, word for word: the file INSTALL.md in your archive. English is the reference, so that what you read here is exactly what you receive. Read this guide in French
1. Tools (about 5 minutes the first time)
- Install Rokit (<https://github.com/rojo-rbx/rokit>), then in the folder:
rokit install. It fetches Rojo, Lune, StyLua, Selene, luau-lsp and uv at the uv synccreates the Python environment the tools use (.venv) fromuv.lock(Python 3.14). A first run downloads the packages: NOT MEASURED.- Check the package on your machine:
bash tools/check.sh. It formats, lints, type-checks, runs every test suite and the balance simulations and builds
versions in rokit.toml. A first run downloads six programs: NOT MEASURED.
the place; it should end with GATE GREEN (full). bash tools/check.sh --fast skips the simulations and the place build. Both are timed in the package's CHANGELOG entry for this version (the figures come from a run of the gate on a marked copy of this very package).
2. Make it yours
Copy sale/project.template.json to project.json (at the folder's root) and edit it: put your Roblox user id in creatorUserId (the number in your profile's address), or a group's in creatorGroupId if the experience belongs to a group; the universe and place ids come in step 8 (the Creator Dashboard shows them once you have created the experience). keyFile is the path of the file that holds your Open Cloud API key (step 4). Nothing else in the package names an owner.
3. Play it now, with nothing drawn from art
bash tools/build_place.sh writes Wayfold.rbxl (Rojo builds it from src/ and default.project.json); open it in Roblox Studio and press Play. The table, the tiles and the enemies are drawn as nothing or as plain shapes (an asset id of 0 draws nothing), the HUD, the draft, the waves, the charter and the settings work. A person has to press Play: NOT MEASURED.
4. An Open Cloud API key
Create one at the Creator Dashboard (Open Cloud > API Keys) with the permissions to create assets (Assets: read, write) for your account or group. Put the key, alone, in a text file outside the package (for example ~/.roblox_key), and either set the environment variable ROBLOX_OPEN_CLOUD_KEY to the key, or write that file's path in keyFile of project.json, or pass --key-file FILE to any upload tool. Every tool takes the key from tools/project.py and nowhere else; none prints it or copies it.
5. Make the art and upload it (the long step)
The models and textures are made by Blender scripts (Blender 5.2; the commands are blender -b --factory-startup --python blender/scripts/<name>.py, with Blender's own executable on your path or written in full). Each script writes its files under blender/out/ and its entries in blender/manifest.json. The developer's times, measured on his machine, are in the second column; the others are NOT MEASURED.
| Script | What it makes | Time |
|---|---|---|
tiles.py, tiles_b.py | the terrain tiles (nine kinds, 18 models with their variants and road pieces), baked into the atlases TilesA and TilesB | tiles.py about 30 s |
keep.py | the Keep and the Gate (LandmarksA) | NOT MEASURED |
room.py, table.py | the room and the table the board stands on, and its props (RoomA, TableA) | NOT MEASURED |
enemy.py, beasts.py, warden.py | the nine enemies, in three atlases (WalkersA, BeastsA, WardenA) | NOT MEASURED |
tower.py | the ten towers' models (TowersT1, TowersT2) | NOT MEASURED |
soldier.py | the Picket's soldiers (SoldiersA) | NOT MEASURED |
hero.py | the hero (HeroesA): a skinned mesh with 23 bones, an idle, a walk and a run | about 3 minutes |
fx.py, flow.py, dust.py, impacts.py, shots.py, shadow.py | the marks, the road's chevron, the dust flipbook, the impacts, the shots, a flyer's shadow | seconds to 1 minute each |
ui.py, glyphs.py | the interface atlases (UiA, UiB, UiC) and the pad and key glyphs (UiG) | ui.py about 1 minute |
Then upload, from the package's folder: uv run python tools/upload_assets.py --dry-run lists what would go up; uv run python tools/upload_assets.py uploads every asset of blender/manifest.json that has no id yet, and records the ids in blender/uploaded.json on your machine. Roblox checks each upload: upload in groups of about fifteen (--only Name1,Name2) and run uv run python tools/upload_assets.py --status before the next group; a state that is not Approved is counted. A model and its texture maps go up together (a re-bake can move the UV islands: --reupload Name1,Name2 uploads them again).
The sounds: uv run python tools/upload_audio.py --all uploads every sound of the game from assets/audio/ (the names are in assets/audio/names.json), then uv run python tools/upload_audio.py --status until none is pending. To make them again, tools/synth_sounds.py, tools/synth_foley.py and tools/synth_music.py write the files (a few seconds to 10 s each, measured).
Last, uv run python tools/setup_ids.py writes every id into src/shared/Data/Ids.luau (the one file that names your assets) and uv run python tools/gen_asset_meta.py writes src/shared/Data/AssetMeta.luau. The time of the whole of step 5 depends on Roblox's moderation queue and on your connection: NOT MEASURED.
6. Build the models in Studio
The uploaded models become the place's ReplicatedStorage.Assets: open the place of step 3 in Studio and run in the command bar require(game.ServerStorage.Tools.AssetBuilder).build() (it loads every model, restores each piece's size and place from the manifest and dresses a baked piece with its atlas's maps). Then save ReplicatedStorage.Assets as assets/Assets.rbxm (right-click > Save to File) and rebuild the place with bash tools/build_place.sh. The developer does this step with automation that the package does not carry; by hand it is NOT MEASURED. tests/packs checks that a built model's surface appearances have their texture packs; if you build the models yourself, run the gate after the step to see what it says.
7. Products and passes (optional)
The game sells nothing. When you create a developer product or a game pass for your experience, write its id into Ids.products through tools/setup_ids.py (or by hand in Ids.luau) and read it with Ids.product("name"); an id of 0 hides the item.
8. Publish
Create the experience at the Creator Dashboard, write its universe and place ids in project.json, and choose the place's maximum players in Studio's Game Settings if you want fewer (every player who joins has a table and a run of their own, so a server holds as many runs as it has players; a party of up to 4 forms by invitation, and how a Roblox server behaves with 50 runs at once is NOT MEASURED). Publish from Studio, or with uv run python tools/publish.py (it needs the same Open Cloud key and permission to save a place version; read the tool's own text first).
9. Tuning the balance
Every tuning number of the game is in src/shared/Data/Balance.luau; CONFIG.md says what each block means and which other file holds what. After a change, bash tools/check.sh --fast, and lune run tests/sim_bands plays the real rules from fixed seeds to show whether the expert bot still wins in the bands the developer chose.
If a step fails
- The gate fails on a fresh package: read the first red line; every suite prints its own name. A gate that was green on the developer's marked copy of this
- An upload is refused or stays pending: Roblox's moderation or permissions.
--statusprints the state of each; a rejected asset is re-made with its no Open Cloud API keyorno creator: step 2 and step 4.- The game plays but nothing is drawn: the ids are still 0. Step 5 ends with
tools/setup_ids.py.
package and is red on yours is a bug of the package: tell the seller, with the line.
script and uploaded again with --reupload NAME.