-
Notifications
You must be signed in to change notification settings - Fork 0
Quick Start
The fastest path to a working RBXStateMachine setup: one Entity module, one FSM module, one server bootstrap, one client bootstrap.
Important
This page is intentionally compact, but it still matches the current source. The framework module is ReplicatedStorage.Orchestrator in this repository's default Rojo mapping.
In one pass you will:
- boot
Orchestrator - create a demo part on the server
- wrap it in an Entity
- drive it with an FSM
- start ServiceManager on the client
- verify that the scheduler heartbeat is running
ReplicatedStorage/
βββ Orchestrator/
βββ Entity/
β βββ QuickStartEntity.luau
βββ StateMachine/
βββ QuickStartFSM.luau
ServerScriptService/
βββ Bootstrap.server.luau
StarterPlayerScripts/
βββ Bootstrap.client.luau
Create ReplicatedStorage/Entity/QuickStartEntity.luau:
local RunService = game:GetService("RunService")
return {
Name = "QuickStartEntity",
Mutable = true,
Schema = {
IsActive = { Type = "boolean", Default = false, Replicate = true },
SpinRate = { Type = "number", Default = 180, Replicate = true },
Tint = { Type = "Color3", Default = Color3.fromRGB(255, 255, 255), Replicate = true },
},
GetContext = function(self, params)
local instance = params.Context and params.Context.Instance
assert(instance and instance:IsA("BasePart"), "QuickStartEntity requires Context.Instance")
return {
Instance = instance,
}
end,
ApplyChanges = function(self, changes)
if not self.Instance then
return
end
if changes.Tint ~= nil then
self.Instance.Color = changes.Tint
end
if RunService:IsClient() and changes.IsActive ~= nil then
self.Instance.Material = changes.IsActive and Enum.Material.Neon or Enum.Material.SmoothPlastic
end
end,
}Create ReplicatedStorage/StateMachine/QuickStartFSM.luau:
return {
Name = "QuickStartFSM",
ValidStates = { "Idle", "Spin" },
InitialState = "Idle",
RegisterStates = function(self)
self:AddState("Idle", function(fsm)
local entity = fsm.Entity
entity.IsActive = false
entity.Tint = Color3.fromRGB(255, 170, 0)
entity:UpdateEntity()
fsm:ScheduleTransition(1, "Spin")
end, { "Spin" })
self:AddState("Spin", {
OnEnter = function(state, fsm)
local entity = fsm.Entity
entity.IsActive = true
entity.Tint = Color3.fromRGB(0, 255, 127)
entity:UpdateEntity()
end,
OnHeartbeat = function(state, fsm, dt)
local entity = fsm.Entity
local part = entity.Instance
if part then
part.CFrame *= CFrame.Angles(0, math.rad(entity.SpinRate or 180) * dt, 0)
end
end,
Timeout = 2,
OnTimeout = "Idle",
}, { "Idle" })
end,
}Create ServerScriptService/Bootstrap.server.luau:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Orchestrator = require(ReplicatedStorage:WaitForChild("Orchestrator"))
Orchestrator:RegisterComponents()
local part = Instance.new("Part")
part.Name = "QuickStartPart"
part.Anchored = true
part.Size = Vector3.new(4, 4, 4)
part.Position = Vector3.new(0, 5, 0)
part.Parent = workspace
local entity = Orchestrator.CreateEntity({
EntityClass = "QuickStartEntity",
EntityId = "QuickStartPart",
Context = {
Instance = part,
},
InitialData = {
SpinRate = 180,
},
})
assert(entity, "Entity creation failed")
local fsm = Orchestrator.CreateStateMachine({
StateMachineClass = "QuickStartFSM",
StateMachineId = "QuickStartPart_FSM",
Context = {
Entity = entity,
EntityId = "QuickStartPart",
},
InitialState = "Idle",
})
assert(fsm, "FSM creation failed")
print("[QuickStart] Server boot complete")-
RegisterComponents()initializes Logger, Factory, Scheduler, NetworkManager, and replication callbacks -
CreateEntity()registers a live entity instance inFactory.Registry -
CreateStateMachine()registers a live FSM instance and auto-starts it -
GlobalStateMachineHeartbeatruns through the scheduler and drives_Update(dt)for all active FSMs
Create StarterPlayerScripts/Bootstrap.client.luau:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Orchestrator = require(ReplicatedStorage:WaitForChild("Orchestrator", 30))
Orchestrator:RegisterComponents()
if RunService:IsStudio() then
local sm = Orchestrator:StartServiceManager()
sm.SwitchSubsystem("TASKS")
sm.SetContextMode("server")
end
print("[QuickStart] Client boot complete")This launches ServiceManager only in Studio, which is the safest default for development.
Server Factory Scheduler FSM Client ServiceManager
β β β β β β
βββ CreateEntity(QuickStartPart) βββββββ β β β
βββ CreateStateMachine(QuickStartPart_FSM) βββ β β β
β βββ Start({State="Idle"}) ββββββββββββββ β β
β β βββ GlobalStateMachineHeartbeat βββββββ β
β β β βββ Idle β Spin β Idle
βββ entity snapshot + replicated fields βββββββββββββββββββββββββββββββββββββββ β
β β β β βββ StartServiceManager() βββ
β β ββββββββββββββββββββββββββββββββββββββ inspect tasks ββββββ
Expected results:
- the part appears in
workspace - it idles for one second
- it spins for two seconds
- it repeats
- the client dashboard opens in Studio
Once the client dashboard opens:
You should see at least:
GlobalStateMachineHeartbeatServiceManagerBrainTick
If GlobalStateMachineHeartbeat is missing, your runtime did not finish booting correctly.
You should see:
QuickStartPart_FSM- current state toggling between
IdleandSpin - transition history growing over time
You should see:
QuickStartPartIsActiveSpinRateTint- incrementing version data as commits happen
You should see:
- current frame budget usage
- hot tasks
- hot FSMs
- GC and thread pool diagnostics
This is the single most important difference from many older snippets in the repo or wiki.
local fsm = Orchestrator.CreateStateMachine({
StateMachineClass = "QuickStartFSM",
StateMachineId = "QuickStartPart_FSM",
Context = { Entity = entity },
})The machine is already active unless you explicitly pass AutoStart = false.
For a fixed timed exit, use ScheduleTransition().
Use WaitSpan when you want a deliberate delayed re-entry into the same state, like the polling loop used in example/DoorStateMachineExample.luau.
The server commits state with UpdateEntity(). The client receives replicated deltas and runs ApplyChanges(changes) locally.
Make sure Rojo actually synced FSM/Orchestrator to ReplicatedStorage.Orchestrator.
Add Mutable = true to the entity definition.
Switch to:
sm.SetContextMode("server")so you are inspecting the authoritative server snapshot.
Check the following in order:
-
QuickStartFSMis inside a folder namedStateMachine -
Entity = entityis passed in FSM context -
GlobalStateMachineHeartbeatis visible in TASKS - no error is printed from
ApplyChangesorChangeState
If this minimal setup works, move immediately to:
- Getting Started for the full zero-to-running walkthrough
- Architecture for the full pipeline
- Examples for TrafficLight, Door, BehaviorTree, HFSM, and ServiceManager patterns
This page gives you the shortest working path; the rest of the wiki explains how to scale it.
Quick Links: Home Β· Quick Start Β· API Reference Β· Architecture Β· Examples Β· Glossary
Copyright: Β© 2026 RBXStateMachine contributors Β· Repository Β· License information