Yesterday we could generate a dungeon. Today we made it playable.
Jump pads
The JumpPad component teleports players between dungeon regions. Step on a glowing pad, fade to black, appear in the next area. Each pad runs a per-player state machine: idle → charging → teleporting → cooldown. This matters for multiplayer — two players can use the same pad at different times without interfering with each other. Player A in cooldown doesn’t block Player B from activating.
The state machine also prevents the classic “touch event fires twice” problem. In Roblox, Touched events can fire multiple times per contact due to physics simulation. Without state tracking, a player standing on a pad would teleport repeatedly. The state machine ignores touch events unless the pad is in the idle state.
Screen transitions
Teleportation needs visual feedback. Without it, the player’s position snaps and the camera jerks — jarring and disorienting. We added fade-to-black transitions: screen fades out, player repositions, new region loads, screen fades back in. The transition system queues requests, so rapid pad-to-pad navigation doesn’t create overlapping fades.
Map type system and AreaHUD
Dungeons now have map types — each region has a name, a color from a palette, and visual theming parameters. The AreaHUD displays the current region name and a color bar at the top of the screen. Walking through a portal updates the HUD with the new region’s identity.
This is the first step toward making dungeon areas feel distinct. Right now the visual difference is just color. Later, map types will drive terrain materials, lighting, and room scale.
3D Minimap
The big feature: a 3D minimap overlay. It renders a scaled-down version of the dungeon geometry in a ViewportFrame, with full gamepad controls:
- Right stick — Rotate the minimap view
- L2/R2 — Navigate between rooms (highlights each room in sequence)
- Portal indicators show connections between rooms with directional arrows
Building a minimap in a ViewportFrame means cloning the dungeon geometry, scaling it down, and rendering it in an isolated 3D scene. The tricky part was getting the camera right — it needs to frame the entire dungeon, centered on the bounding box. Our first version rotated around the world origin instead of the dungeon center, which made the view swing wildly for dungeons that weren’t positioned at (0,0,0).
Room navigation with L2/R2 was a late addition that made the minimap dramatically more useful. Instead of just seeing a static overview, you can step through rooms and see portal connections from each room’s perspective.
Per-player persistence
The day’s final feature: DataStore persistence. Every player’s dungeon state is saved — the generation seed (so the dungeon can be regenerated deterministically), current region index, and discovered map data. Leave and rejoin? You’re back where you were.
We save the seed rather than the entire layout because seeds are tiny (one number) and layouts are large (hundreds of room definitions). Regenerating from seed produces the identical dungeon every time, so we only need to store the player’s position within it.
This was the day the project stopped being a tech demo and started being a game.