§ 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
endBuilding 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
rarity and luck system in Roblox
Weighted selection, luck applied to weights rather than rerolls, and odds you can actually show the player, because for paid rolls Roblox requires it.
Roblox pet system
11 files · 340 lines · 1m 28s · 1 credit. Pets persist across server restarts, trade-safe by default.
Roblox inventory system
6 files · 230 lines · 56 seconds · 1 credit. 30-slot inventory + 5-slot hotbar.