Devlog / Transmission
RobloxMobileGame DesignPerformance

Roblox Mobile Game Design: How We Build for Phones First

Our Roblox mobile game design checklist: test at phone size, place touch buttons around the jump button, keep text out of the view and budget parts per map.

7 min readTumblix Studios

The players we build for are mostly kids, and most of them play on a phone. That one fact shapes more of our Roblox mobile game design than any genre choice. A game that feels great on a 27-inch monitor with a mouse can be unplayable on a five-inch screen with two thumbs: buttons under other buttons, banners over the road, a map that streams in a block at a time.

This post is the checklist we now run on every build, with the mistakes that taught us each item. The examples come from Shopping Cart Mayhem and Ride a Dino, two of our Roblox games.

Test at phone size, as a new player

Roblox Studio's Device Emulator lets you play at a phone resolution. We test in landscape at sizes like 812x375 and 749x367, because that is the space a real phone leaves after the system bars.

Running the emulator is not enough. You have to play the first ten minutes as someone who has never seen the game. On Ride a Dino we learned this the hard way. The build passed every automated check, and still a playtest found a dino standing on its tail, a guide path that vanished, and a "GOLDEN EGG!" banner that said something had happened but not where to go. Every one of those was obvious in the first few minutes of play at phone size.

Our rule now: before anyone else sees a build, we take screenshots at phone size of every screen and every timed event, and ask three questions:

  1. Is it clear what just happened?
  2. Is it clear where to go and what to do next?
  3. Does any text, panel or button cover the part of the screen the player needs?

Put touch buttons where thumbs are

Roblox gives mobile players a thumbstick on the left and a jump button on the right. Your own action buttons (sprint, dash, use item) live around that jump button. The trap: the jump button's size and position change with the screen size and with the player module version. In Shopping Cart Mayhem we first placed our buttons at fixed offsets. On some phones the RUN button ended up half under the jump button.

The fix was to stop using fixed positions. We bind each action with ContextActionService as usual, then place its button on a ring around wherever the jump button really is. Each action gets an angle and a ring number:

-- Degrees around the jump button (0 = right, 90 = up) and the ring
-- (2 = one button further out). Dash and Catch share a slot: guards never dash.
local SLOTS = {
	Sprint = { 180, 1 },
	ShowGuide = { 135, 1 },
	Dash = { 90, 1 },
	Catch = { 90, 1 },
	ToggleView = { 157, 2 },
	EnergyCan = { 90, 2 },
	SmokeBomb = { 113, 2 },
	Horn = { 180, 2 },
}

Two details worth copying. First, the most-used actions sit on the inner ring, closest to the thumb. Second, two actions that can never be used by the same player at once (a thief's dash and a guard's catch) share a slot, so the layout stays small.

Never put text over the view

On a phone, the middle of the screen is the game. A tip, a banner or a toast that sits there for three seconds can get a player caught or lost. We treat the middle of the screen as off limits for anything that stays up.

Use the top bar strip

Roblox's top bar (the menu and chat buttons) leaves free space along the top edge of the screen. GuiService.TopbarInset gives you that free strip as a rectangle in screen coordinates. Our first-heist tips now live there, at full size, out of the way:

local strip, inset = GuiService.TopbarInset, GuiService:GetGuiInset()
if strip.Width >= 280 and strip.Height >= 32 then
	-- Room in the top bar: the tip sits in the strip, full size.
	local width = math.min(strip.Width - 16, 620)
	tutorial.Size = UDim2.fromOffset(width, strip.Height - 8)
	tutorial.Position = UDim2.fromOffset(strip.Min.X + 8 - inset.X, strip.Min.Y + 4 - inset.Y)
else
	-- No room: fall back to a line under the alerts, never mid-screen.
	tutorial.Size = UDim2.fromOffset(480, 44)
end

Note the - inset part: TopbarInset is in screen coordinates, while a ScreenGui that respects the GUI inset measures from below the top bar. Also listen for GuiService:GetPropertyChangedSignal("TopbarInset") and re-run the layout, because the strip changes when the screen rotates or the top bar changes.

Stack the HUD, and let it shrink

We lay out the HUD as two stacks: one under the top bar (alerts, then the tip line, then status lines) and one at the bottom (controls hint, vitals, the current objective, then toasts). Each block sits a fixed gap from the one before it. When a block hides, the blocks after it move up. On short screens the whole HUD scales down, and the left column shrinks further if it would otherwise overlap. No block ever has a hard-coded position that assumes a desktop screen.

Every banner gives a direction

The Ride a Dino Golden Egg banner taught us this one. A banner that says what happened is half a message. The other half is where to go: an arrow, a waypoint, a path on the ground. If a player has to read a sentence to know where to go, a phone player will not read it.

Budget parts per map

Phones run out of memory and frame time long before PCs do. The biggest factor we control is how many parts a map has and how many of them a phone has to load at once.

We count parts on the server per round, for every map. For Shopping Cart Mayhem the count looked like this:

MapParts per round
Mega Mart62,500
Airport17,900
Mall16,700
Museum13,600
Jewelry Store9,400

Mega Mart was the outlier by far, and almost all of it, about 52,700 parts, was products sitting on shelves. A player cannot see most of those products from where they stand. With streaming on, a phone client in Mega Mart still loaded about 17,000 to 23,000 parts at once.

What we do with that number

  • Thin decoration first. If low-end phones lag in Mega Mart, the first thing to cut is shelf stock: fewer rows of products, not fewer shelves or guards. Decoration is the cheapest thing to lose and the biggest thing to save.
  • Turn streaming on and set the radius. Our place uses StreamingEnabled with a target radius of 320 studs and a minimum radius of 128. The player loads what is near them, not the whole store.
  • Pick a streaming mode per model. A model that scripts and clients look up by name (the ground, the entrance, the escape zone) is Persistent, so a client has it before the rest of the map streams in. A display that only makes sense whole, like a cart on its podium, is Atomic, so it streams in as one piece instead of wheel by wheel.
  • Make look-only things cheap. Decorative parts get CanCollide, CanQuery, CanTouch and CastShadow set to false, so physics, pathfinding and guard line of sight ignore them. Our cart showroom shows every cart on its own podium. Those display carts are anchored, with no scripts: they exist to be looked at. The showroom is its own streamed model, so it unloads when the player is far away in a heist.
  • Check new work against the budget. When we added the lobby rebuild and the airport work, we counted again: about 1,500 extra parts. That is fine. A change that adds 10,000 is a conversation.

Small things that add up

  • Draw your icons. We draw UI icons from frames and shapes, or show small 3D models of items, instead of using emoji. They look the same on every device and fit the game's art.
  • Test with the slowest phone you have. The emulator shows layout, not frame rate. A cheap phone shows the frame rate.
  • Keep buttons big. A button that is easy to hit with a mouse can be hard to hit with a thumb.

The checklist

  1. Play the first ten minutes at phone size, as a new player.
  2. Touch buttons sit on a ring around the real jump button, most-used closest.
  3. Nothing stays up in the middle of the screen. Tips go in the top bar strip.
  4. Every banner says where to go, not only what happened.
  5. Count parts per map. Know which map is the outlier and why.
  6. Streaming on, with the right mode per model.
  7. Cut decoration before you cut gameplay.

Phone-first design and retention are the same problem from two sides. A player who cannot read the screen does not finish the first round. For the analytics side of that story, read how we fixed our first-session funnel. If you are starting a new project, our step-by-step guide to making a Roblox game covers the setup this checklist assumes.

// Next transmissions

Keep reading