ai-behavior-trees-util…
Engine-neutral behavior tree and utility AI code for NPCs in any language: Blackboard, reactive composites, decorators and…
Roblox player characters: CharacterAdded lifecycle, Humanoid and HumanoidRootPart, R6, R15 and custom rigs, respawn and Tools. Use when a character script breaks after respawn, animations do not play or replicate, or sprint code fights the Humanoid. Not for hit validation
Claude Code
$ npx -y skills add gamedev-skills/awesome-gamedev-agent-skills --skill roblox-characters --agent claude-code
Codex
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill roblox-characters -a codex -y
Cursor
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill roblox-characters -a cursor -y
Gemini CLI
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill roblox-characters -a gemini-cli -y
GitHub Copilot
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill roblox-characters -a github-copilot -y
OpenCode
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill roblox-characters -a opencode -y
Windsurf
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill roblox-characters -a windsurf -y
name: roblox-characters description: > Roblox player characters: CharacterAdded lifecycle, Humanoid and HumanoidRootPart, R6, R15 and custom rigs, respawn and Tools. Use when a character script breaks after respawn, animations do not play or replicate, or sprint code fights the Humanoid. Not for hit validation (`roblox-networking`), forces and raycasts (`roblox-physics`) or cameras (`camera-systems`).
A `Player` is the durable identity; each `Character` is a replaceable session with its own references, connections, animation tracks, and cleanup. Most character bugs are one character's state leaking into the next.
1. **Read the character contract.** Avatar Settings (rig type, movement system), `StarterCharacter`, `StarterCharacterScripts`, `Players.CharacterAutoLoads`, `Workspace.PlayerCharacterDestroyBehavior`, the existing Animate or controller scripts, tools, tags, and collision groups. Extend what is there; do not add a second controller. 2. **Separate scopes.** Player-scope state survives respawn; character-scope state does not. Put each character's connections, tracks, and temporary instances in one cleanup scope. 3. **Bind existing and future characters.** Connect `CharacterAdded`, then bind `player.Character` if it already exists. On the server, do this for players already in `Players:GetPlayers()`. 4. **Resolve parts defensively.** `WaitForChild` with a timeout for `Humanoid`, the root part, and `Animator`; after every yield, check the character is still the current one before acting. 5. **Choose one movement owner per state.** Standard avatars use Humanoid movement or the Character Controller Library. Physical mechanics (dash, knockback, grapple) use an impulse or a constraint for their duration and hand control back cleanly. 6. **Own animation lifecycle.** Load through the rig's `Animator`, keep tracks and marker connections in the character scope, and stop them on cleanup. Markers drive presentation; any gameplay effect they trigger is validated on the server. 7. **Run the lifecycle check.** With the Studio MCP server connected, start play, respawn the player several times from `execute_luau` on the `Server` datamodel (`for _ = 1, 5 do player:LoadCharacterAsync() task.wait(1) end`), then read `get_console_output`: expect no errors and exactly one setup log per spawn. Without MCP, ask the user to reset five times in Test and once with two players in Server & Clients, and to report duplicated logs, stuck animations, or errors.
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local generation = 0
local connections: {RBXScriptConnection} = {}
local currentCharacter: Model? = nil
local function clearCharacter()
generation += 1
for _, connection in connections do connection:Disconnect() end
table.clear(connections)
currentCharacter = nil
end
local function bindCharacter(character: Model)
-- Guard before teardown: a stale call must not clear a binding that is already current.
if player.Character ~= character or currentCharacter == character then return end
clearCharacter()
currentCharacter = character
local thisGeneration = generation
local humanoid = character:WaitForChild("Humanoid", 10)
local root = character:WaitForChild("HumanoidRootPart", 10)
-- A respawn during WaitForChild bumps generation and makes this call stale.
if not humanoid or not root or generation ~= thisGeneration then return end
table.insert(connections, humanoid.Died:Connect(function()
if generation ~= thisGeneration then return end
setCharacterUiEnabled(false)
end))
attachCurrentCharacterSystems(character, humanoid, root)
end
player.CharacterRemoving:Connect(function(character)
if currentCharacter == character then clearCharacter() end
end)
player.CharacterAdded:Connect(bindCharacter)
if player.Character then task.defer(bindCharacter, player.Character) endUse the project's cleanup utility when one exists rather than introducing a framework for three connections. Server systems repeat this binding per `Player` and clear player-scope tables on `PlayerRemoving`.
local animation = Instance.new("Animation")
animation.AnimationId = "rbxassetid://1234567890"
local track = animator:LoadAnimation(animation)
local markerConnection = track:GetMarkerReachedSignal("Commit"):Connect(function(parameter)
playLocalSwingEffect(parameter) -- presentation only; the server validates any hit
end)
track:Play(0.1)
-- On character teardown:
markerConnection:Disconnect()
track:Stop(0.1)
animation:Destroy()Rigs without a `Humanoid` need an `AnimationController` with an `Animator`. `Humanoid:LoadAnimation()` is deprecated; always load through the `Animator`.
adapter; branch on `Humanoid.RigType` only where topology really differs.
custom rig contract and validate it at spawn.
a `LinearVelocity` constraint for sustained control (details in `roblox-physics`).
`InputAction`, `InputBinding`) instead of raw `UserInputService` hooks. Give your context a higher `Priority` (and `Sink`) than the default player contexts so it wins.
`ControllerManager`, extend its abilities and controllers. Layering `HumanoidStateType` changes on top of it fights the library.
<img src="docs/assets/awesome-gamedev-agent-skills-banner.png" width="820" alt="awesome-gamedev-agent-skills — game-dev skills for AI coding agents.
Engine-neutral behavior tree and utility AI code for NPCs in any language: Blackboard, reactive composites, decorators and…
Engine-neutral game audio technique: bus layout, volume sliders in decibels, loudness, ducking music under dialogue, adaptive…
Builds and tunes game cameras, engine-neutral with Godot and Cinemachine 3 mappings: 2D follow with deadzone and look-ahead,…
Plans, generates or sources, and validates consistent game art: style guides, sprites, pixel art, tilesets, icons and textures,…
Builds engine-neutral branching dialogue with Ink, Yarn Spinner or a small JSON graph runner: lines, choices, conditions,…
Designs engine-neutral enemy and NPC AI: picks FSM, behavior tree, utility or GOAP, and builds perception, steering and A*…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.