Repository navigation
1.16.0
Envs and targets
A build answers two questions, and fox only had room for one of them. The env said what a
build contained, and then quietly carried where it was published too: publish.steam and
publish.steamDemo sat side by side in the config, one naming a store and the other naming
a content. Shipping the same demo to a second store meant inventing a fake env for it.
This release splits the two apart.
env and target
| Axis | Setting | Values | Answers |
|---|---|---|---|
env |
bundle/env |
debug, demo, release |
what the build contains |
target |
bundle/target |
steam, itch |
where it is published, and which store plumbing it carries |
They cross freely. The same demo content ships to Steam with an app id, an overlay and a
Workshop, and to itch.io with none of them, without being two different demos.
A preset declares both, and fox picks one on platform + env + target:
custom_features="env:demo,target:itch"
export_path="export/demo/itch/windows/my-game.exe"Builds land under export/<env>/<target>/<platform>/: made once for what they contain, then
dressed for each store they go to.
fox switch and fox export ask for both
ββ β Faraday Corridors (corridors) v0.22.0
βββββ> DEMO on ITCH -> export/demo/itch/ (never exported)
? env
β― keep DEMO (no switch) -> export/demo/itch/ (last export 2026-09-05 11:37)
switch to DEBUG -> export/debug/steam/ (last export 2026-08-30 17:57)
switch to PROD -> export/release/steam/ (last export 2026-06-21 12:43)
? target
β― ITCH -> export/demo/itch/ (last export 2026-09-05 11:37)
STEAM -> export/demo/steam/ (last export 2026-09-04 22:14)The target prompt only appears when the env can actually reach more than one store, so a
game with a single destination never has to answer for it. Both chips are on the banner, and
the bake says so out loud:
project.godot [bundle] -> platform="macOS" env="demo" target="itch" (no Steam app_id)That last parenthesis is the point: a Steam app id is now resolved only for a Steam
target. An itch build that carried one would ask for a Steam client that is not there.
publish is keyed by store, then env
Credentials belong to the store; a build merely passes through it.
"publish": {
"steam": {
"login": "partner-login",
"envs": {
"release": {"appId": "1", "depots": {"11": "windows"}, "branch": ""},
"demo": {"appId": "2", "depots": {"21": "windows"}, "branch": "staging"},
"debug": {"appId": "1"}
}
},
"itch": {
"user": "someone",
"game": "some-game",
"envs": {"demo": {"channels": {"windows-demo": "windows"}}}
}
}Declaring an env under a store says this build belongs to that app, which is how a debug
build gets an app id and can exercise Steam features locally. Being publishable is the
stricter question, answered by the upload slots: an env with neither depots nor channels
is never offered by fox publish.
itch.io, through butler
fox publish itch demoThe payload gate is now shared by both stores: whatever sits in the export folder is read
back, its baked version and env are shown, and a mismatch with the repo still offers the
export that would fix it before anything is uploaded. Only the uploader differs, steamcmd on
one side and butler on the other. An itch channel name carrying windows, linux or osx
is what tells itch.io which platform an upload is for.
At runtime
G.ENV # 'debug' | 'demo' | 'release'
G.TARGET # 'steam' | 'itch'
G.isSteamTarget()A content question reads G.ENV. A store question reads G.TARGET, never G.ENV:
initializing the Steam SDK, showing a Workshop entry, opening the overlay. A game aimed
elsewhere can now skip the SDK entirely instead of calling into it and reading the failure
back, which is the difference between a clean boot and a wall of S_API FAIL.
Nothing to do on existing projects
A preset declaring env: alone keeps matching every target, bundle/target defaults to
steam when a project does not declare it, and the flat publish.steam / publish.steamDemo
shape is still read. A game that never had a second store behaves exactly as before.
Also
fox lswalks the Steam target's envs rather than the two flat keys, and derives its
content root from the export layout instead of a configured path- the Steamworks build description names the env it actually carries, for every env, instead
of a hardcoded demo suffix docs/exporting/envs-and-targets.mddocuments the two axes, the config shape and the
runtime API
changelog
No pull request was merged into this release: the work landed straight on main.
Full changelog: v1.14.3...v1.16.0