Godot 4.5 Threaded Loader vs Construct 3 Tick Groups for Floor Transitions - 2026
The player clears a room. The screen fades. For 400–900 ms nothing moves—or worse, input still fires while half the next floor exists. In May 2026 bug reports, that moment is the #1 roguelite fest-demo killer on both Godot 4.5 and Construct 3 ships, and the fixes sound nothing alike.
Godot teams reach for ResourceLoader.load_threaded_request and floor epochs. Construct teams reach for tick group order and layout transition discipline. Same player pain, different failure physics.
This Programming & Technical comparison is the cross-engine map the Construct save playbook and RNG tutorial forward-linked but did not yet publish. It is not another WASM memory ceiling essay and not a fourth Steam metadata checklist. Read the deep dives after you pick your lane: Godot threaded loader only, Construct event-sheet freeze challenge.
Who this is for and what you get
| Audience | Outcome |
|---|---|
| Engine picker | Decision matrix for floor-transition architecture |
| Godot programmer | What Construct teams mean by “group order” |
| Construct designer | What Godot teams mean by “epoch discard” |
| Producer | One receipt JSON both engines can attach to fest evidence |
Time: ~45 minutes to read; 90 minutes to implement first fixes in your engine.
Prerequisites: One playable floor loop; for Construct, RNG seed ledger; for Godot, Godot 4.5 project.
Why this matters now (H2 2026)
- Roguelite floor granularity — Rooms, not worlds; transitions happen every 60–120 seconds in fest demos. Hitch frequency beats hitch duration in refund psychology.
- Cross-engine teams — Artists prototype in Construct, programmers port spikes to Godot (or reverse). Mis-translated fixes cause double work.
- Construct NW.js + Godot Steam — Both target October 2026 Next Fest; both need proof artifacts beside BUILD_RECEIPT.
- Save semver coupling — Construct save migration and Godot
floor_indexkeys must agree with transition timing—loads and saves are one system. - Phaser third lane — Chunk streaming solves tile memory, not sheet order—triangulate instead of arguing engines on Twitter.
Direct answer: Godot removes main-thread load hitches with threaded requests + epoch guards; Construct removes logic-order and layout races with frozen tick groups + transition gates. You need both concepts if you maintain multi-engine ports.
The failure modes (same symptom, different root)
| Player symptom | Godot likely cause | Construct likely cause |
|---|---|---|
| Long freeze on door | load() on main thread |
Heavy On start of layout + sync spawn |
| Inputs work on black screen | Scene half-added | Layout not finished; groups still running |
| Wrong enemies after skip | Stale threaded completion | random() before RunRNG group |
| Crash after fast floor skip | Orphan nodes from old epoch | Duplicate global triggers |
| Fine in editor, bad in export | Web threading / missing preload | Browser vs NW.js layout difference |
| Replay diverges | Load order changed seed timing | Tick order changed between builds |
Concept mapping — epochs vs tick groups
| Idea | Godot 4.5 expression | Construct 3 expression |
|---|---|---|
| “This transition attempt” | floor_epoch integer |
transition_id global + layout name |
| Cancel stale work | Discard load status when epoch mismatch |
Disable groups until layout ready |
| Deterministic sim | Fixed _process poll order |
Frozen tick_group_order in ledger |
| Lookahead | Queue next floor during combat | Pre-create off-screen spawners (careful memory) |
| Progress UI | Aggregate load_threaded_get_status |
Fade + “Loading…” on UI group only |
| Proof artifact | floor_load_receipt_v1.json |
sheet_inventory + freeze receipt |
Epoch is time discipline for async work. Tick group order is time discipline for synchronous events. Porting teams that only copy Godot loaders into Construct without freezing groups still fail.
Godot lane — threaded loader summary (not a full duplicate)
Full code lives in Godot threaded ResourceLoader guide. Comparative essentials:
Coordinator checklist
- Increment
floor_epochon every portal trigger (including death restart). load_threaded_requestforPackedScenepaths—neverload()in transition_ready.- Poll statuses in
_process; cap concurrent requests (4–8). - Instantiate only when all required paths report loaded and epoch matches.
- Free previous floor root before adding new root (avoid double physics).
- Web export: run hosting smoke tests—threading presets differ from desktop.
Godot anti-patterns
| Anti-pattern | Why it fails fest QA |
|---|---|
preload() entire biome tree |
RAM spike + hitch on first use |
| Ignore stale completions | Enemies from floor N on floor N+1 |
Block in await chains without epoch |
Skip portal breaks await |
| Progress bar fake | Players still feel hitch |
Minimal epoch guard (reference)
func _on_portal_entered() -> void:
floor_epoch += 1
var ep := floor_epoch
_queue_floor_assets(next_floor_id, ep)
# poll until complete or ep != floor_epoch → abort
Construct lane — tick groups summary
Full week discipline lives in 7-day event-sheet order freeze. Comparative essentials:
Group order template
Document in rng_seed_ledger.json:
"tick_group_order": ["RunRNG", "WorldSim", "Combat", "UI", "FX"]
| Group | Floor transition role |
|---|---|
| RunRNG | Seed advance only here—never in FX |
| WorldSim | Layout start, door triggers |
| Combat | Spawners after layout ready flag |
| UI | Fade, input lock |
| FX | Particles last—no gameplay side effects |
Layout transition gate pattern
- On door clicked → set
transition_active = 1; disable Combat group. - Start fade (UI group).
- On fade complete →
Go to layoutnext floor. - On start of layout → reset spawners; set
layout_ready = 1; enable Combat. - Clear
transition_active.
Construct anti-pattern: Spawning enemies on Every tick during fade—reads as “game broke” in streams.
Construct vs browser refresh
Replay case study shows refresh ≠ layout change—but group order still must match ledger or replay diverges.
Side-by-side decision matrix
| Question | Prefer Godot threaded path | Prefer Construct tick-group path |
|---|---|---|
| Hitch is profiler load spike | Yes | — |
| Hitch is logic running mid-fade | — | Yes |
| Team strength | GDScript + scenes | Event sheets |
| Target | Steam desktop + optional web | itch HTML5 + NW.js |
| Content size | Large packed scenes | Many small layouts |
| Proof culture | floor_load_receipt |
sheet_freeze_receipt |
Hybrid studios: Prove each engine with its native pattern—do not paste GDScript structure into event sheets verbatim.
Proof table — comparative acceptance tests
| # | Test | Godot pass | Construct pass |
|---|---|---|---|
| 1 | 20 rapid floor skips | No orphan enemies | No duplicate spawns |
| 2 | Profiler main thread | No >100ms load spikes | No >100ms sync layout work |
| 3 | Epoch/ledger version | Receipt semver bumped | tick_group_order matches screenshot |
| 4 | Death restart mid-load | Loads abort cleanly | Layout reset clears globals |
| 5 | Fest demo laptop | 60 FPS combat between floors | Same |
| 6 | Save/load after floor 3 | floor_index correct |
Save semver + floor index |
| 7 | 10 min session | Memory stable | No layout leak |
| 8 | build_id in pause | Visible | Visible |
Run engine-specific columns—do not average scores across engines.
floor_transition_receipt_v1.json (cross-engine)
{
"receipt_type": "floor_transition",
"version": "1.0.0",
"engine": "godot_4.5 | construct_3",
"build_id": "fest-2026-05-22",
"godot": {
"threaded_loader": true,
"epoch_guard": true,
"max_concurrent_loads": 6
},
"construct": {
"tick_group_order_frozen": true,
"ledger_path": "rng_seed_ledger.json",
"layout_gate": true
},
"tests_passed": [1, 2, 3, 4, 5, 6, 7, 8],
"notes": ""
}
Store under release-evidence/floor-transition/ beside release evidence taxonomy.
Beginner path — pick one engine this week
If you use Godot
- Read threaded loader guide sections “Coordinator” and “Epoch”.
- Replace one
load()call in your portal flow. - Add
floor_epochglobal. - Run proof tests #1–#2.
If you use Construct
- Complete RNG seed ledger evening.
- Screenshot event sheet group order → paste into ledger.
- Add layout gate pattern above.
- Run proof tests #1 and #3.
Do not attempt both engines in one week unless you enjoy two half-fixed pipelines.
Developer path — porting and fest ops
Godot → Construct port checklist
| Godot concept | Construct translation |
|---|---|
floor_epoch |
transition_id + abort spawns when mismatch |
| Threaded load | Split layouts; reduce per-layout spawn cost |
Poll in _process |
Never—use layout gates instead |
| PackedScene cache | Object pooling on same layout |
Construct → Godot port checklist
| Construct concept | Godot translation |
|---|---|
| Tick group order | Node groups + explicit _process order doc |
| Layout fade | AnimationPlayer + input lock singleton |
| System random audit | Central RunRNG autoload |
| NW.js vs browser | Godot export presets per platform |
Fest branch promotion gate
Before promoting demo branch:
- [ ] Floor transition receipt tests 1–8 green
- [ ] Wednesday demo smoke golden path includes two floor changes
- [ ] Playtest tools forms include
build_id+floor_index - [ ] Save migration semver matches Construct playbook if applicable
Phaser third lane (when neither engine fits)
| Problem | Phaser pattern |
|---|---|
| Tilemap OOM | Chunk streaming playbook |
| Tab refocus | Same + visibility handlers |
| Floor transition | Chunk unload + chunk load epoch (parallel idea to Godot epoch) |
Compare concepts, do not merge codebases.
Debugging playbook — 30-minute triage
| Step | Godot | Construct |
|---|---|---|
| 1 | Profiler main thread during portal | Performance profiler + layout switch |
| 2 | Log floor_epoch on every complete |
Log layout_ready + group states |
| 3 | List active load_threaded paths |
Find Every tick spawns during fade |
| 4 | Kill lookahead queue | Disable groups until fade done |
| 5 | Re-run test #1 rapid skip | Same |
Tooling cross-links
- 16 Construct debugging tools — ledger, refresh protocol
- 5-day crash log challenge — attach floor transition logs
- itch HTML5 demo scope — browser SKU limits affect Construct more often
Store and marketing (floor transitions are player-facing)
Unreadable loading text is not this post—but pixel font pass matters if your loading UI uses micro type during transitions.
Trailers that cut on black frames between floors train wrong expectations—sync with trailer frame audit.
Telemetry you can log without inventing metrics
Fest teams do not need a analytics SaaS to debug transitions—log counts locally:
| Field | Godot | Construct |
|---|---|---|
floor_index |
int | int |
floor_epoch / transition_id |
int | int |
transition_ms |
wall time portal→playable | same |
aborted_loads |
epoch mismatches | layout skip during fade |
build_id |
string | string |
Export last 50 transitions in a JSONL next to crash logs for crash log challenge. Do not publish fabricated “saved 40% load time” percentages in store copy—partners spot fake perf claims.
Worked example — Godot hitch traced to stale epoch
Symptom: Skipping a portal quickly spawns mini-boss assets from previous floor.
Profiler: Threaded loads complete after player already left.
Fix: On portal enter, increment epoch; in poll handler, if ep != floor_epoch: return before instantiate().
Verification: Test #1 twenty skips—zero orphan bosses.
Time: ~40 minutes for solo programmer.
Worked example — Construct hitch traced to FX group
Symptom: Fade plays but damage numbers still tick.
Sheet audit: Combat runs before UI during layout change.
Fix: Reorder groups to template; move damage to Combat; lock Combat until layout_ready.
Verification: Ledger screenshot matches engine; Test #3 pass.
Time: ~25 minutes for designer + 10 minutes programmer confirm globals reset.
Memory vs hitch (do not conflate)
| Issue | Engine signal | Read instead |
|---|---|---|
| RAM climb over 30 min | Texture/layout leak | Phaser chunk / Godot web WASM |
| Single long frame | Main-thread load | This post Godot column |
| Stutter every door | Sync layout work | This post Construct column |
| Tab refocus crash | Browser lifecycle | Phaser tab-refocus playbook |
Teams that only optimize WASM while ignoring tick order still fail Construct demos; teams that only freeze sheets while synchronous load() remain in Godot still hitch.
AI-assisted code warning
LLMs love generating load() in _ready (Godot) and Every tick spawns (Construct). Human review must enforce epoch and group discipline—see ChatGPT + Claude build log for review culture, not engine specifics.
90-minute paired studio workshop (two engineers)
| Minute block | Godot owner | Construct owner |
|---|---|---|
| 0–15 | Demo hitch on video | Demo hitch on video |
| 15–30 | Show profiler spike | Show sheet order screenshot |
| 30–45 | Explain epoch | Explain layout gate |
| 45–60 | Draft receipt JSON | Draft receipt JSON |
| 60–90 | Cross-QA proof tests | Cross-QA proof tests |
Output: shared release-evidence/floor-transition/README.md linking both subfolders.
Release checklist — floor transitions before October fest
| Day | Godot team | Construct team |
|---|---|---|
| Mon | Profile one portal; list sync loads | Screenshot sheet order → ledger |
| Tue | Implement epoch + threaded queue | Add layout_ready gate |
| Wed | Run tests #1–#4 | Run tests #1, #3–#4 |
| Thu | Write floor_load notes in receipt |
Attach sheet freeze screenshot |
| Fri | Cross-review other engine’s column in this post | Same |
Publish build_id only when both sides agree test #5 passes on the same fest laptop if you ship dual SKUs (itch + Steam).
When to escalate to a deeper single-engine guide
| Signal | Escalate to |
|---|---|
| Godot web-only hitch | WASM memory playbook |
| Construct save lies after floor change | Save migration trend playbook |
| Need week-long sheet discipline | 7-day event-sheet freeze challenge |
| Godot code-heavy coordinator | Threaded ResourceLoader guide |
This comparison stays the routing page; implementation depth intentionally lives in those URLs so we do not duplicate five hundred lines of GDScript or event-sheet screenshots here.
Outbound authority
Key takeaways
- H2 2026 floor transitions are the roguelite bottleneck on Godot and Construct.
- Godot fix: threaded loads + floor epoch — see deep guide.
- Construct fix: tick group order + layout gates — see freeze challenge.
- Same symptom ≠ same root cause—use the failure mode table.
floor_transition_receipt_v1.jsonworks for both engines.- Pair with save semver and RNG ledger—not isolated performance tuning.
- Phaser adds chunk discipline as a third lane.
- Fest promotion needs rapid-skip test #1 on real hardware.
- This post is comparative programming, not WASM OOM or store metadata.
- Engine war is less useful than epoch vs group order vocabulary.
FAQ
Which engine is “better” for roguelites?
Neither—maturity of your team’s discipline matters more than logo.
Can I use threaded loading in Construct?
No native equivalent—reduce per-layout cost and gate groups.
Does epoch replace save migration semver?
No—pair with save migration playbook.
We only ship itch HTML5 Construct—skip NW.js?
Still run layout gates; refresh bugs differ from NW.js but group order still applies.
Godot web export hitches only in browser?
Check threading preset and WASM playbook—distinct from desktop threaded path.
How does this relate to event sheet freeze week?
Freeze week is Construct implementation; this article explains why beside Godot.
Should multiplayer roguelites use the same patterns?
Epoch and group order still help local sim; netcode adds authority layer—not covered here.
What about Unity Addressables?
Same epoch idea as Godot; compare mentally, implement per Unity docs—out of scope but analogous.
Conclusion
Players do not care which engine you chose—they care that the door feels instant and fair. Godot 4.5 earns that with threaded ResourceLoader work guarded by epochs. Construct 3 earns it with tick group order frozen in a ledger and layout transitions that never spawn combat mid-fade.
Use this comparison to translate fixes across teams, file one floor transition receipt, and drill proof test #1 (twenty rapid skips) before October 2026 fest traffic. Then dive the engine-specific guides linked above—implementation depth lives there on purpose.
Next reads: RNG seed ledger tutorial, Construct save migration, Godot threaded loader.