Your First Defold Steam Desktop Collection and Save Audit in One Evening - 2026 Beginner Pipeline
You bundled Defold for Windows. The editor run was clean. Steam players install the demo, reach the first checkpoint, quit, relaunch—and progress is gone. You used sys.save in the tutorial sense, but the packaged app wrote to a different root than you assumed, or your bootstrap collection was not the one Steam loads first.
May–October 2026 is when HTML5-first and 2D teams—many on Defold beside GDevelop and GameMaker—add Steam desktop demos for Next Fest. This Tutorials & Beginner-First pipeline is not a full Steamworks depot guide (see playtest branch evening); it is the Defold-specific collection and save audit you run once per build_id before upload.
Pair with BUILD_RECEIPT, Wednesday demo smoke, and HTML5-first storefront analysis.
Who this is for and what you get
| Audience | You will be able to… |
|---|---|
| First-time Defold Steam exporter | Document collections and save roots before depot upload |
| Solo dev | Stop trusting editor-only save tests |
| Producer | Require defold_steam_audit_receipt_v1.json before branch promotion |
Time: one evening (3–4 hours first bundle; 50–70 minutes on repeat).
Prerequisites: Defold project that runs in editor, Desktop platform added, Steamworks app with depot planned.
Why this matters now (May 2026)
- HTML5 → Steam path — Defold ships web and mobile first; desktop bundle layout surprises teams at fest week.
- Collection bootstrap bugs — Wrong
game.projectmain collection or proxy load order shows only in packaged builds. sys.saveroot drift — Save file location differs between editor, dev app, and Steam install.- Fest smoke culture — Wednesday demo smoke needs a binary that boots and saves.
- Cross-engine expectations — Players compare your demo to Construct and GameMaker discipline; evidence culture transfers.
Direct answer: Map collections → audit save roots → bundle desktop → run gates D1–D5 → write receipt → upload.
What you will have after one evening
collection_map_v1.jsonlisting every collection and bootstrap rolesave_root_map_v1.jsonwith slot keys and OS paths verified on standaloneexport/DefoldSteam/bundle folder ready for SteamPipedefold_steam_audit_receipt_v1.json- Main-menu screenshot from packaged app, not editor
- Visible
build_labelin-game matching receipt
Evening timeline
| Block | Minutes | Output |
|---|---|---|
| 1 — Collection map | 40 | collection_map_v1.json |
| 2 — Save root audit | 45 | save_root_map_v1.json, D2 pass |
| 3 — game.project + bundle | 45 | Desktop bundle, D3 layout |
| 4 — Boot + round-trip | 60 | D4–D5 golden path + save |
| 5 — Receipt + evidence | 30 | JSON in release-evidence/defold/ |
Mental model — editor vs packaged desktop
| Surface | What it proves |
|---|---|
| Editor Play | Logic rough cut |
| Project → Bundle → Desktop | What Steam players receive |
| Steam installed build | Depot + branch + runtime |
Tonight ends at packaged desktop on a PC without Defold editor (gate D3). Installed Steam smoke is the next session.
Step 1 — Collection map (Gate D1)
Defold games are collections of game objects, not monolithic scenes. Fest bugs often start with wrong collection loaded first.
Create collection_map_v1.json:
{
"schema": "collection_map_v1",
"project_version": "0.3.0-fest-audit",
"main_collection": "/main/main.collection",
"bootstrap": [
{ "collection": "/main/main.collection", "role": "retail_entry", "proxy_loads": ["/levels/level1.collectionc"] }
],
"excluded_from_retail": ["/debug/debug_overlay.collection"],
"factories": [
{ "id": "enemy_factory", "collection": "/entities/enemy.go" }
]
}
D1 pass checklist:
- [ ]
game.projectmain collection matchesmain_collectionin JSON - [ ] No debug collection in retail bootstrap path
- [ ] Every
collectionproxytarget listed with purpose - [ ] Loading screen collection documented if used
collectionproxy discipline
| Pattern | Fest demo rule |
|---|---|
| Load gameplay via proxy | Document load order in map |
| Unload previous world | Log in save_root_map notes if saves tied to proxy |
| Async load without UI block | Fail D4 if player can input during half-load |
Outbound: Defold collection manual (verify against your editor version).
Lua module pattern for saves (beginner-friendly)
Wrap raw sys.save behind one module save_service.lua:
local M = {}
local KEY = "/demo_save_v1"
local VERSION = 1
function M.save_state(state)
state._version = VERSION
local ok = sys.save(KEY, state)
return ok
end
function M.load_state()
local state = sys.load(KEY)
if not state or state._version ~= VERSION then
return nil
end
return state
end
return M
Why: One place to bump VERSION, log failures, and ban debug fields from persisted tables. Gate D2 reviews only this module’s contract.
Step 2 — Save root audit (Gate D2)
Defold persistence usually flows through sys.save / sys.load or wrapped modules.
Document save_root_map_v1.json:
{
"schema": "save_root_map_v1",
"slots": [
{
"slot_id": "demo_progress",
"api": "sys.save",
"key": "/demo_save_v1",
"verified_path_note": "See packaged app log — typically under app support directory",
"forbidden": ["hardcoded absolute paths", "editor-only test keys"]
}
],
"save_format_version": 1,
"faq_alignment": "local progress only; no Steam Cloud in demo"
}
D2 test script (packaged app only):
- Delete known save file if exists (document path after first run).
- Launch packaged app; reach checkpoint.
- Confirm
sys.savereturns without error (log in script). - Quit fully.
- Relaunch; confirm load restores checkpoint.
- Log actual path from
print(sys.get_save_file(key, path))in development build only—remove noisy prints before retail.
| Symptom | Likely cause |
|---|---|
| Save works in editor, not bundle | Testing editor path, not sys.save |
| Load always fresh | Wrong key string between save/load |
| Crash on save | Non-serializable table in saved state |
Align FAQ save claims with map.
Save table hygiene
| Rule | Why |
|---|---|
| Only serializable Lua tables | Functions userdata break save |
| Version field inside save blob | Enables migration |
| Small payload for demo | Faster IO on HDD laptops |
Cross-read GDevelop save-path challenge for parallel HTML5-first discipline.
Factories, atlases, and included resources (D1 extension)
Fest demos still fail when assets are missing from bundled collections:
| Asset type | Audit row in collection_map |
|---|---|
| Atlas / tile source | Linked from every sprite using it |
| Factory prototype | enemy_factory points to valid .go |
| Sounds | Referenced paths exist in bundle log |
| Fonts | BMFont / TTF included |
Run Project → Build report (or bundle log) and attach warnings to gate1_pass.log. Pink/missing textures in packaged app are D3 fails, not art polish issues.
Input bindings before bundle
| Check | Pass |
|---|---|
| Gamepad mapped for advertised support | Yes |
| ESC opens pause or quit path documented | Yes |
| Keyboard defaults work on AZERTY spot-check | Optional note in receipt |
Deck testing is optional until store claims Deck—honesty beats checkbox features.
Step 3 — game.project and desktop bundle (Gate D3)
Open game.project and record in game_project_audit.md:
| Field | Fest demo value |
|---|---|
[project] title |
Matches store demo name |
bootstrap main collection |
Matches D1 map |
graphics / display profiles |
Fixed size for pixel art if needed |
native_extension |
Only extensions you ship |
steam / platform IDs |
Document if Steamworks extension enabled |
Bundle steps (conceptual):
- Project → Bundle → Desktop → Windows x86_64 (or your target).
- Output to clean folder
export/DefoldSteam/. - Confirm
.exeor launcher present per Defold version output layout. - Double-click run without editor open.
D3 pass:
- [ ] App launches within 90s cold boot
- [ ]
build_labelvisible on title (add GUI text bound tosys.get_config_info) - [ ] No missing
.collectioncerrors in log - [ ] Working directory writable for saves
Zip contents for SteamPipe per depot discipline—not an extra parent folder named export.
Step 4 — Golden path boot (Gate D4)
Write five steps in demo-golden-path.md:
- Launch to title
- Start demo run
- Reach first checkpoint (flag variable)
- Trigger save (autosave or interact)
- Observe HUD readable at 1080p
Run 60 seconds of gameplay after first input—same vocabulary as Wednesday smoke.
D4 pass: No soft-lock; first collection proxy completes.
Step 5 — Save round-trip and quit (Gate D5)
After D4, execute save round-trip twice:
| Attempt | Pass |
|---|---|
| 1 | Quit to OS; relaunch; checkpoint remains |
| 2 | Repeat on second Windows user or clean VM if available |
D5 fail blocks upload—even if D4 felt fine.
Debug and console discipline
Disable debug keys for retail demo per developer console opinion. Defold debug scripts should not ship in fest bundle profile.
defold_steam_audit_receipt_v1.json
{
"schema": "defold_steam_audit_receipt_v1",
"build_label": "df-nextfest-2026-05-24-rc1",
"defold_version": "1.10.0",
"platform": "x86_64-win32",
"audited_at_utc": "2026-05-24T18:00:00Z",
"gates": {
"D1_collection_map": "pass",
"D2_save_root": "pass",
"D3_bundle_layout": "pass",
"D4_golden_boot": "pass",
"D5_save_roundtrip": "pass"
},
"main_collection": "/main/main.collection",
"save_format_version": 1,
"paired_build_receipt": "release-evidence/05-operations/receipts/df-nextfest-2026-05-24-rc1.json",
"notes": "Win11; no Steamworks extension yet"
}
Archive under release-evidence/defold/. Copy build_label into BUILD_RECEIPT.
After audit — Steam upload handoff
- Upload bundle to depot root.
- Capture Steam build id in BUILD_RECEIPT.
- Run Wednesday demo smoke on installed build.
- Run metadata diff before promotion.
Packaged audit does not replace installed smoke.
Cross-engine freeze family
| Engine | Article | Primary risk |
|---|---|---|
| Construct | Sheet freeze | Event order |
| GameMaker | Export sanity | Texture pages |
| GDevelop | Save-path challenge | Storage API |
| Defold | This pipeline | Collections + sys.save root |
Use one evidence taxonomy—do not fork folders per engine brand.
HTML5 itch + Steam dual SKU
If you ship itch HTML5 and Steam desktop:
| SKU | Audit focus |
|---|---|
| itch | Browser storage row in save map |
| Steam | Packaged sys.save path row |
See dual-SKU economics. Re-run all gates when switching platform target.
Native extensions and Steamworks
If you add Steamworks extension later:
| Check | Gate |
|---|---|
| Achievements match demo scope | D1 FAQ alignment |
| Cloud off unless promised | D2 map |
| Overlay does not block first save | D5 |
Optional D6 row in receipt when extension enabled.
Save migration mini-ladder (when demo scope changes)
If you add a floor mid-fest:
save_format_version |
Action |
|---|---|
| 1 | Baseline fest demo |
| 2 | New field only—migrate or wipe with logged message |
Never silently read v1 blobs with v2 schema—players call it corruption. Pattern aligns with Construct save migration.
Performance smoke on packaged build (optional D4b)
| Signal | Pass heuristic |
|---|---|
| Stable 60 on golden path laptop | No sustained <45 fps |
| Memory stable 15 min | No climb in Task Manager |
Fest demos need stable more than max—log “D4b optional pass” in receipt notes.
Playtest branch before public fest
Upload audited bundle to friends-and-family playtest branch before fest branch. Receipt proves folder sanity; playtest proves install path.
Distributed handoff
When Asia-EU handoff bundles overnight:
- EU morning verifies
collection_maphash unchanged - Asia logs Defold editor version in BUILD_RECEIPT
- Never promote without D5 on installed build
Incident response when saves fail live
| Hour | Action |
|---|---|
| 0 | Pause ads (fest cap) |
| 1 | Communicate wipe policy if unavoidable |
| 2 | Hotfix + bump save_format_version |
| 3 | Re-run D2–D5; new receipt |
| 4 | Demo patch notes if player-visible |
Operating review hook
Four-Friday operating reviews Block 3:
- Audits filed per promoted
build_id - D2 vs D5 failure ratio
- Qualitative refund tags “lost save”
Month-one adoption ladder
| Week | Goal |
|---|---|
| 1 | First receipt + maps committed |
| 2 | Second machine D5 |
| 3 | Playtest branch upload |
| 4 | Installed Wednesday smoke habit |
Worked example (composite solo dev)
| Hour | Action | Result |
|---|---|---|
| 0 | D1 map — found debug collection in bootstrap | Removed from retail path |
| 1 | D2 — save key typo demo_save_v1 vs demo_save_v2 |
Fixed |
| 2 | Bundle — missing proxy unload | Fixed load hang |
| 3 | D4–D5 pass | Receipt filed |
| 4 | BUILD_RECEIPT + screenshot | Ready for SteamPipe tomorrow |
Lesson: Editor never loaded wrong proxy order; bundle did.
Common mistakes (seven)
- Auditing saves in editor only — D2 requires packaged app.
- Wrong main collection in game.project — D1 fail.
- Non-serializable save tables — D5 intermittent fail.
- Debug collection left in bootstrap — Players see dev UI.
- No
build_label— Support cannot correlate refunds. - Skipping installed smoke — Depot path differs from local bundle folder.
- Assuming web save equals desktop — Dual SKU needs two map rows.
Pro tips (six)
- Log save path once in dev bundle, strip prints for retail.
- Screenshot title screen with
build_labelevery audit. - Commit collection_map beside source—diff on fest week.
- Second machine test monthly.
- Pair with 18 playtest tools after smoke passes.
- Block fest marketing cap spend on D5 fail.
collectionproxy load order (advanced D1 table)
When your demo streams levels:
| Order | Collection | Load trigger | Save hook |
|---|---|---|---|
| 1 | /main/menu |
App start | None |
| 2 | /levels/run |
Proxy on “Start” | save_service on checkpoint |
| 3 | /ui/pause |
Parallel overlay | Must not reset run state |
Document unload: if proxy does not unload previous world, memory climbs and saves may reference destroyed instances—fail D4 if RAM doubles after three loads.
Beginner quick start (30 seconds)
Defold fest shipping is collections + saves + bundle, not “press export.” Tonight: list collections, test save on the built exe, file receipt. Steam upload waits until gates pass.
Treat this like learning Git for the first time: awkward for one evening, then automatic every promotion.
Second-week habits
- Re-run D2 only when save schema changes.
- Full D1–D5 on any
main_collectionchange. - Attach receipt path to Slack promotion template.
CI hook (optional)
test -f release-evidence/defold/defold_steam_audit_receipt_v1.json || exit 2
jq -e '.gates.D5_save_roundtrip == "pass"' release-evidence/defold/defold_steam_audit_receipt_v1.json || exit 3
Match validate-packet exit code style.
Partner packet crosswalk
Attach to partner ZIP 01_builds/:
collection_map_v1.jsonsave_root_map_v1.jsondefold_steam_audit_receipt_v1.json
Q3 diligence asks how saves work—maps answer without fake retention stats.
Non-repetition note (editorial)
First URL dedicated to Defold Steam collection + save audit; Lua scripting overview mentions Defold but does not cover fest export gates. Consumed Blog-Planner High #1 after May 23 refill—not escape hatch.
Key takeaways
- Collections and save roots are the Defold fest risk surface—not only “does it export.”
- Gates D1–D5: map, save audit, bundle, golden boot, round-trip.
defold_steam_audit_receipt_v1.jsonpairs with BUILD_RECEIPT and Wednesday smoke.- Packaged desktop test is mandatory; editor play is not proof.
game.projectmain collection must matchcollection_map_v1.json.- Dual itch/Steam SKUs need separate save map rows.
- Debug collections must stay out of retail bootstrap.
- Installed Steam smoke still required after this audit.
- Cross-engine teams share one evidence folder taxonomy.
- Non-serializable tables are the silent D5 killer.
Evidence folder layout
release-evidence/
defold/
collection_map_v1.json
save_root_map_v1.json
defold_steam_audit_receipt_v1.json
screenshots/
title_build_label.png
logs/
gate1_pass.log
gate3_bundle.log
Friday Block 5 spot-checks this folder monthly.
Promotion gate checklist (copy-paste)
[ ] defold_steam_audit_receipt_v1.json all gates pass
[ ] build_label matches BUILD_RECEIPT and in-game HUD
[ ] collection_map matches game.project main collection
[ ] Wednesday metadata diff GREEN
[ ] Wednesday demo smoke S4–S6 GREEN on installed build
[ ] FAQ save wording matches save_root_map
Refund dashboard crosswalk
When refund signals spike “progress lost,” verify:
| Question | Evidence |
|---|---|
Which build_label? |
Receipt + BUILD_RECEIPT |
| Did promotion precede D5? | Gate logs dated before branch |
| Cloud promised? | save_root_map FAQ row |
FAQ
We use DefoldKit or custom CI bundle—skip?
No—map collections and save paths regardless of bundle button.
Does this replace GDevelop seven-day challenge?
Parallel engine; run the audit matching your stack.
Steamworks extension day one?
Optional D6; start without SDK for first demo.
macOS depot too?
Re-run all gates; save paths differ.
How long per repeat audit?
Under 70 minutes when maps exist.
Does Defold use the same paths as GameMaker?
No—follow this map; cross-read GameMaker export sanity only for evidence culture, not file paths.
Steam Deck note (optional)
If your store page mentions Deck support, run D4–D5 once on Deck hardware after Windows pass—log in receipt notes. Defold projects still need a readable pause menu at 1280×800 even when a future Unity glyph article covers Input System tables for other stacks.
Snippet-friendly answers
How do I export Defold to Steam?
Map collections, audit sys.save on a packaged desktop bundle, file defold_steam_audit_receipt_v1.json, upload via SteamPipe, then run installed smoke before branch promotion.
Why does Defold save work in editor but not Steam?
Usually wrong save key, non-serializable state, or testing editor instead of bundled app.
What is a collection map?
A JSON list of which Defold collections boot, load via proxy, and stay out of retail builds.
Conclusion
Defold rewards fast iteration—and punishes unmapped collections on desktop.
Spend one evening on D1–D5. File the receipt. Upload only after saves survive a packaged quit.
If your team already runs evidence cycles, slot this audit in the light week before a heavy content push—collection truth is part of shipping, not a detour.
Bookmark the five gate names on a sticky note beside your monitor: D1 map, D2 save, D3 bundle, D4 boot, D5 round-trip. When a producer asks “can we promote tonight,” the answer is a file path in release-evidence/defold/, not a feeling about yesterday’s editor session.
Next reads: BUILD_RECEIPT pipeline, Wednesday demo smoke, GameMaker export sanity.