In this post
The studio is a Flutter studio. Six of seven games are Flutter, the rest of the portfolio is Flutter, and the standardisation is deliberate.
One game is Godot 4.3, in GDScript.
This post is about what justifies breaking your own rule.
What the game is
A mobile-first 2.5D platformer in the spirit of unfair-trap games — where the fun is precisely the block that falls where you did not expect. Eleven playable levels across two worlds, a boss on level 10 and a bonus stage.
The word that decides everything in that description is levels.
The criterion: who draws the level?
In Flame or plain widgets the criterion was whether state changes per frame or per event. Here there is a third step, and it is not about rendering:
Is the game's content drawn or generated?
A game with generated content — endless, procedural, random — needs no editor. The rules produce the content, and the work is tuning the rules.
A game with drawn content needs someone placing each element. And placement is visual, iterative work: you move the trap two blocks right, test, move it back, test again. Fifty times per level.
| Content | Tool required |
|---|---|
| Generated by rules | rendering library |
| Drawn by hand | scene editor with live preview |
Without an editor, every position tweak is: change code, recompile, open the game, play to the level, look. With an editor it is drag and look. In a platformer level that happens hundreds of times — the difference is not convenience, it is feasibility.
What Godot provides that was missing
Scene editor. Placing platforms, traps and enemies visually, with the game running next to it. That is the main reason.
Tilemap. Building levels from a block palette, with collision included. Reimplementing that is weeks.
Physics with bodies. A character that falls, slides, pushes and collides with materials has behaviour nobody wants to hand-write — and that must stay consistent across eleven levels.
Node tree with scene inheritance. A trap becomes a reusable scene; changing the base scene updates every instance in every level. That is what makes late adjustments possible.
Fast iteration. GDScript reloads and the game continues. In a game whose fun is the exact timing of a trap, test-cycle speed is the design process.
What it cost
Being honest here matters more than the list of advantages.
Duplicated context. Two languages, two project conventions, two toolchains. Switching has a real mental cost, most visible when returning after weeks.
Different publishing. Export, signing and store submission had automation ready for Flutter. For Godot it was rebuilt. Not hard; time that was not planned.
Bigger binary. A full engine bundled in weighs more than a regular app. In casual games, download size affects installs — that is a product cost, not just a technical one.
Nothing is reusable. Components, theme, utilities, ad integration: none of what existed applied. Starting from zero in a studio that standardised precisely to avoid starting from zero is uncomfortable.
And the status is worth recording, because it qualifies everything above: the Android export has not been completed yet. So this post reports the decision and the development cost, not the total cost — the publishing part, which is where the missing automation will hurt, is still ahead. Telling only the known half would sell the decision better than it has actually proven.
The cost that was not technical and nearly went unnoticed
Troll Quest's biggest risk did not come from the engine. It came from what the game is.
The premise is Brazilian humour: memes, references and easter eggs the audience recognises. That works very well as a product and creates a problem no engine decision solves — meme audio has an owner.
A snippet of a song, a line from a viral video, a sound effect that became famous: each one is somebody's work, and "everyone uses it" is not a licence. In an app store the consequence is not a lawsuit: it is removal. The complaint reaches the platform, the platform pulls the app, and the argument about who was right happens with the product already down.
| Asset | Risk |
|---|---|
| Engine code | clear licence, settled |
| Original art | no risk |
| Recognisable meme audio | third-party rights, unlicensed |
The lesson is not about meme games. It is that the architecture decision was the easy part, and the hard part was in the material — the same pattern that shows up across everything we write: the expensive problem is rarely where the technical argument is looking.
What justifies it anyway
First, the alternative was worse. Building a level editor inside Flutter is a project in itself — and a project that is not the game. Or writing eleven levels in code, which would have turned level design into a programming task, done by the wrong person, at the wrong pace.
Second, platformer is a category, not a project. For a single isolated game the context cost would not pay for itself. Since the format is meant to be repeated, the investment has somewhere to amortise.
Adopting a second stack is justified when it solves a category of problem. Adopting one for a single project is usually a loss dressed up as a technical choice.
That framing also gives you a way to say no. Most requests to introduce a new technology arrive attached to one concrete project, which is the weakest possible case for them and the most persuasive in the moment. Asking "what is the second project that would use this?" is not bureaucracy — it is the difference between an investment and a souvenir.
Summary
- The criterion is not rendering, it is authoring: is the content drawn or
generated? Drawn content needs an editor.
- Godot supplied the scene editor, tilemaps, physics bodies, scene inheritance and
a fast iteration loop.
- It cost duplicated context, rebuilt publishing tooling, a larger binary and zero
code reuse — and the Android export is still pending.
- The biggest risk turned out to be unlicensed meme audio, which no engine choice
addresses.
- A second stack pays off for a category, never for a single project.
- When unsure, prototype the mechanic in Flutter first. If it is not fun, the tool
does not matter.
The rule that stuck
Written before the next game, so it is not decided in the heat of the moment:
- 1. Content generated by rules → Flutter. With Flame if it changes per frame,
without if it changes per event.
- 2. Content drawn by hand → an engine with an editor.
- 3. Unsure between the two → prototype the mechanic in Flutter first. It is
faster to build, and if the mechanic is not fun, the tool does not matter.
Step 3 is the most valuable and the most skipped. Choosing an engine before knowing whether the game is fun is optimising the execution of an unvalidated idea.
A design note on "mobile-first"
One detail worth recording, because it nearly became a problem: trap platformers were born on keyboards, and keyboard precision does not exist on a touchscreen.
Translating that required changing the design, not just the controls — wider reaction windows on traps, closer checkpoints, cheap deaths and instant restarts. A game of this genre ported without that adjustment becomes unfair in the wrong way: frustrating instead of funny.
No tool solves that. None of them do.
Frequently asked questions
Couldn't the platformer be built with Flame?
It could, at a specific cost: building a level editor, or writing every level in code. Eleven hand-written levels are manageable; adjusting a trap's position in code, recompiling and testing, fifty times per level, is not.
Does Godot export well to mobile?
It exports to Android and iOS. The binary is larger than a regular app and the signing and publishing flow has its own steps — nothing blocking, but it is a different process from the one already automated for Flutter.
Is it worth maintaining two stacks in a small studio?
Only when the second one solves an entire category of problem, not a single project. For one isolated game the context cost would not pay for itself.
Why GDScript and not C#?
Iteration speed. GDScript is the editor's first-class language, with fast reload and direct integration with the node tree. For a game about mechanics rather than raw performance, iteration is worth more than any speed difference.