SHIPPING A GAME IN 48 HOURS: MASKARADE POSTMORTEM
Shipping a Game in 48 Hours: Maskarade Postmortem
Maskarade shipped. It’s rough around the edges, some of those edges are load-bearing, but it exists and people played it. Here’s the full breakdown of what happened during those 48 hours at Global Game Jam 2026.
The Setup
Team of 3. Theme: “Mask.” Engine: Godot 4.6. I handled programming, one teammate did art and UI, the third wrote the narrative and designed levels. We’d worked together on university projects before, so communication wasn’t a problem. Scope was.
The pitch: a narrative detective game where masks reveal hidden emotions, and you interrogate suspects to find a killer in a society that claims crime no longer exists. Strong concept. Way too ambitious for 48 hours. We knew that going in and scoped down anyway — no combat, no procedural generation, just branching dialogue and clue-gathering. It was still too much.
Day 1: Hours 0-24
Hours 0-4: Brainstorming and scoping. We landed on the concept fast, but spent too long debating whether to include a deduction board. Cut it. Good decision.
Hours 4-10: I built the core dialogue system using the Dialogue Manager plugin and wired up a global state autoload to track clues, visited locations, and suspect states. Scene tree stayed flat — one root scene with child scenes swapped via SceneTree.change_scene_to_packed().
Hours 10-18: First playable loop. You could talk to two suspects, find clues, and reach an ending. The signal-based architecture paid off here — UI elements connected to state changes without hard references:
# ClueManager.gd (autoload)
signal clue_discovered(clue_id: String)
func discover_clue(clue_id: String) -> void:
if clue_id not in discovered_clues:
discovered_clues.append(clue_id)
clue_discovered.emit(clue_id)
Every UI panel, dialogue condition, and location unlock listened to signals from the autoloads. No spaghetti. This pattern held up through the entire jam.
Hours 18-24: Content pipeline. My narrative teammate was writing dialogue in Dialogue Manager’s editor while I wired up locations. Art was streaming in. Things felt good. Too good.
Day 2: Hours 24-48
Hours 24-30: Scope creep hit. We wanted a journal UI to show collected clues. “It’ll take an hour.” It took four. The layout broke when clue text was longer than expected, and we had to refactor the container to use VBoxContainer with dynamic sizing. Should have used a simple list from the start.
Hours 30-38: The accusation system. Players needed to pick a suspect and present evidence. I built it as a separate scene with a suspect lineup and drag-and-drop clue cards. At hour 35, we realized there was no “accuse no one” option — what if the player figured out the twist but had no valid suspect? Rushed that in as a dialogue option.
Hours 38-44: Polish and bug fixing. Audio went in late, which meant we never properly balanced dialogue timing with sound cues. Some scenes felt silent. Others had overlapping audio.
Hours 44-48: The web export disaster. We hadn’t tested the HTML5 build once. SharedArrayBuffer requirements, audio context restrictions, asset loading failures. Spent the last four hours fighting export settings and browser quirks. The game ran fine in the editor the whole time. Classic.
What Godot 4.6 Got Right
The scene and signal system is genuinely great for rapid prototyping. Autoloads as global state managers work well for jam-scale projects. GDScript’s typing improvements caught real bugs during development — func discover_clue(clue_id: String) saved me from passing a node reference instead of a string at one point.
The Dialogue Manager plugin deserves special mention. Writing branching dialogue in a visual editor while the programmer wires up conditions separately — that workflow is powerful for small teams.
What’s Still Rough
Web export is painful. The documentation exists but the actual experience of getting a Godot game running in a browser involves too much trial and error. For a jam where itch.io web builds are the primary distribution channel, this matters.
The editor’s performance with multiple scenes open degraded noticeably on my teammate’s laptop. We worked around it, but it shouldn’t be a factor.
What I’d Change
Test the export target from hour 1. Not hour 44. This is non-negotiable for any future jam.
Scope the content to 50% of what feels achievable. We scoped to 70% and still cut features. The accusation system works but feels rushed because it was.
Playtest with someone outside the team by hour 20. We were too close to the narrative to notice pacing issues. Some dialogue sequences dragged because we’d read them so many times they felt normal.
The Bigger Picture
Game jams are the fastest way to learn what actually matters in game development. Not architecture, not engine mastery — decision-making under pressure. When do you cut a feature? When is “good enough” actually good enough? Coming from DevOps, where production incidents force similar tradeoffs, the muscle memory transferred directly. The context is different. The skill is the same.