ColorPane, a suite of color tools for Studio [v0.5.0]

Hello everyone, there are no updates in this post, but I wanted to let you know about a ColorPane integration I found. If you use the Tag Editor plugin, you can use ColorPane to edit tag colors if you have the API script injected.

This has actually been around for a while (since mid-May), but I just found out about it, and I wanted to let you know about it as well. :cookie:

3 Likes

I would just like you to know this is the most POLISHED (And probably the best) resource I have ever seen on this forum for the Year I have been here. Thank you.

2 Likes

Also could you explain more how to use the API? I’m creating a plugin and I would like to use this but I’m extremely confused.

1 Like

Sure. I’m not sure exactly what you want me to go into, but you can reply again if you still have questions that needs to be answered.

The ColorPane API is exposed through a ModuleScript in the CoreGui named ColorPane, so to get the API you would use something like require(game:GetService("CoreGui"):FindFirstChild("ColorPane")). If the user hasn’t injected the API, this script won’t exist, so you will need to keep that in mind.

If you want to get a color, you would use:

ColorPane.PromptForColor({
    PromptTitle = "Select a color", -- title bar text
    InitialColor = Color3.new(0.5, 0.5, 0.5), -- the starting color

    OnColorChanged = function(newColor)
        -- do something
    end,
})

PromptForColor returns a Promise, which allows you to do operations asynchronously. The Promise will get rejected when you provide invalid prompt options or if the color picker is already open, and it will resolve when the user presses the OK button.

OnColorChanged is called whenever the user changes the color (e.g. moving a slider, using the color wheel, editing the color hex, or picking a color from a palette). It should only be used for previewing color changes, and not for applying any color changes (e.g. setting waypoints with ChangeHistoryService). You should only apply colors when the Promise resolves.

ColorPane.PromptForColor({
    -- prompt options
}):andThen(function(newColor)
    -- user pressed the OK button, apply color changes
end, function()
    -- handle rejections
end):finally(function(status)
    -- most likely used for explicitly handling cancellations
end)

You can also get gradients by using PromptForColorSequence, where the prompt options are the same but use ColorSequences instead of Color3s.

You can use IsColorEditorOpen (or IsColorSequenceEditorOpen) to check if the prompts are currently being used.

If you keep the ColorPane API or Promises in stored somewhere (e.g. in variables or in state when using Roact or Rodux), you can use the ColorPane.Unloading event to know when to clean these up.

ColorPane.Unloading:Connect(function()
    -- clean up
end)

Here’s an example script that shows you the basics of using the API. The script lets you use ColorPane to edit the color of a TextButton when you click on it.

local ColorPane = ... -- the required API script

local textButton = ...
local textButtonLastColor = textButton.BackgroundColor3
local colorPaneUnloading

textButton.Activated:Connect(function()
    if (not ColorPane) then return end
    if (ColorPane.IsColorEditorOpen()) then return end

    ColorPane.PromptForColor({
        PromptTitle = "TextButton Color",
        InitialColor = textButtonLastColor,

        OnColorChanged = function(intermediateColor)
            -- preview colors
            textButton.BackgroundColor3 = intermediateColor
        end,
    }):andThen(function(newColor)
        -- apply the new color
        textButton.BackgroundColor3 = newColor
        textButtonLastColor = newColor
    end, function() end):finally(function(status)
        if (status == ColorPane.PromiseStatus.Cancelled) then -- ColorPane.PromiseStatus = Promise.Status
            -- user cancelled color picking, restore the original color
            textButton.BackgroundColor3 = textButtonLastColor
        end
    end)
end)

colorPaneUnloading = ColorPane.Unloading:Connect(function()
    colorPaneUnloading:Disconnect()
    colorPaneUnloading = nil

    ColorPane = nil
end)

If you’re not used to Promises, you can Promise.awaitStatus to turn it into a synchronous call, although in this example it won’t make too much of a difference.

textButton.Activated:Connect(function()
    if (not ColorPane) then return end
    if (ColorPane.IsColorEditorOpen()) then return end

    local status, newColor = ColorPane.PromptForColor(...):awaitStatus()

    if (status == ColorPane.PromiseStatus.Resolved) then
        -- apply the new color
        textButton.BackgroundColor3 = newColor
        textButtonLastColor = newColor
    elseif (status == ColorPane.PromiseStatus.Cancelled) then
        -- user cancelled color picking, restore the original color
        textButton.BackgroundColor3 = textButtonLastColor
    end
end)

(I haven’t tested this script, apologies if there are typos or it doesn’t work for some reason.)

2 Likes

Is there any way to export a gradient as a ColorSequence.new() that I can put in a script?

Unfortunately there isn’t any way to export a gradient. Sorry about that. I’ll consider adding a way to export them in a future version.

1 Like

Is ColorPane in CoreGui? I thought it was in PluginGui.

If you’re asking if the API script named ColorPane is in CoreGui and not in the plugin gui, then yes, the API script is in CoreGui. If you’re asking if the plugin guis are in CoreGui, then no, the plugin guis are in PluginGuiService. Sorry if I’m not understanding your question.

1 Like

Yeah, that was what I was asking because plugins usually don’t put their api scripts in Core gui.

