Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Script a Roblox experience in Luau: get services, create and parent Instances, connect events, run server Scripts vs client LocalScripts, and communicate across the client/server boundary with RemoteEvents/RemoteFunctions (server-authoritative). Use when building or debugging Roblox Studio scripts — when the user mentions Roblox, Luau, services, RemoteEvent, Instance.new, PlayerAdded, or client vs server. For saving player data use roblox-datastores.
.claude/skills/gamedev-skills-roblox-luau/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 80% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 69% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 61% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 120% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 138% | 0% |
Script a Roblox experience in Luau: services, Instances, events, the server/client split, and secure cross-boundary communication. Targets the current Roblox engine and Studio.
connecting events, deciding server vs client, or wiring RemoteEvent/ RemoteFunction communication.
Script/LocalScript/ModuleScript objects, .rbxl(x)places, or a Rojo *.project.json, and code calls game:GetService(...).
When not to use: persisting data across sessions → roblox-datastores. Remote protocol architecture, exploit hardening, rate limits, high-frequency replication, and multi-client abuse testing → roblox-networking. Generic Lua questions unrelated to the Roblox API. Engine-agnostic input/save architecture → input-systems / save-systems.
game:GetService("Name"). Common ones: Players,Workspace, ReplicatedStorage (shared client+server), ServerScriptService (server-only code), ServerStorage, RunService, UserInputService (client).
Script runs on the server; a LocalScriptruns on a client (in StarterPlayerScripts, StarterGui, or the player's character). A ModuleScript is shared code you require.
local p = Instance.new("Part"), set itsproperties, then set p.Parent last (parenting triggers replication).
:Connect to signals like Players.PlayerAdded,part.Touched, or RunService.Heartbeat. Disconnect when done to avoid leaks.
Clients request via RemoteEvent:FireServer(...); the server validates and applies. The server is authoritative for all game state.
window and the server/client view toggle to confirm where code ran.
lua-- ServerScriptService/Leaderboard.server.luau (a Script = runs on the server) local Players = game:GetService("Players") local function onPlayerAdded(player: Player) local stats = Instance.new("Folder") stats.Name = "leaderstats" -- this name makes it show on the leaderboard local coins = Instance.new("IntValue") coins.Name = "Coins" coins.Value = 0 coins.Parent = stats stats.Parent = player -- parent LAST end Players.PlayerAdded:Connect(onPlayerAdded)
lualocal Workspace = game:GetService("Workspace") local part = Instance.new("Part") part.Size = Vector3.new(4, 1, 4) part.Position = Vector3.new(0, 10, 0) part.Anchored = true -- won't fall under gravity part.BrickColor = BrickColor.new("Bright blue") part.Parent = Workspace -- set Parent last so it replicates once, fully
lualocal debounce = false local connection connection = part.Touched:Connect(function(hit: BasePart) local character = hit.Parent local humanoid = character and character:FindFirstChildOfClass("Humanoid") if not humanoid or debounce then return end debounce = true humanoid.Health -= 10 task.wait(1) -- task.wait, NOT the deprecated wait() debounce = false end) -- Later, when the part is removed or the round ends: -- connection:Disconnect()
lua-- ReplicatedStorage: create a RemoteEvent named "BuyItem" (in Studio or via code). -- CLIENT (LocalScript): request a purchase. The client can lie — this is only a request. local ReplicatedStorage = game:GetService("ReplicatedStorage") local buyItem = ReplicatedStorage:WaitForChild("BuyItem") -- wait: may not have replicated yet buyButton.MouseButton1Click:Connect(function() buyItem:FireServer("sword") -- send the item id only; never the price/result end)
lua-- SERVER (Script): the ONLY place the transaction is decided. local ReplicatedStorage = game:GetService("ReplicatedStorage") local buyItem = ReplicatedStorage:WaitForChild("BuyItem") local PRICES = { sword = 100, shield = 75 } buyItem.OnServerEvent:Connect(function(player: Player, itemId) -- TRUST NOTHING from the client. Validate types and values. if type(itemId) ~= "string" then return end local price = PRICES[itemId] if not price then return end -- unknown item local coins = player.leaderstats.Coins if coins.Value < price then return end -- can't afford coins.Value -= price -- server applies the change grantItem(player, itemId) end)
lualocal RunService = game:GetService("RunService") -- Heartbeat fires every frame AFTER physics; dt is seconds since the last step. RunService.Heartbeat:Connect(function(dt) spinner.CFrame *= CFrame.Angles(0, math.rad(90) * dt, 0) -- 90deg/sec, frame-independent end)
lua-- ReplicatedStorage/GameConfig (a ModuleScript) — usable by server and client. local GameConfig = {} GameConfig.MaxHealth = 100 function GameConfig.damageFor(weapon: string): number return ({ sword = 25, bow = 15 })[weapon] or 0 end return GameConfig
lualocal GameConfig = require(game:GetService("ReplicatedStorage"):WaitForChild("GameConfig")) print(GameConfig.MaxHealth)
RemoteEvent/RemoteFunction. Validate every argument's type and range on the server and keep the server authoritative over health, currency, and inventory.
LocalScript doesn't run where you put it → LocalScripts run inStarterPlayerScripts, StarterCharacterScripts, StarterGui, or tools — not in Workspace or ServerScriptService. Server Scripts belong in ServerScriptService/Workspace.
task.wait/task.spawn/task.delay, not the oldwait()/spawn()/delay() (worse scheduling and throttling).
Parentlast so the instance replicates once in its final state.
nil on the client right after join → objects stream/replicate over time; useparent:WaitForChild("Name") instead of indexing directly on the client.
:Connect handlers leak and canfire on destroyed objects; store the connection and :Disconnect() (or use Instance:GetAttributeChangedSignal/:Once where appropriate).
RemoteFunction blockswaiting for a return and a malicious/slow client can stall the server; prefer one-way RemoteEvents unless you genuinely need a reply.
RemoteFunction vs RemoteEvent,:WaitForChild timing, BindableEvent for same-context messaging, attributes, CollectionService tags, and :Once/connection cleanup), read references/client-server.md.
roblox-datastores — persist player data across sessions (server-only).roblox-networking — production remote contracts, server validation, rate limits, replication,streaming, prediction, and multi-client testing.
save-systems — engine-agnostic persistence concepts.game-ai / input-systems — portable AI and input patterns to implement in Luau.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-12 | pass→pass | 14,049 | 15,379 | +9% | 1 | 1 | 0% | 1,450 | 3,541 | +144% | 0 | 0 | — |
case-06 | pass→pass | 15,723 | 20,796 | +32% | 1 | 1 | 0% | 1,872 | 3,709 | +98% | 0 | 0 | — |
case-01 | fail→pass | 18,316 | 17,004 | -7% | 1 | 1 | 0% | 2,262 | 4,061 | +80% | 0 | 0 | — |
case-02 | fail→pass | 20,530 | 21,274 | +4% | 1 | 1 | 0% | 2,842 | 4,791 | +69% | 0 | 0 | — |
case-03 | fail→pass | 18,484 | 15,202 | -18% | 1 | 1 | 0% | 2,290 | 3,686 | +61% | 0 | 0 | — |
case-04 | pass→pass | 15,245 | 13,694 | -10% | 1 | 1 | 0% | 1,534 | 3,449 | +125% | 0 | 0 | — |
case-05 | pass→pass | 16,280 | 17,317 | +6% | 1 | 1 | 0% | 1,752 | 3,230 | +84% | 0 | 0 | — |
case-07 | pass→pass | 18,929 | 8,485 | -55% | 1 | 1 | 0% | 2,327 | 3,381 | +45% | 0 | 0 | — |
case-08 | fail→fail | 16,844 | 16,778 | -0% | 1 | 1 | 0% | 1,841 | 3,793 | +106% | 0 | 0 | — |
case-09 | pass→pass | 17,903 | 23,759 | +33% | 1 | 1 | 0% | 2,114 | 4,611 | +118% | 0 | 0 | — |
case-10 | pass→pass | 18,468 | 17,057 | -8% | 1 | 1 | 0% | 1,783 | 3,904 | +119% | 0 | 0 | — |
case-11 | fail→pass | 13,649 | 13,372 | -2% | 1 | 1 | 0% | 1,425 | 3,140 | +120% | 0 | 0 | — |
case-13 | pass→pass | 18,091 | 12,771 | -29% | 1 | 1 | 0% | 2,299 | 3,797 | +65% | 0 | 0 | — |
case-14 | pass→fail | 16,890 | 34,237 | +103% | 1 | 1 | 0% | 2,149 | 4,674 | +117% | 0 | 0 | — |
case-15 | pass→pass | 14,190 | 16,461 | +16% | 1 | 1 | 0% | 2,208 | 3,723 | +69% | 0 | 0 | — |
case-16 | pass→pass | 12,080 | 13,682 | +13% | 1 | 1 | 0% | 2,085 | 4,141 | +99% | 0 | 0 | — |
case-17 | fail→pass | 14,342 | 11,207 | -22% | 1 | 1 | 0% | 1,570 | 3,733 | +138% | 0 | 0 | — |
case-18 | pass→pass | 24,322 | 14,571 | -40% | 1 | 1 | 0% | 3,683 | 4,694 | +27% | 0 | 0 | — |
case-19 | pass→fail | 14,102 | 14,228 | +1% | 1 | 1 | 0% | 2,455 | 4,590 | +87% | 0 | 0 | — |
case-20 | pass→pass | 16,694 | 23,306 | +40% | 1 | 1 | 0% | 3,026 | 6,334 | +109% | 0 | 0 | — |
case-21 | pass→fail | 46,543 | 44,165 | -5% | 1 | 1 | 0% | 7,863 | 9,132 | +16% | 0 | 0 | — |
case-22 | pass→pass | 24,632 | 21,087 | -14% | 1 | 1 | 0% | 4,899 | 5,192 | +6% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +9 percentage points is the difference between those two pass rates over the 22 comparable cases. 3 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 8/2/2026 | +9% |
Other measured skills in the registry, with their headline benchmark lift.