> 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.
npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill roblox-luau
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.
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.
-- 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)
local 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
local 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()
-- 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)
-- 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)
local 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)
-- 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
local 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).save-systems — engine-agnostic persistence concepts.game-ai / input-systems — portable AI and input patterns to implement in Luau.Integration with protocols.io API for managing scientific protocols. This skill should be used when working with protocols.io to search, create, update, or publish protocols; manage protocol steps and materials; handle discussions and comments; organize workspaces; upload and manage files; or integrate protocols.io functionality into workflows. Applicable for protocol discovery, collaborative protocol development, experiment tracking, lab protocol management, and scientific documentation.
Analyzes job descriptions and generates tailored resumes that highlight relevant experience, skills, and achievements to maximize interview chances
Generate Excalidraw diagrams from natural language descriptions. Use when asked to "create a diagram", "make a flowchart", "visualize a process", "draw a system architecture", "create a mind map", or "generate an Excalidraw file". Supports flowcharts, relationship diagrams, mind maps, and system architecture diagrams. Outputs .excalidraw JSON files that can be opened directly in Excalidraw.
Build and distribute Expo development clients locally or via TestFlight
Use when you have a written implementation plan to execute in a separate session with review checkpoints
Data structure for annotated matrices in single-cell analysis. Use when working with .h5ad files or integrating with the scverse ecosystem. This is the data format skill—for analysis workflows use scanpy; for probabilistic models use scvi-tools; for population-scale queries use cellxgene-census.
Benchling R&D platform integration. Access registry (DNA, proteins), inventory, ELN entries, workflows via API, build Benchling Apps, query Data Warehouse, for lab data management automation.
Comprehensive molecular biology toolkit. Use for sequence manipulation, file parsing (FASTA/GenBank/PDB), phylogenetics, and programmatic NCBI/PubMed access (Bio.Entrez). Best for batch processing, custom bioinformatics pipelines, BLAST automation. For quick lookups use gget; for multi-service integration use bioservices.
Take gamedev-skills/roblox-luau from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.