The easiest way to use StacyPilot is through the plugin. Press the plugin button and install the plugin. In Studio, open the Plugins section and click on StacyPilot. Click the Insert button to insert StacyPilot.
Alternatively, you can download the StacyPilot model directly and insert it into Workspace
No matter which method you choose, keep in mind that StacyPilot does NOT record anything by itself. You need to insert (or make) add-ons for the stuff you want to record (usually into the Addons folder)
Make sure to enable Studio Access to API Services in Game Settings Security
To start recording, simply press the "Start" button on the panel. When you're finished press the "Stop" button and wait a few seconds for everything to save. When filling out the recording name, you should only use letters and numbers
With the plugin: Open the plugin, put the recording name in the "Recording Name" field and press Insert.
Without the plugin: Copy this code into the Command Bar (View Command Bar) insert the recording name import("HERE") and press enter.
If you want to combine multiple recordings into one, you need to open the RecordingNames script, duplicate the example provided and change the names
The recording should now be visible on the panels
By default StacyPilot doesn't record anything. If you want to record something, you need to add or
make an add-on for it. Add-ons don't have to be in the "Addons" folder, but it's a nice way to keep
your game organised.
Below are some add-ons I made for my other projects.
Core
moduleThe core module contains functions responsible for recording, replaying and firing events:
- :StartRecording()
will start recording
- :StopRecording()
will stop the current recording
- :ChangeRecordingName(newName: string)
will change the name of the current/next
recording
- :IsRecording()
will return true if the core is currently recording
- :IsPlaying()
will return true if the core is currently replaying a recording
- :GetReplayData()
will return all data for the currently playing recording. Values
will be nil for pieces of data that have already been replayed
- :FilterData(data: {any}, module: string)
will return only data from that module
- :Record(module_name, ...)
will record all the arguments passed to it as data for
"module_name". Currently StacyPilot can record: numbers, strings, booleans, Color3s and Vector3s
(with more coming soon™️).
- :RegisterResponse(module_name, function)
will tell the core to run
function
when replaying some data for module_name
- :Play(...)
will start playback of recordings with names passed as parameters (for
example :Play("recording1", "recording2")
)
- :StopPlaying()
will stop the current playback
- .Events.PlaybackStarted(full_data)
is fired when replaying a recording, passes full
data for that recording
- .Events.PlaybackStopped()
is fired when replaying has stopped
- .Events.PlaybackTick(time_passed)
is fired every Heartbeat when replaying a
recording, passes the amount of seconds that have passed since the replaying started
- .Events.PlaybackTickWithData(time_passed, remaining_data)
is fired every Heartbeat
when replaying a recording, additionally passes the data that has not yet been replayed
- .Events.PlaybackData(this_data)
is fired whenever the core reaches a piece of data
and needs to run a function for it
- .Events.RecordingStarted
is fired when recording starts
- .Events.RecordingStopped
is fired when recording is stopped
Panels
moduleThe panels module contains functions resposible for displaying a playback on the default panels:
- :GetPixelsForTime(seconds: number)
allows you to get the amount of pixels the panels
expect for the amount of seconds passed. Useful for Positions and Sizes
-
:AddTrack(symbol: string, color: Color3, display_order: number, auto_scroll: boolean)
is used to add a Track to the Panel. There's a separator with a display order of 0, so anything with
higher display order will be below it
- Track:PopulateWithData({{Duration: number, Text: string, Time: number}})
is used to
easily show data on a track, you don't need to use it
-
There are also some other Track functions that I'll document soon, you can look at the cameras
add-on to see them
Let's say you want to make an addon to record your pyro. I'll assume that the code is not very complex and currently it looks something like this:
local pyroFolder = workspace.Fire
local clickDetector = script.Parent.ClickDetector
clickDetector.MouseClick:Connect(function()
for _, part in pyroFolder:GetChildren() do
part.ParticleEmitter.Enabled = true
end
end)
clickDetector.RightMouseClick:Connect(function()
for _, part in pyroFolder:GetChildren() do
part.ParticleEmitter.Enabled = false
end
end)
The first thing we need to do is include the Core module which is responsible for recording
local core = require(workspace.StacyPilot.Core)
Now for the actual recording part. Remember that StacyPilot shouldn't record results of actions, but their activators. So instead of telling it when every piece of fire went off, we should tell it that we pressed the "On" button. To keep the code clean, let's first move our on/off code to separate functions
local function turnOn()
for _, part in pyroFolder:GetChildren() do
part.ParticleEmitter.Enabled = true
end
end
local function turnOff()
for _, part in pyroFolder:GetChildren() do
part.ParticleEmitter.Enabled = false
end
end
Now, when the button is pressed, we will turn on the pyro and tell StacyPilot to record it. The core:Record() function needs at least 1 parameter: the name of the module that will be saved. In this case we'll use "Fire" but it could be anything. In a more professional scenario you should probably record all pyro as "Pyro" to improve save/load times
clickDetector.MouseClick:Connect(function()
turnOn()
core:Record("Fire", "On")
end)
clickDetector.RightMouseClick:Connect(function()
turnOff()
core:Record("Fire", "Off")
end)
Now StacyPilot can record when we activated or deactivated fire, but it can't replay it yet. To do that, we need to run the core:RegisterResponse() function which StacyPilot will run whenever it finds a piece of data from this module. The first parameter needs to be the same as in the :Record function ("Fire" in our case). The data below is all data passed into :Record packed into a table. In out case the first entry is either going to be "On" or "Off"
core:RegisterResponse("Fire", function(data)
local actionName = data[1]
if actionName == "On" then
turnOn()
elseif actionName == "Off" then
turnOff()
end
end)
And that's it! StacyPilot can now record your fire. Full code:
local core = require(workspace.StacyPilot.Core)
local pyroFolder = workspace.Fire
local clickDetector = script.Parent.ClickDetector
local function turnOn()
for _, part in pyroFolder:GetChildren() do
part.ParticleEmitter.Enabled = true
end
end
local function turnOff()
for _, part in pyroFolder:GetChildren() do
part.ParticleEmitter.Enabled = false
end
end
clickDetector.MouseClick:Connect(function()
turnOn()
core:Record("Fire", "On")
end)
clickDetector.RightMouseClick:Connect(function()
turnOff()
core:Record("Fire", "Off")
end)
core:RegisterResponse("Fire", function(data)
local actionName = data[1]
if actionName == "On" then
turnOn()
elseif actionName == "Off" then
turnOff()
end
end)
If you need more examples, you can look at the source code of the addons I made, which are available above
But let's say you also want to display when the fire is going to get turned on or off on the panels. To do that we need to use the Panels module:
local panels = require(workspace.StacyPilot.Panels)
Then we need to create a new track on the panels, in this example the track will be indicated by a fire emoji. It'll also have a brownish background, be placed below the separator and will scroll automatically
local track = panels:AddTrack("🔥", Color3.fromRGB(97, 65, 0), 1, true)
Now we will listen for when a replay starts, when it does, we will filter out the data so we only have data for the fire
core.Events.PlaybackStarted:Connect(function(data)
data = core:FilterData(data, "Fire")
...
Next we will transform the data a bit, we will only show the line when the fire is on and we will give the lines a slightly green background
...
local transformedData = {}
for i, fireData in data do
if fireData.Data[1] == "On" then
local nextData = next(data, i)
local duration = if data[nextData] then data[nextData].Time - fireData.Time else 2
table.insert(transformedData, {
Duration = duration,
Text = fireData.Data[1],
Time = fireData.Time,
BackgroundColor = Color3.fromRGB(0, 113, 26)
})
end
end
...
Finally, we'll tell the panels to display that data
...
track:PopulateWithData(transformedData)
end)
And now we will be able to see when the fire turns on and off. Full code:
local core = require(workspace.StacyPilot.Core)
local panels = require(workspace.StacyPilot.Panels)
local pyroFolder = workspace.Fire
local clickDetector = script.Parent.ClickDetector
local track = panels:AddTrack("🔥", Color3.fromRGB(97, 65, 0), 1, true)
local function turnOn()
for _, part in pyroFolder:GetChildren() do
part.ParticleEmitter.Enabled = true
end
end
local function turnOff()
for _, part in pyroFolder:GetChildren() do
part.ParticleEmitter.Enabled = false
end
end
clickDetector.MouseClick:Connect(function()
turnOn()
core:Record("Fire", "On")
end)
clickDetector.RightMouseClick:Connect(function()
turnOff()
core:Record("Fire", "Off")
end)
core:RegisterResponse("Fire", function(data)
local actionName = data[1]
if actionName == "On" then
turnOn()
elseif actionName == "Off" then
turnOff()
end
end)
core.Events.PlaybackStarted:Connect(function(data)
data = core:FilterData(data, "Fire")
local transformedData = {}
for i, fireData in data do
if fireData.Data[1] == "On" then
local nextData = next(data, i)
local duration = if data[nextData] then data[nextData].Time - fireData.Time else 2
table.insert(transformedData, {
Duration = duration,
Text = fireData.Data[1],
Time = fireData.Time,
BackgroundColor = Color3.fromRGB(0, 113, 26)
})
end
end
track:PopulateWithData(transformedData)
end)