§ How to · with Picoo

How to make an egg hatching system in Roblox

By Sametcan Tasgiran, Founder & Developer·Published ·Updated

The suspense animation is the product, but the result must be decided before it starts — otherwise a disconnect at the wrong second costs a player a legendary.

Hatching is a rarity roll wrapped in theatre, and the order of operations is what makes it safe.

Result first, theatre second

The server rolls, saves and replies; the client then plays the animation for a result that already exists.

Space checked upfront

Inventory capacity and currency are validated before anything is spent or rolled.

Multi-hatch

Three or eight eggs at once, rolled independently and presented together.

Per-egg tables

Each egg has its own weights and price, derived from the shared rarity system.

Rarity-scaled reveal

Longer build-up and stronger effects for a rare result, using the outcome the server already sent.

Odds display

The egg's real chances shown on the egg, generated from its table.

Files Picoo ships for this prompt

2 files · 200 lines · ~30s · 1 credit

EggService

Purchase validation, capacity check, rolling, persistence, reply.

120 lines

EggClient

Hatch animation, rarity-scaled reveal, multi-hatch layout.

80 lines

Sample output: ServerScriptService.EggService

-- ORDER MATTERS. Roll and PERSIST first, animate second. If the animation runs
-- while the server is still deciding, a player who disconnects at the wrong
-- moment has paid and received nothing — and that is a support ticket you cannot
-- disprove.
local function hatch(plr: Player, eggId: string, count: number): { string }?
	local egg = EGGS[eggId]; if not egg then return nil end
	local data = Store.get(plr)

	-- Check space BEFORE taking money. Rolling into a full inventory means either
	-- losing the pet or refunding, and both are worse than refusing up front.
	if #data.pets + count > data.petCapacity then
		notify(plr, "Not enough pet space"); return nil
	end
	if data.coins < egg.price * count then return nil end

	data.coins -= egg.price * count
	local results = {}
	for _ = 1, count do
		local pet = Rarity.roll(egg.table, luckOf(plr))
		table.insert(results, pet)
		table.insert(data.pets, pet)
	end

	if not Store.saveNow(plr, data) then
		return nil                       -- nothing spent, nothing granted
	end
	return results                       -- client animates a result that EXISTS
end

Building an egg hatching system in Roblox

Egg hatching is a weighted roll with three seconds of theatre attached, and almost everything that goes wrong with it is a question of what happens in what order.

The instinct is to build it in the order the player experiences it: press hatch, play the animation, decide the result, hand it over. That sequence has a hole in the middle. If the player disconnects, the server restarts, or the DataStore write fails while the egg is still spinning, they have paid and received nothing — and from your side it is indistinguishable from someone claiming they did. Rolling and persisting first, then sending the result down for the client to reveal, closes it completely. The animation becomes a presentation of something that already exists, which also means you can scale the build-up by rarity, because the client knows what it is revealing before it starts.

Capacity is the second ordering question. Rolling into a full inventory leaves you choosing between destroying a pet somebody paid for and writing a refund path, and refund paths have their own bugs. Checking space before any currency moves eliminates the branch entirely.

Multi-hatch is mostly a feel problem. Roll each egg independently — sharing one roll across eight eggs produces conspicuously identical results and players notice immediately — and reveal them together, rarest last. What players are buying is compressed ceremony, not better odds, and treating it that way keeps the maths simple.

Underneath, this is the rarity system doing the work. Keep the egg's weight table as data, generate its odds panel from that same table, and hatching stays a thin layer over something you already trust.

See more on the Luau generator, the game builder, or browse the full blog.

Frequently asked

Should the client or the server decide what hatches?+

The server, before the animation starts. A client that rolls is a client that picks, and in a pet game that is the entire economy. The animation's only job is to reveal a result the server has already decided and saved.

What happens if a player leaves mid-animation?+

Nothing, if you ordered it correctly. The pet was rolled and persisted before the animation began, so it is waiting when they return. If you animate first and grant on completion, a disconnect at the wrong second means they paid and got nothing — and you cannot tell that apart from a false claim.

Why check inventory space first?+

Because the alternatives are both bad. Rolling into a full inventory means either destroying a pet the player paid for or writing a refund path that will have its own bugs. Refusing before any currency moves is one line and removes the whole class of problem.

How do I make multi-hatch feel worth it?+

Roll each egg independently — a shared roll makes the outcome feel fake because eight identical results are conspicuous — and reveal them together with the rarest last. The value is in compressing the ceremony, not in changing the odds.

Should rare results get a longer animation?+

Yes, and you can, because the client already knows the outcome when the animation starts. Scaling the build-up by rarity is what makes the reveal land. Just do not let that build-up be the thing that decides the result.

Related Picoo prompts