Photobooth Plugin

Photobooth

logo

Photobooth is a plugin that allows you to capture images of the workspace or UI elements entirely in Roblox studio.

Notably, it features the ability to remove skyboxes/backgrounds from images and bindings to allow developers to write their own capture workflows.

Results are output as editable images stored as a mesh part’s texture.

Limitations

Photobooth has a couple of limitations specific to the skybox removal preset. For most users these will likely not be of significant impact, but I’m listing them here so people can see them before purchase.

General:

  • No capture can be larger than 1024 x 1024 since that’s the limit of editable images.
  • Photobooth can only be used during edit mode in studio. It cannot be used to capture anything during a studio play session.
  • The built-in upload feature is currently disabled. You can still upload, but you have to write code to do it yourself. Read more about this further down the post.

Skybox removal:

  • No atmosphere / fog support.
  • Anything that cannot be frozen in place on screen is not supported. For example:
    • Terrain grass.
    • Force-field material.
  • Certain configurations of color correction such as Brightness > 0 and / or Contrast < 0.
  • Retro color grading is highly recommended for best results, but not mandatory.

Bindings:

  • See the OS scaling section below

Warning: This plugin will cause the screen to flash when removing skyboxes. Those with photosensitive epilepsy are advised caution when using this plugin.

I have listed all these limitations because I know a non-free plugin is an investment. I want to be completely transparent about what this plugin can and cannot do before you buy it.

Bindings

This plugin can be used for automation purposes. An example use case might be capturing icons for all the inventory items in your game thereby allowing you to avoid using viewport frames which are more expensive than traditional images.

To use this feature open the viewer and in the settings menu toggle “Bindings” to true.

bindings_enabled

Roblox may prompt you for script injection permissions.

RobloxStudioBeta_bbMp0Ictpr

This will create a ModuleScript underneath ServerStorage which provides a typed interface that can be used to create automated capture workflows. Included are a couple of common template workflows to get you started.

For example:

local Photobooth = require(game.ServerStorage.PhotoboothBindings)

local capture = Photobooth.captureViewport(Rect.new(0, 0, 300, 300), "NoSkybox")
capture.Name = "Example"
capture.Parent = game.ServerStorage

OS scaling

With the advent of high resolution monitors many computers use scaling options built into their operating system to ensure that applications rendered on screen are not too small. Roblox however, always captures in full resolution leading to a number of UX problems.

Photobooth will attempt to resolve this issue automatically, but for the highest quality image when using bindings it is strongly recommended to use your monitor’s true resolution.

i.e. use scale 100% and the display resolution that matches your monitor.

Or on Mac:

Saving Captures as PNGs

If you want to save any of the plugin captures to your computer, you can do so by right clicking the exported mesh part and selecting “Export Selection”.

This will prompt you to export the mesh in .obj format which will include the texture of the mesh in .png format. Both the .obj and .mtl files can be discarded.

Uploading

This feature is currently disabled!

Uploading will be enabled in the future once Roblox provides the proper security tooling to allow creator store plugins to upload assets on your behalf. More detail from Roblox here.

For now, developers will have to write their own code to upload editable images.

local ATTRIBUTE_NAME = "UploadResult"

local AssetService = game:GetService("AssetService")
local SelectionService = game:GetService("SelectionService")

for _, selected in SelectionService:Get() do
	if selected:IsA("MeshPart") and not selected:GetAttribute(ATTRIBUTE_NAME) then
		local content = selected.TextureContent
		local object = content and content.Object

		if object and object:IsA("EditableImage") then
			local result, value = AssetService:CreateAssetAsync(object, Enum.AssetType.Image, {
				Name = selected.Name,
				Description = "",
				IsPackage = false,
			})

			if result == Enum.CreateAssetResult.Success then
				selected:SetAttribute(ATTRIBUTE_NAME, `rbxassetid://{value}`)
			end
		end
	end
end

When this feature is enabled this is what the upload process will look like:


Reviews

This is a brand new plugin and I think it offers a tool that has otherwise traditionally been locked behind 3rd party applications.

I have spent a lot of time ironing out bugs and issues, but if you find any I’d very much appreciate reaching out to me before jumping to leaving a negative review. If you’ve done that and I haven’t reasonably responded or given a good solution then go nuts!

53 Likes

Glad to see this is finally out! But it seems to be bugged for me currently making it unusable