A really neat feature I’d like to see added into the gradient editor is the ability to utilize gamma correction, or a different interpolation space, using that other module of yours.

In my eyes, the option would have 3 modes, “Off”, “Standard”, and “Ultra”, where “off” does nothing but stock Roblox interpolation and allows for all 20 keypoints. “Standard” would only allow 10 keypoints, and would reserve one hidden keypoint between each of the available 10 that adjusts the middle between the two editable keypoints appropriately (resulting in 19 keypoints on the sequence used). “Ultra” would allow only 8 keypoints, but have two hidden keypoints between each (resulting in all 20 keypoints on the sequence being used).

For most of my personal use cases, one keypoint between them is good enough to work with, but having the extra resolution could be useful.

Your thoughts on this?

1 Like

Cool plugin, can you give out a non plugin version, like a GUI and scripted and stuff and it will have rgb value inside the GUI ?
Bc I really needed one of these for a customize preference GUI for my plugin

I’ve been thinking about creating a version of ColorPane that has just the color picking components where you can integrate them into existing UI, but I haven’t really worked out any of the details on how that would work.

I may work on something like that in the future, but there aren’t any immediate plans to do so.

It sounds like an interesting idea, and it doesn’t seem too complicated to add into the plugin. I’ll consider adding such a feature in a future version.

1 Like

Hello everyone, ColorPane has been updated to v0.3.1. This is a very small update which fixes a single bug:

  • Fixed a bug where trying to use the scroll wheel on a dropdown selector (e.g. slider or palette pickers) resulted in a blank page

If you don’t know what this update is talking about, there is a shortcut where you can use the scroll wheel to switch between sliders and palettes instead of having to open the dropdown. Here’s a video (scroll wheel not included):

Technical information about the bug

As far as I can tell, sometime between v0.3.0 and v0.3.1 there was an update where the Z component of an InputObject’s Position was changed from -1 or 1 to -0.5 or 0.5. The original dropdown UI code relied on this value being -1 or 1, so the change broke scroll wheel functionality.

Apologies for the lack of new stuff in this update. Unless there are new bugs discovered or reported, the next version should be a feature update.


In other news, we recently passed 300 sales! It means a lot to know that so many people have tried out ColorPane. Thank you for using the plugin, and happy holidays!

:christmas_tree: :cookie:

3 Likes

Thanks for making this available to the community! I am interested in using this as part of a plugin, as it appears Roblox Studio does not provide color picker functionality for plugin authors. I’ve seen a lot of Roblox devs asking for this feature, so I imagine yours would be great for many of us.

How can I reference ColorPane from my plugin? I am OK with either compiling your code directly into mine or requiring the end user to have already downloaded your plugin and referencing it that way. I tried both and failed.

Reference Github Sources
When I cloned your repo from github and referenced it from my script, I get all sorts of errors relating to not being able to find referenced .lua files. Specifically, the folders under your ‘include’ dir are empty - promises, roact, etc.

I could take some guesses at which repo/release/etc. to clone for each of those repos and try to manually plumb things in, but I’m guessing there is some procedure to do this automatically that I’m not aware of.

Reference Live Plugin
I am not familiar with how to reference an existing live plugin, so I guessed a few things - CoreGui:WaitForChild(…), PluginGuiService(…) - and haven’t yet been able to figure it out.

Thanks for your help!

To use the color pickers from another plugin, you need to use the ColorPane API, which requires having the plugin installed.

This API is only exposed after the user presses the Inject API button in the toolbar, or at start-up if the user has the specific setting enabled. If the user allows this, there will be a ModuleScript inserted into CoreGui named ColorPane which will contain the API. You can read this page for more information about how to inject and acquire the API, and this page for the API reference.

You don’t need to compile any code unless you want to contribute to the plugin’s development. Hope this helps!

1 Like

Thank you! This helped me better understand what “Inject API” means and I was able to get the color picker to pop up from my plugin. Success!

One note to other “promise-newbies” like me: I had a hard time figuring out how to determine if the user had pressed the “Cancel” button on ColorPane. This is what I ended up with to detect cancellation:

        promise
            :andThen(
                function(newColor)
                    -- This never seems to get triggered.  Don't know why... 
                    -- ... but it's not important because we get notified in PromptOptions::OnColorChanged
                    print("Promise finished with status=" .. tostring(promise:getStatus()))
                end,
                function(errorObject)
                    error("Caught promise error: " .. tostring(errorObject))
                end)
            :doneCall(
                function()
                    local promiseStatus = promise:getStatus()
                    if (promiseStatus == "Cancelled") then
                        print("User cancelled color selection")
                    end
                end)
            :catch(
                function(errorObject)
                    error("Promise catch block entered: " .. tostring(errorObject))
                end)

Can you color a specific face on the part?

No, but as far as I know you can’t color individual faces of Parts anyway. This plugin doesn’t add building utilities like the one you’re describing, it adds ways for designers to choose colors for their projects.

1 Like

This looks pretty cool, I wanted to try this out myself at one point but I couldn’t figure out the math.

Anyway, is there any chance of a built-in module that just calculates the colors with the UI? This would make it easier for integration with games, where a localscript can just call a function in a modulescript, passing in a folder which contains the UI, and gets the Color3 as a response.