In short
Insert a Tool into StarterPack, put a Part named Handle inside it (not anchored, not colliding), and add a Script inside the Tool that connects tool.Activated. Activated fires when the player clicks or taps while holding it, and a server Script inside the tool receives it, so the effect counts for everyone. Use Equipped and Unequipped for things that happen when it is taken out or put away.
- The part must be named exactly
Handle, or set the Tool'sRequiresHandleoff for a tool with nothing in the hand. - Never anchor the Handle: it pins the player in place.
- Keep cooldowns and uses on the server script, not in a LocalScript.
Get the script
Healing potion tool script with uses and cooldown
A server Script inside a Tool that heals the holder on click, with a cooldown and a number of uses, and removes the tool when it is empty.
-- Script inside the Potion Tool, named PotionScript.
-- Heals the holder on click, with a cooldown and a limited number of uses.
local tool = script.Parent :: Tool
local HEAL_AMOUNT = 40
local COOLDOWN_SECONDS = 3
local lastUse = 0
tool.Activated:Connect(function()
local now = os.clock()
if now - lastUse < COOLDOWN_SECONDS then
return
end
-- the tool is inside the character while it is held
local character = tool.Parent
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if not humanoid or humanoid.Health <= 0 or humanoid.Health >= humanoid.MaxHealth then
return -- nobody to heal, or already at full health: do not waste a use
end
local uses = tool:GetAttribute("Uses")
if typeof(uses) ~= "number" or uses <= 0 then
return
end
lastUse = now
humanoid.Health = math.min(humanoid.Health + HEAL_AMOUNT, humanoid.MaxHealth)
tool:SetAttribute("Uses", uses - 1)
tool.ToolTip = (uses - 1) .. " drinks left"
if uses - 1 <= 0 then
tool:Destroy()
end
end)
RoCode builds it in the place you have open in Roblox Studio, on Windows or macOS with a desktop browser; on a phone the button sends the prompt and the link to your computer. Free to start, with free credits every day. More Roblox Studio scripts
Where to put it
StarterPack
Potion Tool new
Handle Part new
PotionScript Script new
Settings you can change
HEAL_AMOUNTIn the script- Health restored per drink. Default:
40. COOLDOWN_SECONDSIn the script- Seconds before it can be used again. Default:
3. UsesAttribute- Drinks left. Set a number attribute named Uses on the Tool; the tool is removed at 0. Default:
3.
What a cheater can and cannot doThe cooldown and the uses are kept by the server script, so clicking faster or firing the tool's activation from a cheat never heals more.
Type-checked with luau-lsp strict against Roblox's API definitions on 5 November 2026. Not playtested in Studio yet: press Play and watch the Output window before you publish.
Prompt for RoCode
Make a healing potion Tool in StarterPack: a Handle part, and a server Script that heals 40 health on click with a 3 second cooldown, has 3 uses stored in a Uses attribute, and destroys the tool when it runs out.
On this page
How tools work
Everything in StarterPack is copied into each player's Backpack every time they spawn, and the Backpack is what the hotbar shows. When the player equips a tool (presses its number or taps it), Roblox moves it from the Backpack into their character and welds its Handle to the right hand. Unequipping moves it back.
| Name | What it is |
|---|---|
Activated | The player clicked or tapped while holding it. Fires on the server and the client. |
Deactivated | They let go of the click. |
Equipped / Unequipped | Taken out or put away. |
Enabled | While false, clicks do not fire Activated. |
RequiresHandle | Off for a tool with no part in the hand, such as a spell. |
CanBeDropped | Whether Backspace drops it on the ground. |
Grip | Where and at what angle the hand holds the Handle. |
TextureId and ToolTip | The hotbar icon and the text when hovering it. |
Step 1: Build the tool
- In the Explorer, hover over StarterPack, click + and insert a Tool. Name it
Potion. - Insert a Part into the Tool and rename it exactly
Handle. Make it small, about0.8, 1.2, 0.8. Leave Anchored off and untick CanCollide. - For more detail, add more parts inside the Tool and join each to the Handle with a WeldConstraint (Part0 the Handle, Part1 the extra part). Unanchored, unwelded parts fall off.
- Press Play, press 1 to equip it and look at the hand. If it sits wrong, stop and change the Tool's
Grip(orGripPosto move it,GripForwardandGripUpto turn it), then try again.
For a hotbar icon, upload an image and paste its ID into TextureId; otherwise the hotbar shows the tool's name. ToolTip is the hint shown when hovering the slot.
Step 2: A healing potion with uses
Select the Tool and add a number attribute named Uses set to 3 (Properties window, Attributes, +). Then insert a Script into the Tool named PotionScript:
-- Script inside the Potion Tool, named PotionScript.
-- Heals the holder on click, with a cooldown and a limited number of uses.
local tool = script.Parent :: Tool
local HEAL_AMOUNT = 40
local COOLDOWN_SECONDS = 3
local lastUse = 0
tool.Activated:Connect(function()
local now = os.clock()
if now - lastUse < COOLDOWN_SECONDS then
return
end
-- the tool is inside the character while it is held
local character = tool.Parent
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if not humanoid or humanoid.Health <= 0 or humanoid.Health >= humanoid.MaxHealth then
return -- nobody to heal, or already at full health: do not waste a use
end
local uses = tool:GetAttribute("Uses")
if typeof(uses) ~= "number" or uses <= 0 then
return
end
lastUse = now
humanoid.Health = math.min(humanoid.Health + HEAL_AMOUNT, humanoid.MaxHealth)
tool:SetAttribute("Uses", uses - 1)
tool.ToolTip = (uses - 1) .. " drinks left"
if uses - 1 <= 0 then
tool:Destroy()
end
end)
This is a server Script, so the heal and the use count are decided by the server: a cheater can fire the activation as fast as they like and still only heal once every 3 seconds. Because a fresh copy comes from StarterPack on every spawn, the player gets a full potion each life. To make it last across deaths, give it from the server instead, as in Step 4.
Step 3: A flashlight that turns on and off
A tool that toggles something is the same pattern with a state. Make a Tool named Flashlight with a Handle, put a SpotLight inside the Handle (untick its Enabled), and add this Script to the Tool:
-- Script inside the Flashlight Tool, named FlashlightScript.
local tool = script.Parent :: Tool
local handle = tool:WaitForChild("Handle") :: BasePart
local light = handle:WaitForChild("SpotLight") :: SpotLight
light.Enabled = false
tool.Activated:Connect(function()
light.Enabled = not light.Enabled
end)
tool.Unequipped:Connect(function()
light.Enabled = false -- off when put away
end)
Turn the SpotLight so it points the same way as the hand by changing its Face property, and raise Range and Brightness for a horror map. Every player sees each other's flashlights, because the server switches them.
Step 4: Give tools from the server
StarterPack gives a tool to everyone. For tools earned or bought, keep the original in ServerStorage, where players cannot reach it, and clone it into the player's Backpack from a server Script. Putting a second copy in StarterGear means they keep it after dying, because Roblox refills the Backpack from StarterPack and StarterGear on each spawn.
-- Script in ServerScriptService named GiveTools.
-- Gives a tool from ServerStorage.Tools to players who touch the GiveFlashlight part.
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local toolsFolder = ServerStorage:WaitForChild("Tools")
local pad = workspace:WaitForChild("GiveFlashlight") :: BasePart
local function giveTool(player: Player, toolName: string, keepAfterDeath: boolean)
local template = toolsFolder:FindFirstChild(toolName)
if not (template and template:IsA("Tool")) then
warn("[GiveTools] no Tool named " .. toolName .. " in ServerStorage.Tools")
return
end
local backpack = player:FindFirstChildOfClass("Backpack")
local character = player.Character
local alreadyHas = (backpack and backpack:FindFirstChild(toolName)) or (character and character:FindFirstChild(toolName))
if alreadyHas or not backpack then
return
end
template:Clone().Parent = backpack
local starterGear = player:FindFirstChild("StarterGear")
if keepAfterDeath and starterGear and not starterGear:FindFirstChild(toolName) then
template:Clone().Parent = starterGear
end
end
pad.Touched:Connect(function(hit: BasePart)
local character = hit.Parent
local player = if character and character:IsA("Model") then Players:GetPlayerFromCharacter(character) else nil
if player then
giveTool(player, "Flashlight", true)
end
end)
Create a Folder named Tools in ServerStorage and move the Flashlight tool into it, then add a part named GiveFlashlight in Workspace. The check for an existing copy (in the Backpack, or in the character while held) stops one touch from filling the hotbar. The shop GUI guide uses the same giving function after a purchase, and the inventory guide manages many tools at once.
Step 5: Play an animation when used
A drink or a swing animation makes a tool feel finished. Animations on a player's own character are best started on their device, and they replicate to everyone. Add a LocalScript to the Tool:
-- LocalScript inside the Potion Tool, named PotionAnimation.
local tool = script.Parent :: Tool
local drinkAnimation = Instance.new("Animation")
drinkAnimation.AnimationId = "rbxassetid://0" -- your own animation ID
local track: AnimationTrack? = nil
tool.Equipped:Connect(function()
local character = tool.Parent
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
local animator = humanoid and humanoid:FindFirstChildOfClass("Animator")
if animator and drinkAnimation.AnimationId ~= "rbxassetid://0" then
track = animator:LoadAnimation(drinkAnimation)
end
end)
tool.Activated:Connect(function()
if track then
track:Play()
end
end)
tool.Unequipped:Connect(function()
if track then
track:Stop()
end
track = nil
end)
Make the animation in Studio's Animation Editor, publish it, and paste its ID. It must belong to you, or to your group for a group game; see Failed to load animation with sanitized ID if it does not play. The animation script guide covers priorities and looping.
Common errors and fixes
Open the Output window (Window menu, then Output) before you press Play.
The tool does not appear in my hand
The part is not named exactly Handle, or it is not a direct child of the Tool. If the tool should have nothing in the hand, untick RequiresHandle.
I cannot move while holding it
The Handle or another part of the tool is anchored. Untick Anchored on every part inside the tool.
Parts of the tool fall off
Extra parts are not welded to the Handle. Add a WeldConstraint from the Handle to each one.
Clicking does nothing
Check the Script is inside the Tool and is a Script, the Tool's Enabled is ticked, and ManualActivationOnly is off. Add print("activated") as the first line of the Activated handler.
Build it with RoCode
If you would rather not build tools by hand, RoCode can build them in the place you have open. RoCode is an independent AI agent for Roblox Studio, not made by Roblox: you describe the change in a web chat, and its Studio plugin creates the tool, its parts and its scripts in your Explorer.
Make a flashlight Tool in ServerStorage.Tools with a handle and a spot light that toggles on click and turns off when put away. Give it, kept after death, to players who touch the part named GiveFlashlight, checked on the server.
- Can look through your place first with Search Game, so it puts tools where your existing ones live
- Creates the Tool, its Handle and the light with Create Instance, and writes the scripts with Create Script
- Is told to compile-check each script it writes with Check Script
- Sets an undo point before and after each batch of changes, so Ctrl+Z steps back one batch at a time
Equip the tool yourself after it is built and check how it sits in the hand; adjust Grip if needed. With plugin 3.9.15 or newer RoCode can control a test character, but it checks only what it chose to test. How RoCode connects to Studio.
Questions
How do you make a tool in Roblox Studio?
Insert a Tool in StarterPack, add a part named Handle inside it (unanchored), and a Script inside the Tool that connects tool.Activated. Step 1 and Step 2 walk through it.
Should a tool script be a Script or a LocalScript?
A Script for anything that changes the game, such as healing or damage, because Activated fires on the server too. A LocalScript for things only the holder needs: aiming, animations, the mouse.
How do I give a player a tool with a script?
Clone it from ServerStorage into player.Backpack on the server. Also clone it into player.StarterGear if they should keep it after dying.
How do I make a tool with no handle?
Untick the Tool's RequiresHandle. Activated still fires when the player clicks while it is selected.
How do I stop players dropping a tool?
Untick CanBeDropped on the Tool. While it is ticked, Backspace drops the equipped tool into Workspace.
Sources and further reading
- Roblox Creator Docs: In-game tools. the Handle, StarterPack and tool scripts
- Roblox Creator Docs: Tool. Activated, Equipped, RequiresHandle, Grip and CanBeDropped
- Roblox Creator Docs: StarterGear
- Roblox Creator Docs: Backpack
How the code was checked: every script on this page passes Luau's strict type checker against Roblox's API definitions (luau-lsp, 5 November 2026). A type check catches misspelt APIs and wrong types, not game logic, so playtest in Studio before you publish.