image

2 Likes

Thank you for this report. I’m jumping right on it!

What is the context you’re capturing under? - Are you perhaps in team create?

Im just in studio not running a play test. Yes it is a team create enabled place

Okay, that’s likely the issue. I believe I can pretty easily fix that. Hold tight an update will come very soon.

Should be fixed now. Please update the plugin!

2 Likes

Alright i appreciate the speedy response. I just tried it out on a new baseplate without team create enabled and it works great, already one of my favorite plugins!

1 Like

The fix worked great for me too!
image

2 Likes

Awesome!

Just a reminder that as with regular editable images in a team create sessions your co-devs won’t be able to see the capture results since Roblox explicitly doesn’t allow the replication of editable images. You’d have to first upload the results and then use the asset id for them to see.

I myself have not yet tested this behavior so I could be completely wrong in this statement, but something to consider / be aware of.

Yeah that makes sense. We mainly just have a separate shared place with a bunch of assets for the main game, so replication is not really important in my case

This is actually amazing! Thank you EgoMoose!

Game changer for sure! Definitely getting it!

The lebron james of roblox. :sunny:

1 Like

Was looking for something like this a few days ago!! thanks for making this, extremely useful

Can you also release this on itch.io or somewhere else? I can’t really buy it from the Creator Store and would even consider donating more. This is so very well worth the price; it’s a great plugin.

2025 Best Plugin winner, no doubt

I don’t inherently have an issue with selling on another store front, but I have to read into Roblox’s ToS to make sure that’s okay. Beyond that I’ll prob also take some time to speak to other devs who have released on different marketplaces to field their thoughts.

I’m curious why the creator store isn’t an option for you? Is it unavailable in certain countries? Lack of payment options? etc…?

Lack of payment options basically, and I don’t really like purchasing from Creator Store itself.

Boatbomber released their Benchmark plugin on itch.io, you can go ahead and ask him for details if you wish. You can sell Plugins on other sources.

I’m not sure if I’m doing something wrong, but I get some error when I take a photo. Exporting the result mesh doesn’t appear to save a .png texture file either.


image

  20:15:40.365  Error: attempt to index nil with 'Parent'  -  Edit
  20:15:40.365  builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.Scheduler.Scheduler.forks.SchedulerHostConfig.default:117: 
------ Error caught by React ------
attempt to index nil with 'Parent'
------ Error caught by React ------
builtin_TextureGenerator.rbxm.TextureGenerator.Src.Components.ViewSelector:51
sabuiltin_VisualizationModes.rbxm.VisualizationModes.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1539 function mountMemo
builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.React.React.ReactHooks:178 function useMemo
builtin_TextureGenerator.rbxm.TextureGenerator.Src.Components.ViewSelector:37 function ViewSelector
sabuiltin_VisualizationModes.rbxm.VisualizationModes.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3134 function renderWithHooks
sabuiltin_VisualizationModes.rbxm.VisualizationModes.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:207 function renderWithHooks
sabuiltin_VisualizationModes.rbxm.VisualizationModes.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:1575 function mountIndeterminateComponent
sabuiltin_VisualizationModes.rbxm.VisualizationModes.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:3483 function beginWork
builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:245
builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1946
builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1834
builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1783
builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:919
builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:837
builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.Scheduler.Scheduler.Scheduler:304
builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.Scheduler.Scheduler.Scheduler:260
builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.Scheduler.Scheduler.forks.SchedulerHostConfig.default:81 function doWork
builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.Scheduler.Scheduler.forks.SchedulerHostConfig.default:104 function performWorkUntilDeadline
  -  Edit
  20:15:40.365  Stack Begin  -  Studio
  20:15:40.366  Script 'builtin_MaterialPicker.rbxm.MaterialPicker.Packages._Index.Scheduler.Scheduler.forks.SchedulerHostConfig.default', Line 117 - function performWorkUntilDeadline  -  Studio
  20:15:40.366  Stack End  -  Studio
1 Like

That error seems to be unrelated to the plugin. However, try first viewing the capture in the viewer then exporting. I believe this is a fincky thing on Roblox’s end that causes the texture of the mesh to register as empty until it’s actually needed by the engine/renderer.

Let me know if that fixes it which will give you a short-term fix and I’ll look towards a long-term solution.

1 Like