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 synccreates the Python environment the tools use (.venv) fromuv.lock(Python 3.14, numpy, scipy, Pillow, soundfile, requests).- Check the package on your machine:
bash tools/check.sh. It formats, lints, type-checks, runs every test suite and the balance simulations
uv at the versions in rokit.toml. 0.1 s when the tools are already there; the first run downloads six programs: NOT MEASURED.
0.4 s with the packages already downloaded; a first run downloads them: NOT MEASURED.
(the five of them take most of the time: bash tools/check.sh --fast skips them and the place build) and builds the place; it should end with GATE GREEN (full). 17 minutes 22 seconds.
2. Make it yours
Edit project.json: 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. Leave universe and place at 0 until step 8.
Then write the Daily Show's secret, a value only your servers know (the seed of each night's show is mixed with it): uv run python tools/setup_ids.py --secret writes src/server/DailySecret.luau. Keep that file out of any public repository. Left empty, the game still runs but anyone who reads the source can compute a night's show, and the server says so once when it starts.
3. Play it now, with nothing drawn from art (about 2 minutes)
The package's src/shared/Data/Ids.luau is blank, so every asset of yours reads 0 and is drawn as nothing; there is no store to hide (the game sells nothing). That is enough to build, test and change the game before you make anything.
bash tools/build_place.shwritesCutstring.rbxl(1.0 MB). 0.14 s.- Open it in Roblox Studio and press Play (Home tab, "Play"). You arrive in a plain dressing room (a floor and eight brass slabs where the stations will stand, in front of a dark house); the lift's notice stands at the screen's foot with plain paper and brass boxes where the art will be, and a run starts and ends: the stage has no sets and no puppets yet, the cards are plain paper, the words are all there in English and French. Studio's Output holds one warning for each model not built yet ("a plain floor stands in until you build it", "no model Guard") and nothing else.
4. An Open Cloud API key
The upload and publish tools talk to Roblox with your own API key. Create one at <https://create.roblox.com/dashboard/credentials> ("Create API Key"): permissions Assets (read and write) with your account or group as the owner; add Universe Places (write) and Luau Execution Sessions (write) only if you will use tools/publish.py and tools/cloud_run.py. Give the key to the tools with the environment variable ROBLOX_OPEN_CLOUD_KEY (in PowerShell: $env:ROBLOX_OPEN_CLOUD_KEY = "<the key>"), or keep it in a file outside the folder and pass --key-file <file> (or put its path in project.json as keyFile). The tools never print it, and it is never written into the project: keep it out of any repository you make of the package. An upload goes to the creator in project.json (creatorUserId, or creatorGroupId), or --creator user:<id> / --creator group:<id>.
5. Make the art and upload it (the long step)
Every model, texture, atlas, flipbook and glyph is made by a script in blender/scripts (Blender 5.2 LTS, run without a window) or in tools/, uploaded to your account by tools/upload_assets.py (its record is blender/uploaded.json) and the sounds by tools/upload_audio.py (assets/ audio_uploaded.json). Then uv run python tools/setup_ids.py writes the ids into src/shared/Data/Ids.luau, where the game reads them by name (the generated data modules ask Ids for each asset by name, so they need no change after an upload).
With BLENDER the path of your Blender executable (the commands are the ones the developer used; a script that takes names makes only those). The textures' CC0 library comes first: uv run python tools/fetch_textures.py (its sources and licences are in THIRD_PARTY.md).
| Part | Commands, in order |
|---|---|
| The surfaces | uv run python tools/fetch_textures.py, uv run python tools/material_variants.py build, upload blender/manifest_textures.json (below), then uv run python tools/material_variants.py gen |
| Models: the stage, the sets, the house, the dressing room, the puppets and enemies, the props | "$BLENDER" -b --factory-startup --python blender/scripts/<script>.py for each of stage_blockout, stage_kit, stage_curtain, set_act1, set_act1_cloud, set_act2, house, dressing_room, bouquet, hp_plaque, puppet_guard, puppet_trickster, puppet_mender and each enemy_* script, then uv run python tools/check_texture_palette.py, upload the maps (uv run python tools/upload_assets.py --manifest blender/manifest_textures.json) and the models (uv run python tools/upload_assets.py) |
| The interface: cards, HUD, props, scenes, loading picture | "$BLENDER" -b --factory-startup --python blender/scripts/ui_art.py, ui_objects.py, card_illustrations.py, card_illustrations.py -- --portraits, card_illustrations.py -- --demos, loading_curtain.py; then uv run python tools/make_ui_atlas.py build and upload blender/manifest_textures.json |
| The pad's glyphs | "$BLENDER" -b --factory-startup --python blender/scripts/ui_glyphs.py, uv run python tools/make_glyphs.py build, upload uv run python tools/upload_assets.py --manifest blender/manifest_glyphs.json |
| The effects | "$BLENDER" -b --factory-startup --python blender/scripts/fx_flipbooks.py, uv run python tools/make_fx_textures.py build, upload blender/manifest_textures.json |
| The game's own sounds | uv run python tools/make_sounds.py (writes build/sounds/*.wav; the foley's recipes are tools/foley.py), then uv run python tools/upload_audio.py NAME=build/sounds/NAME.wav ... for each |
| The ids | uv run python tools/setup_ids.py |
uv run python tools/upload_assets.py skips what is already uploaded (the same file hash), so you can stop and go on; an asset still in Roblox's moderation reads its state with uv run python tools/upload_assets.py --status <Name>.
NOT MEASURED and NOT RUN as one session on a machine other than the developer's: the developer made this art over weeks, script by script, and did not time a rebuild of all of it. The uploads are limited by Roblox (moderation takes minutes per batch). The one script timed, hp_plaque.py (a small model), took 16.6 s headless on the developer's machine; the baked sets, the stage kit and the puppets take minutes each: NOT MEASURED.
6. Build the models in Studio
Uploaded meshes become the game's models in Studio (they are restored to their exact sizes, rigged and dressed with the materials). Open Cutstring.rbxl (rebuild it after step 5: bash tools/build_place.sh), then in Studio's command bar:
require(game.ServerStorage.Tools.AssetBuilder).build()
It reports one line per model (ok, or why not: a model whose id is still 0 says to upload it). Right-click ReplicatedStorage.Assets in the Explorer, "Save to File...", and save it over assets/Assets.rbxm; rebuild the place. The materials come from assets/materials/*.model.json, which tools/material_variants.py gen wrote in step 5. Then look at the stage in Studio before you publish: a published game draws a material's maps only from its texture pack, and Studio makes the pack when it draws the material. NOT MEASURED, and NOT RUN on a creator's account other than the developer's.
7. Products and passes (optional)
The game sells nothing and has no store. If you add an offer, put its developer product or pass id in sale/products.json under a key you list in tools/setup_ids.py's PRODUCTS and read it with Ids.product(key): a key at 0 is "not for sale" and the code must not show it.
8. Publish
Create an experience in the Creator Hub, put its universe and place ids in project.json, open the place in Studio and use File, "Publish to Roblox" (or tools/publish.py if you keep the project in git and want the tested release path it documents). Set the experience's supported languages to English and French and turn Automatic Text Capture and translated content off (the game translates itself, from src/shared/Strings.csv; the texts of your store page are yours to write, in both languages).
9. Tuning the balance
Every number that decides how hard and how generous the game is lives in src/shared/Balance.luau: the fight's energy and draw, the applause, the turn timer, the map's size, the rewards' gold and odds, the prop room's prices, the Critics' levels, the Daily Show's score, the party sizes' scaling of an enemy's HP and damage, a run's timers, healing and starting HP, and the bands the balance simulations hold the game to. The content (each card's effects and cost in src/shared/Data/Cards.luau, each enemy's HP, moves and damage in Data/Enemies.luau, the props' and tricks' effects) stays in its data modules.
Change a number, then run the simulations: lune run tests/run_sim (a whole run, by party size and level), lune run tests/combat_sim (each encounter), lune run tests/hook_sim, lune run tests/engine_sim, lune run tests/builds_sim, or all of them with bash tools/check.sh; each takes minutes and prints what it measured and the band it failed. lune run tools/balance_bench (see its header) tries a change without touching the files. A band is a verdict you may move on purpose (it is in Balance.BANDS), never silently.
If a step fails
Send the conversation on the resource's page the step's number and its output (never a key). Common causes: a tool at the wrong version (rokit install again), the key missing a permission (the tool says which request failed), an asset still in moderation.
Support: Botera Studio, on Discord (https://discord.gg/enaYMavQbW).