Lua Scripting

How to find a Roblox game idea and actually finish it

You have eight .rbxl files saved, twelve ideas in a notes app and no published game. The fix is to stop looking for an idea, pick a verb and close a playable 60-second loop before you touch the map.

by Gustavo Cantino11 min readBeginner

Produced with AI and checked by automated verification. This text carries no source list. No person read this text before publication. Editorial Policy

Mosaic of dozens of Roblox game thumbnails from different genres on a black background, with the platform logo in the centre.

The short answer covers both questions: you do not find an idea, you find a verb; and you do not finish a game, you finish a 60-second loop and publish it ugly. People who ask "how do you find ideas" almost never lack ideas — they have twelve notes on their phone and zero prototype anyone can play. And people who ask "how do you finish" usually started with the map, the logo and the name, which are exactly the three things that do not need to exist in the first week.

The rest of this piece is the route, step by step, with a script ready to paste and a 7-day scope sheet.

The idea is not your problem; scope is

Open the folder where Studio saves your files. If there are five, eight, twelve .rbxl files named things like "new game", "test2", "obby final for real" and none of them is live, the diagnosis is scope, not creativity.

Do the arithmetic that kills the project. You open Studio full of energy and list the features: shop, pets, quests, rebirth, map 2, boss, trade system, saved inventory. That is eight items. Each one takes about 4 hours if everything goes right — and on a first game nothing goes right first time, so 8 is the honest number. That is 64 hours of work, eight full weekends, before a single person clicks Play. In week three you get tired, open Studio and start a new file. It is the same cycle, every time.

What you lose there is not money: publishing an experience on Roblox costs 0 Robux, creating a gamepass costs 0 Robux, shipping an update costs 0 Robux. What you lose is the only thing that really teaches — strangers playing what you made and giving up at second 40. While the game is on your hard drive, you are guessing. Once it is published, you are measuring.

And there is a side effect nobody mentions: finishing a small bad game leaves you better off than almost-finishing a big pretty one. The first teaches you the whole cycle (idea, prototype, publish, feedback, update). The second teaches you to build a map.

Five steps from idea to published game in 7 days

Step 1 — list verbs, not games (30 minutes). Open the Roblox app and look at the last ten games you played. For each one, write the central verb on a single line: run and dodge; push the others; click and watch the number go up; hide; steal things from other people; survive until the timer runs out. Ten lines, thirty minutes. A new idea is almost always a known verb plus a new context plus one crooked rule. "Push" + "escalator" + "whoever falls loses everything they collected" is already a game. You did not have to invent a genre.

Step 2 — the 12-word sentence. Write the game in at most 12 words, and the verb has to be in it. "You collect coins in the arena and last place is eliminated." If the sentence does not fit, the scope is too big — cut until it fits. Then show the sentence to someone who is not a developer. If they ask "right, and what do I do?", you do not have a verb yet, you have a setting.

Step 3 — a 90-minute prototype with grey boxes. Open Studio, choose the Baseplate template (just a grey floor). The Explorer is the right-hand panel that lists every object in the game; if it is not open, go to the View tab at the top and click Explorer. Inside it is ServerScriptService, the box that holds the scripts running on the server. Hover over its name, click the + button, choose Script, delete whatever is written there and paste the code from the artifact below.

Before anything else, confirm that scripts are running. Paste this, press F5 (Play) and open View → Output, the panel that shows messages and errors in red:

Script in ServerScriptService
print("it ran")

If "it ran" appears in the Output, your environment is up. The 90-minute rule: no Toolbox, no pretty model, no final name. Just grey Parts and the verb working.

Step 4 — write the scope before you model. Three features, maximum. Everything that does not serve the verb goes into a list called depois.txt and leaves your head. The JSON sheet in the artifact already has the seven days split up: days 1 and 2 the loop, day 3 scoreboard and on-screen feedback, day 4 an ugly but working map, day 5 sound and minimal UI, day 6 testing with five people, day 7 publishing.

