ProductsDocumentationHow we make thingsSupport
Join the Discord

Wayfold

The full guide

Everything needed to open the kit, make its art and make it yours, readable in full before you spend anything.

On this page
  1. 1. Tools (about 5 minutes the first time)
  2. 2. Make it yours
  3. 3. Play it now, with nothing drawn from art
  4. 4. An Open Cloud API key
  5. 5. Make the art and upload it (the long step)
  6. 6. Build the models in Studio
  7. 7. Products and passes (optional)
  8. 8. Publish
  9. 9. Tuning the balance
  10. If a step fails

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)

  1. 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
  2. versions in rokit.toml. A first run downloads six programs: NOT MEASURED.

  3. uv sync creates the Python environment the tools use (.venv) from uv.lock (Python 3.14). A first run downloads the packages: NOT MEASURED.
  4. 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
  5. 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.

ScriptWhat it makesTime
tiles.py, tiles_b.pythe terrain tiles (nine kinds, 18 models with their variants and road pieces), baked into the atlases TilesA and TilesBtiles.py about 30 s
keep.pythe Keep and the Gate (LandmarksA)NOT MEASURED
room.py, table.pythe room and the table the board stands on, and its props (RoomA, TableA)NOT MEASURED
enemy.py, beasts.py, warden.pythe nine enemies, in three atlases (WalkersA, BeastsA, WardenA)NOT MEASURED
tower.pythe ten towers' models (TowersT1, TowersT2)NOT MEASURED
soldier.pythe Picket's soldiers (SoldiersA)NOT MEASURED
hero.pythe hero (HeroesA): a skinned mesh with 23 bones, an idle, a walk and a runabout 3 minutes
fx.py, flow.py, dust.py, impacts.py, shots.py, shadow.pythe marks, the road's chevron, the dust flipbook, the impacts, the shots, a flyer's shadowseconds to 1 minute each
ui.py, glyphs.pythe 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
  • package and is red on yours is a bug of the package: tell the seller, with the line.

  • An upload is refused or stays pending: Roblox's moderation or permissions. --status prints the state of each; a rejected asset is re-made with its
  • script and uploaded again with --reupload NAME.

  • no Open Cloud API key or no 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.