This is a remake of my older post about how to make plugins:
The older post is not exactly outdated and still can be used if you find it easier. However, it only shows how to make plugins without explaining how exactly they work and other essential stuff.
Note that this guide is based of my personal experience while working with plugins. If you find any mistakes or have something to add, please write that in the reply to the post!
Additionally, you can follow roblox’s official guide on how to make plugins.
Post Content:
- About Plugins
1.1 What is a plugin?
1.2 How plugins are made in general - Plugins essentials
- Testing your plugin
- Making an example plugin
3.1 “Hello World” plugin
3.2 Adding toolbar buttons to plugin
3.3 Adding UI to plugin
3.3.1 Normal UI
3.3.2 Widget UI
3.3.3 UI Frameworks
3.4 Publishing plugin - Making a paid plugin
- More plugin’s features you can use
- Services useful for plugins
1. About Plugins
What is a plugin?
As Roblox documentation states, plugin is a custom add-on to Studio which adds new behavior and features that are not normally included.
Personally I understand plugin as a roblox model/script that is being run behind the scenes in the studio. That means if you created a script that prints “Hello World” in ServerScriptService or as a plugin, they’d behave exactly the same. The only difference is that plugin has access to services that normal scripts in games can’t access, such as the Selection service.
How plugins are made in general?
As I stated above, plugin is just a roblox model/script with practically exact same behaviour. You make plugins the same way you’d script something, but you have to store your code in 1 model/script.
2. Plugins Essentials
When making plugins you will mostly use these 2 globals and 1 service that can be accessed only by plugin scripts:
-
plugin - is a reference to your plugin object. Provides you with various functions to work with user’s studio environment. NOTE -
plugin
global can’t be accessed inModuleScript
s the normal way, you’ll have to pass it in there manually fromScript/LocalScript
. - DockWidgetPluginGuiInfo - describes the look of widget UI
- ChangeHistoryService - Allows to implement Undo/Redo functionality for your plugin.
3. Testing your plugin
In order to test your plugin you, naturally, would need to run it. In order to do that you’ll need to save your model/script as a local plugin. Once that’s done, a roblox model file will be saved to your roblox local plugins folder, and the plugin will automatically run in your studio environment! To test your plugin again, you’ll have to save it as a local plugin once again, but make sure that the name is identical or else you will have a clone of your plugin!
In order to save your plugin locally: Right click on your roblox model/script in studio and press “Save as local plugin” and save it in your plugins folder.
The plugin will then automatically run in your studio environment.
However if you really want to change the name of the file, you’ll have to delete the older save of the plugin:
- Navigate to the PLUGINS tab in roblox studio and press “Plugins Folder” button.
- A folder on your PC will open up. Find the file of your plugin and delete it:
Alternatively, you can try and use PluginDebugService by enabling Plugin Debugging Enabled in Studio Settings, but I couldn’t figure out how to get it to work.
4. Making an example plugin
“Hello World” plugin
Let’s start off with trying to run the plugin itself. For that we’ll make a plugin that prints “Hello World” in the output when the plugin starts up (aka when studio environment starts up or plugin is loaded).
It is very simple. All we have to do is create a Script
. Since it already has print("Hello World")
by default, we won’t even have to write any code!
Now save the plugin locally following the 3. Testing your plugin
.
If you look at the output, you should see “Hello world!” printed in there:
It was really simple, right? We didn’t even need to write even a line of code! This should perfectly show you that plugins behave just like normal scripts!
Adding toolbar buttons to plugin
Now that we know how plugins work, it’s time to do something that only a plugin can!
Let’s create a toolbar button which allows us to give our plugin more functionality to user.
If you don’t know what toolbar buttons are, it’s those buttons you see for plugins in PLUGINS tab:
Before creating toolbar buttons, we will have to create a toolbar itself which is used to store those buttons. In order to do that, we will use plugin
’s CreateToolbar(name: string)
method.
Method arguments
- name argument determines the title of the toolbar, labeling the group of buttons contained within.
local toolbar = plugin:CreateToolbar("Script Inserter")
Then we can create a button using toolbar’s CreateButton(buttonId: string, tooltip: string, iconname: string, text: string)
method.
Method arguments
- buttonId is a unique button ID that can be seen only by scripts.
- tooltip determines the text that is displayed when the button is being hovered.
- iconname is the id of the button’s icon
-
text is a label below the button. If empty, then the value of
buttonId
argument will be used instead.
local scriptButton = toolbar:CreateButton("Insert Script", "Create an empty Script", "rbxassetid://4998267428")
local localScriptButton = toolbar:CreateButton("Insert LocalScript", "Create an empty LocalScript", "rbxassetid://16775265105")
When the viewport of the world is hidden, the plugins buttons will be deactivated and won’t be usable by user. However, since I’m making a plugin that inserts scripts in the explorer, thus nullifying the need in viewport, I’d like them remain clickable. To do that, I’ll have to set button’s ClickableWhenViewportHidden
property to true.
scriptButton.ClickableWhenViewportHidden = true
localScriptButton.ClickableWhenViewportHidden = true
Additionaly, when the plugin button is pressed, it becomes activated, making the background of the button darker until pressed again. While it’s nice, I’d like to get rid of it as my buttons don’t toggle anything. This can be done by using SetActive(active: bool)
method to deactivate the button right after it was pressed, using Click
event.
Normally, just putting SetActive(false)
into Click
event would be enough, but for some reason it doesn’t work and must be done like that instead:
local activated = false
button:SetActive(activated)
button.Click:Connect(function()
activated = not activated
button:SetActive(activated)
if activated then
activated = false
button:SetActive(activated)
end
end)
My theory is that SetActive()
is a toggable function, which means that it works only if the argument is the opposite to the current state of the button. I honestly have no idea why it’s like that but if you know a better way then please write that in the reply!
Anyways, now that we have a button it’s time to write it’s functionality, which once again can be done through the Click
event! There’s nothing much to say as you write functionality the same way you write it for games.
function initButton(button : PluginToolbarButton, scriptClass : string)
local activated = false
button:SetActive(activated)
button.Click:Connect(function()
activated = not activated
button:SetActive(activated)
if activated then
activated = false
button:SetActive(activated)
end
local newScript = Instance.new(scriptClass)
newScript.Parent = workspace
end)
end
initButton(scriptButton, "Script")
initButton(localScriptButton, "LocalScript")
While it’s cool and all, you can notice that Ctrl + Z
and Ctrl + Y
(or Undo/Redo buttons) don’t work properly if you’re adding something to the explorer. It can be a very big disturbance for users of our plugin and we wouldn’t want that!
This can be fixed with the use of ChangeHistoryService.
local recordId = ChangeHistoryService:TryBeginRecording("Insert Script") --From this moment on, everything we do will be recorded into Undo/Redo operation!
if not recordId then --It's important to make sure that recordId is returned, or recording won't finish! (because it never started in the first place)
--recordId might not have returned because of 2 reasons:
--1. The previous recording is still active
--2. User is play testing the game
local alreadyRecording = ChangeHistoryService:IsRecordingInProgress() --Checking if the previous recording is still active.
if alreadyRecording then --If yes, we must cancel previous recording!
ChangeHistoryService:FinishRecording("", Enum.FinishRecordingOperation.Cancel) --Cancelling previous recording
end
warn("Something went wrong! Please try again later or restart Roblox Studio!")
return --We must return either way, because recordId is nil!
end
local newScript = Instance.new(scriptClass)
newScript.Parent = workspace
ChangeHistoryService:FinishRecording(recordId, Enum.FinishRecordingOperation.Commit) --Finishing our recording
Ta-da! The plugin is now fully functional and can be published into the marketplace for 30$!!! (this is a joke please dont do that)
Adding UI to plugin
Normal UI
We can add our UI we make the usual way. Just put up your UI in StarterGui as you usually do.
Here’s my masterpiece:
Now put your Gui inside your plugin model/script.
In order to display our Gui, we must parent it to CoreGui
HOWEVER - you’ll need to make sure that the Gui won’t stay there after plugin is unloaded or experience is saved/published.
local toolbar = plugin:CreateToolbar("Script Inserter")
local pluginButton = toolbar:CreateButton("Open Menu", "", "rbxassetid://4998267428")
pluginButton.ClickableWhenViewportHidden = true
local menu = script:WaitForChild("Gui")
menu.Archivable = false --Making sure it won't be saved/published along with the experience
menu.Parent = game:GetService("CoreGui")
pluginButton.Click:Connect(function()
menu.Enabled = not menu.Enabled
end)
plugin.Unloading:Connect(function()
menu:Destroy()
end)
--Script your UI's functionality the same way you do in games...
This method is the most simple one, but is not recommended as you have to make sure that your Gui doesn’t interfere with user’s experience.
Widget UI
Widgets are those little menus you can see in studio:
They’re really nice! You can drag them, resize them… And roblox so generously allowed us to use those too! So you won’t need to script the drag and resize functionality on your own! Not only that, widget is automatically cleaned up when our plugin is unloaded!
It is very easy to make one, we just need to use plugin
’s CreateDockWidgetPluginGui(pluginGuiId : string,dockWidgetPluginGuiInfo : DockWidgetPluginGuiInfo)
method and DockWidgetPluginGuiInfo global’s new()
method to describe our widget look,
Plugin's method arguments
-
pluginGuild is a unique ID of our widget (does not determine widget’s label on top, use widget’s
Title
property for that). - dockWidgetPluginGuiInfo determines the look of our widget.
Global's method arguments
- InitialDockState (Enum.InitialDockState) determines if the widget will be floating or pinned to some side.
- InitialEnabled (bool) determines if the widget’s visibility is on by default.
-
InitialEnabledShouldOverrideRestore (bool) determines if widget’s
InitialEnabled
will ALWAYS determine widget’s visibility on load, or use the saved parameter from previous session. - FloatingXSize (number) default X size (in pixels) of widget if it’s state is floating.
- FloatingYSize (number) default Y size (in pixels) of widget if it’s state is floating.
- MinWidth (number) minimal X size (in pixels) the widget can take.
- MinHeight (number) minimal Y size (in pixels) the widget can take.
Widget is our new ScreenGui, so you’ll need to parent all of your UI components in there.
local widget = plugin:CreateDockWidgetPluginGui("Script Inserter", DockWidgetPluginGuiInfo.new(
Enum.InitialDockState.Float,
false,
true,
755,
317,
100,
100
))
widget.Title = "Script Inserter"
local menu = script:WaitForChild("Main"):Clone() --is a frame that contains the buttons
menu.Parent = widget
pluginButton.Click:Connect(function()
widget.Enabled = not widget.Enabled
end)
NOTE - your UI’s size will scale accordingly to widget, so if your frame’s size is {1, 0}, {1, 0}
, it will fill up the entire widget, not the screen of viewport!
UI Frameworks
There are some UI frameworks made by other people specifically for plugins UI! They can be used if you REALLY want to have the Roblox Studio’s UI style.
Some UI frameworks I know about:
I am not going to explain how to use them as it’s self-explanatory and the guide is not about them.
Publishing plugin
Publishing plugin is very simple as it’s the same as publishing your models on roblox toolbox!
-
Right click on your model/script and press “Publish as Plugin”
-
Set the “Title” and “Description” of your plugin and click “Save” button to publish it!
Ta-da! You published your plugin!
However, that doesn’t mean that your plugin is public.
-
Navigate to your creation dashboard plugin page and find your plugin in there. This is a page where you can edit your plugin’s page information if you need.
-
Scroll down and press
Distribute on Creator Store
and pressSave Changes
.
Ta-da! You published your plugin!
5. Making a paid plugin
Unfortunately, I am unable to show how to make paid plugins as my country is not supported by Creator Store despite meeting other criterias.
However do not fret, as roblox has an official guide on how to sell stuff on Creator Store: Sell on the Creator Store | Documentation - Roblox Creator Hub
6. More plugin’s features you can use
- You can use plugin:SetSetting() and plugin:GetSetting() methods to store data in your plugin, they work like attributes.
- You can use plugin:OpenScript() method to open a script in user’s experience.
- You can use plugin:OpenWikiPage() to open a wiki page on roblox’s devforum.
- You can use settings() global function to access user’s studio settings.
7. Services useful for plugins
- Selection - gives you ability to manipulate user’s selection.
- ScriptEditorService - used for interacting with ScriptDocument instances.
- StudioService - provides access to configuration of Roblox Studio, allows importing files from the user’s file system, and other miscellaneous information.
- LogService - allows you to read outputted text.
- InsertService - used to insert assets from the Roblox website, typically the LoadAsset() function.
- AssetService - a service that handles asset-related queries to the Roblox web API.
NOTE: there might be more services that can be useful by plugins. Some of the services (like LogService, InsertService and AssetService) can be also used in games.
I hope this post could help you in some way, bye!