Reino do Ritmo
Six shires, each with a style of music, where you collect notes, raise creatures that play along and open the next shire. Made for a seven-year-old child to play. The name is Portuguese for “Kingdom of Rhythm”.
The central decision
The game rule does not know Roblox. The core is pure Luau, without a line of game,
workspace, Instance or task, and it is where economy, rarity rolls, offline income, streak and
collection validation live. What runs inside Roblox is a thin layer that applies that core and draws
the result.
The practical consequence is the same as in Onde está o Gato: most of the game is testable without opening Studio, with the suite running headless in milliseconds. The alternative would be opening the editor to check whether offline income respects the hour cap, which is slow enough that in practice nobody checks.
Keeping the core pure took three layers
It was the most interesting part of the project, and the one I would not have foreseen:
| Layer | What it catches |
|---|---|
| Linter configured with the language’s standard library, not Roblox’s | game, workspace, Instance, task |
| Guard in CI | os.time, os.clock, tick, math.random — legitimate Luau, but it breaks determinism |
| The suite running outside Roblox | everything: a module that touches the runtime simply does not execute |
The third is the one that proves it. The first two exist so the failure arrives early and points to the right place, instead of showing up as a red test with no explanation.
A trap that cost discovery: the linter does not cascade configuration by directory. Running it pointed at the core folder ignores the restricted configuration there and uses the root one, which loads the Roblox library and approves exactly what it should block. Only the explicit form catches it, and it is the one CI uses.
What crossed from stack to stack
This project is the translation of my .NET patterns into Luau: layered architecture with the dependency pointing inward, notification instead of exception, clock and randomness injected instead of accessed directly.
What did not cross is documented with the same honesty, because it is where translating a pattern usually turns into cargo cult: not everything that makes sense in an enterprise domain with relational persistence makes sense in a single-aggregate save. Identity, repository and domain event, for example, gain nothing here.
About the people in the game
Two NPCs are a tribute to real children, with first name and stylized appearance. Nothing that identifies anyone.