Step 5 — publish ugly on day 7. In Studio, File → Publish to Roblox As. The experience is born private; to open it, go to Home → Game Settings → Permissions and switch it to Public. Icon and thumbnail: take a screenshot of the game itself, thirty minutes, done. Send the link to five people and watch what they do in the first 60 seconds without explaining anything. The point where they stop understanding is your next bug.

The minimum loop script and the 7-day scope sheet

The artifact has two parts. The first is a Script (a normal Script, not a LocalScript — a LocalScript runs on the player's computer and is no use here) that you paste inside ServerScriptService following step 3. On its own it already delivers a playable game: it creates a yellow coin floating in the map, gives 1 point to whoever touches it, moves the coin to a random spot, keeps a scoreboard in the top right corner of the screen and runs 60-second rounds, announcing the winner and resetting everything at the end.

Pasted it? Press F5. Run to the coin with your character. The number on the scoreboard goes up. That is it — that is a closed loop, and most abandoned projects never reached that point.

Now swap the verb. Three variables at the top of the script control almost everything: ROUND_SECONDS (make it 30 for a more frantic game), AREA (the size of the square where the coin spawns) and POINTS_PER_COIN. If your verb is "push", change the coin into a Part that pushes; if it is "survive", make the points go up with time instead of on touch. The skeleton — player joins, scoreboard exists, round starts, round ends, scoreboard resets — is the same in an obby, a simulator, a tycoon and a horror game.

The second part is escopo.json. It does not run in Studio: save it in the same folder as your .rbxl file and open it in a text editor whenever you feel the urge to add pets. The fields that matter are verbo, frase_12_palavras, features_permitidas (three, and only three) and depois. If what you want to build now is not in features_permitidas, write it in depois and go back to the day you are on.

The mistake that costs three weeks: starting with the map

The most expensive mistake is not technical. It is opening the Toolbox (View tab → Toolbox, the free model store) on day 1 and spending three weekends building scenery. You end up with a beautiful map, zero mechanics and no will to continue, because the fun part is already over.

There is a second problem alongside it: a free Toolbox model often comes with a script hidden inside. The most common kind calls require() with an asset number and downloads code from outside your game — that is how people lose a published game to a stranger. Before using any model, click it in the Explorer, expand the little arrow next to its name and look for any Script or LocalScript you did not put there. To sweep the whole project, press Ctrl+Shift+F (Find All) and search for require(. If a require with a huge number shows up inside a free model, delete the model, not just the script.

How to get out if you are already in that hole: do not fix the old file. Open a fresh Baseplate, spend 90 minutes getting only the loop running and, if it is fun, then import pieces of the old map. The map is a tool for the verb, not the other way round. And if you cannot play your own prototype for two minutes without getting bored, the problem was never the lack of decoration.

What to measure in the first week live

Once published, open the Creator Dashboard in your browser, go into your experience and open Analytics. Three numbers decide the future of the project:

Average Session Time. If it is under a minute, nobody understood the verb in the first few seconds — fix the entry to the game, do not add content. Day 1 Retention (how many came back the next day). It is the number that separates a prototype from a game: if nobody comes back, more features will not save it. Visits only gives context to the other two; high visits with a 30-second session means your thumbnail is better than your game.

Run one experiment a week and change one thing at a time: round length, walk speed, points per coin. Publish the update, wait seven days, compare against your own previous week. Comparing with somebody else's game at this stage produces no decision at all.

And do not add a gamepass before retention exists. Monetising a loop nobody repeats is spending a day of work to sell tickets to an empty room. First people come back; then you charge.

Ready-to-use artifact

Script in ServerScriptService
lua
--!strict
-- MINIMUM PLAYABLE LOOP
-- Where to paste it: Explorer > ServerScriptService > + button > Script
-- (a normal Script, NOT a LocalScript.)
-- What it does: creates a coin, gives a point to whoever touches it,
-- keeps a scoreboard and runs 60-second rounds.

local Players = game:GetService("Players")

-- Touch only these three values to change the pace of the game:
local ROUND_SECONDS: number = 60
local AREA: number = 60 -- half the side of the square where the coin spawns
local POINTS_PER_COIN: number = 1

-- Creates the player's scoreboard (appears in the top right corner).
local function createScoreboard(player: Player)
	local folder = Instance.new("Folder")
	folder.Name = "leaderstats" -- this exact name is mandatory
	local points = Instance.new("IntValue")
	points.Name = "Points"
	points.Value = 0
	points.Parent = folder
	folder.Parent = player
end

Players.PlayerAdded:Connect(createScoreboard)
-- Covers anyone already in the game when the script started (Studio testing):
for _, player in ipairs(Players:GetPlayers()) do
	if not player:FindFirstChild("leaderstats") then
		createScoreboard(player)
	end
end

local function getPoints(player: Player): IntValue?
	local folder = player:FindFirstChild("leaderstats")
	if not folder then
		return nil
	end
	local value = folder:FindFirstChild("Points")
	if value and value:IsA("IntValue") then
		return value
	end
	return nil
end

-- The coin: a floating yellow Part. Swap it for anything else later.
local coin = Instance.new("Part")
coin.Name = "Coin"
coin.Size = Vector3.new(2, 2, 2)
coin.Anchored = true -- does not fall and cannot be pushed
coin.CanCollide = false -- the player passes through instead of bumping
coin.Material = Enum.Material.Neon
coin.Color = Color3.fromRGB(255, 200, 0)
coin.Parent = workspace

local function repositionCoin()
	coin.CFrame = CFrame.new(math.random(-AREA, AREA), 4, math.random(-AREA, AREA))
end
repositionCoin()

-- Simple latch so Touched does not fire ten times on the same touch.
local canTouch = true

coin.Touched:Connect(function(hit: BasePart)
	if not canTouch then
		return
	end
	local character = hit.Parent
	if not character or not character:IsA("Model") then
		return
	end
	local player = Players:GetPlayerFromCharacter(character)
	if not player then
		return
	end

	canTouch = false
	local points = getPoints(player)
	if points then
		points.Value += POINTS_PER_COIN
	end
	repositionCoin()
	task.wait(0.2)
	canTouch = true
end)

-- The round loop: counts the time, announces the winner, resets everything.
task.spawn(function()
	while true do
		print("Round started! " .. ROUND_SECONDS .. " seconds.")
		task.wait(ROUND_SECONDS)

		local bestName = "nobody"
		local bestValue = -1
		for _, player in ipairs(Players:GetPlayers()) do
			local points = getPoints(player)
			if points and points.Value > bestValue then
				bestValue = points.Value
				bestName = player.Name
			end
		end
		print("Round over. Winner: " .. bestName .. " with " .. bestValue .. " point(s).")

		for _, player in ipairs(Players:GetPlayers()) do
			local points = getPoints(player)
			if points then
				points.Value = 0
			end
		end
		repositionCoin()
		task.wait(3) -- breather between rounds
	end
end)
escopo.json file saved in the same folder as your .rbxl
json
{
  "projeto": "prototipo-semana-01",
  "verbo": "collect",
  "frase_12_palavras": "You collect coins in the arena and whoever has fewest is eliminated.",
  "features_permitidas": [
    "coin that gives a point on touch",
    "per-player scoreboard (leaderstats)",
    "round with a timer and a winner"
  ],
  "depois": [
    "shop",
    "pets",
    "rebirth",
    "map 2",
    "saving progress",
    "gamepass"
  ],
  "cronograma_7_dias": {
    "dia_1": "90-minute prototype: Baseplate + the loop script running",
    "dia_2": "tune the pace: round length, walk speed, points per coin",
    "dia_3": "on-screen feedback: pickup sound, end-of-round text",
    "dia_4": "ugly but working map: walls, spawn, arena boundary",
    "dia_5": "minimal UI and a game name",
    "dia_6": "test with 5 people and note where each one got stuck",
    "dia_7": "publish public + icon taken from a screenshot of the game"
  },
  "criterio_de_pronto": "a stranger plays for 2 minutes without me explaining anything",
  "metricas_semana_1": [
    "average session time",
    "day 1 retention",
    "visits"
  ]
}
In this article

Keep reading