[ ](https://github.com/Blupo/Color/edit/master/docs/index.md "Edit this page")

# Color¶

Color is a Roblox Luau library for color management and manipulation, inspired by [chroma.js](https://vis4.net/chromajs/).

## Installing¶

The module is available in the library [here](https://roblox.com/library/7933448750) if you want to install it using the Toolbox. You can also grab a [release](https://github.com/Blupo/Color/releases) from GitHub and install it manually.

If you know how to use [Rojo](https://rojo.space), you can build the latest code from the development branch to get the newest features. Keep in mind that this is **development code**, and things can break or change quickly.

The library has two parts: the Color module and the Gradient module. You can access them using `[Module].Color` and `[Module].Gradient`.

    local ColorLib = require(...)

    local Color = ColorLib.Color
    local Gradient = ColorLib.Gradient

## Conversions¶

Colors can be constructed from different [color types](https://blupo.github.io/Color/api/color/#color-types), including hex strings, HSB/L, and L*a*b*. You can use [`Color.from`](https://blupo.github.io/Color/api/color/#colorfrom) or `Color.from[ColorType]` (e.g. `Color.fromHex`).

There are also a few additional constructors:

  * [`Color.new`](https://blupo.github.io/Color/api/color/#colornew), which is equivalent to `Color3.new`
  * [`Color.random`](https://blupo.github.io/Color/api/color/#colorrandom) for making random colors
  * [`Color.gray`](https://blupo.github.io/Color/api/color/#colorgray) for making greyscale colors
  * [`Color.named`](https://blupo.github.io/Color/api/color/#colornamed) for referencing [CSS colors](https://www.w3.org/TR/2021/REC-css-color-3-20210805/#svg-color)

    local pink = Color.fromHex("#ff69b4")
    local blue = Color.from("HSB", 240, 1, 1)
    local yellow = Color.fromLab(0.97139, -0.21554, 0.94478)

    local newYeller = Color.fromBrickColor(BrickColor.new("New Yeller"))
    local white = Color.new(1, 1, 1) -- or Color.gray(1)

    local hotpink = Color.named("hotpink")

Likewise, you can also convert Colors to various color types, using [`Color.to`](https://blupo.github.io/Color/api/color/#colorto) or `Color.to[ColorType]` (e.g. `Color.toHex`). You can also get the RGB components of a color using [`Color.components`](https://blupo.github.io/Color/api/color/#colorcomponents).

    local blue = Color.new(0, 0, 1)

    print(blue:toHex()) --> "0000ff"
    print(blue:toHSB()) --> 240, 1, 1
    print(blue:to("Lab")) --> 0.32297, 0.79188, -1.07860

    print(blue:components()) --> 0, 0, 1

## Interpolation¶

Color interpolation in RGB (e.g. using `Color3.Lerp`) can result in grey or dark intermediate colors. This can be avoided by interpolating in a perceptually-uniform color space such as CIELAB or CIELUV, or by doing a "linear RGB" interpolation in XYZ. You can interpolate colors using [`Color.mix`](https://blupo.github.io/Color/api/color/#colormix).

    local red = Color.named("red")
    local aqua = Color.named("aqua")

    red:mix(aqua, 0.5)
    red:mix(aqua, 0.5, "XYZ")
    red:mix(aqua, 0.5, "Lab")
    red:mix(aqua, 0.5, "Luv")

Here are images of what these interpolations look like:

## Miscellaneous¶

The library includes some general-purpose manipulation functions:

  * [`Color.invert`](https://blupo.github.io/Color/api/color/#colorinvert) for inverting colors
  * [`Color.brighten`](https://blupo.github.io/Color/api/color/#colorbrighten) and [`Color.darken`](https://blupo.github.io/Color/api/color/#colordarken) for making colors brighter or darker
  * [`Color.saturate`](https://blupo.github.io/Color/api/color/#colorsaturate) and [`Color.desaturate`](https://blupo.github.io/Color/api/color/#colordesaturate) for (de)saturating colors
  * [`Color.blend`](https://blupo.github.io/Color/api/color/#colorblend) for blending colors

It also includes some functions which can be used for accessibility:

  * [`Color.luminance`](https://blupo.github.io/Color/api/color/#colorluminance) for calculating the relative luminance of a color
  * [`Color.contrast`](https://blupo.github.io/Color/api/color/#colorcontrast) for calculating the contrast ratio between colors
  * [`Color.bestContrastingColor`](https://blupo.github.io/Color/api/color/#colorbestcontrastingcolor) for determining the color with the highest contrast ratio

There are also functions that don't fall into a general category:

  * [`Color.deltaE`](https://blupo.github.io/Color/api/color/#colordeltae) for calculating the difference between colors
  * [`Color.harmonies`](https://blupo.github.io/Color/api/color/#colorharmonies) for calculating harmonious colors

## Gradients¶

Gradients are similar in construction and behaviour to ColorSequences. They can be used to generate intermediate colors or ColorSequences so that they can be used in places where they're required, such as ParticleEmitters or UIGradients.

A Gradient can be constructed using an array of "gradient keypoints", which is just a dictionary with a `Time` and `Color` field, similar to the `Time` and `Value` fields of a [ColorSequenceKeypoint](https://developer.roblox.com/api-reference/datatype/ColorSequenceKeypoint). The constructor for this method is [`Gradient.new`](https://blupo.github.io/Color/api/gradient/#gradientnew).

    local keypoints = {
        {Time = 0, Color = Color.grey(0)},
        {Time = 0.25, Color = Color.grey(0.5)},
        {Time = 1, Color = Color.grey(1)}

    local gradient = Gradient.new(keypoints)

You can also construct a Gradient with a list of Colors using [`Gradient.fromColors`](https://blupo.github.io/Color/api/gradient/#gradientfromcolors). This creates a gradient where the colors are equidistant from each other.

    local gradient = Gradient.fromColors(
        Color.named("red"),
        Color.named("green"),
        Color.named("blue")
    )

Finally, the constructor [`Gradient.fromColorSequence`](https://blupo.github.io/Color/api/gradient/#gradientfromcolorsequence) creates a gradient from a ColorSequence.

    local cs = ColorSequence.new(
        Color3.new(0, 0, 0),
        Color3.new(1, 1, 1)
    )

    local gradient = Gradient.fromColorSequence(cs)

Generating colors from a gradient is similar to mixing colors, using [`Gradient.color`](https://blupo.github.io/Color/api/gradient/#gradientcolor). If you need a list of colors, you can use [`Gradient.colors`](https://blupo.github.io/Color/api/gradient/#gradientcolors). If you need a ColorSequence, you can use [`Gradient.colorSequence`](https://blupo.github.io/Color/api/gradient/#gradientcolorsequence).

    local gradient = Gradient.fromColors(
        Color.named("red"),
        Color.named("green"),
        Color.named("blue")
    )

    print(gradient:color(0.6, "XYZ"):toHex()) --> "00737c"
    print(gradient:color(0.6, "HSB", "Increasing"):to("Hex")) --> "00993d"

    -- generates a list of 50 equidistant colors on the gradient
    gradient:colors(50, "XYZ")

    -- generates a ColorSequence using the maximum number of keypoints (currently 20)
    gradient:colorSequence(nil, "XYZ")


[ ](https://github.com/Blupo/ColorPane/edit/develop/docs/user-guide/tips.md "Edit this page") [ ](https://github.com/Blupo/ColorPane/raw/develop/docs/user-guide/tips.md "View source of this page")

# Tips and Tricks¶

## Color Editor¶

### Page Pickers¶

  * On the Slider and Palette sections, you can use the scroll wheel with the mouse hovering over the dropdown button to quickly switch between pages.

### Palettes¶

  * If you have a color selected, you can use the `Up`, `Down`, `Left`, or `Right` keys to select a different color, and you can hold down the key to change selections faster.
  * You can skip the confirmation screen to delete a palette if you hold down the `Shift` key before you click the _Delete_ option.
  * If you prefer to name palettes _after_ you create them, there is an option in the [Settings](https://blupo.github.io/ColorPane/0.5/user-guide/settings/) that lets you create palettes without naming them. They will have the default name _New Palette_.

## Gradient Editor¶

  * If you have a keypoint selected, you can use the `Left` or `Right` arrow keys to select a different keypoint.
  * You can right-click on a keypoint to delete it instead of having to use the  button.


[ ](https://github.com/Blupo/ColorPane/edit/develop/docs/user-guide/settings.md "Edit this page") [ ](https://github.com/Blupo/ColorPane/raw/develop/docs/user-guide/settings.md "View source of this page")

# Settings

Note

Settings can only be modified if you have the Companion plugin installed.

This page explains the various options in the Settings window, in the order that they appear.

## ColorPane Settings¶

These settings apply to all instances of ColorPane.

  * _Name palettes before creating them_ : If enabled, you will have the opportunity to change a palette's name _before_ you create it. If not, you can only do that _after_ the palette is created.
  * _Gradient keypoint snap %_ : The [gradient editor's](https://blupo.github.io/ColorPane/0.5/user-guide/gradient-editor/) keypoint snap value.

## Companion Settings¶

These settings only apply to the Companion plugin itself.

  * _Automatically load the Roblox API data for Color Properties on startup_ : Used in [Color Properties](https://blupo.github.io/ColorPane/0.5/user-guide/color-properties/). If enabled, the plugin will automatically load Roblox API data, which lets you use Color Properties without having to manually activate it.
  * _Cache Roblox API data for use during testing sessions_ : Used in Color Properties. If enabled, Roblox API data will be saved to plugin settings, which lets you use Color Properties while testing your games.

## Setting Controls¶

There are several buttons at the bottom of the settings page for settings management.

  * Import Settings: Allows you to restore backed-up settings information.
  * Export Settings: Allows you to back up your settings information.


[ ](https://github.com/Blupo/ColorPane/edit/develop/docs/changelog.md "Edit this page") [ ](https://github.com/Blupo/ColorPane/raw/develop/docs/changelog.md "View source of this page")

# Changelog

## [0.5.0] - 2024-08-13¶

### Added¶

  * Added partial translations for French (`fr`), Korean (`ko`), and Russian (`ru`)
  * Color editor: Added a dedicated "Set Color" button for colors in the palette list layout
  * Color editor: Added a random color button
  * Gradient editor: Added a "Reset" button for gradient precision
  * Companion: Added settings importing and exporting
  * API: Added `API.IsColorPromptAvailable` to check if calling `API.PromptForColor` will succeed or immediately reject (replaces `API.IsColorEditorOpen`)
  * API: Added `API.IsGradientPromptAvailable` to check if calling `API.PromptForGradient` will succeed or immediately reject (replaces `API.IsGradientEditorOpen`)

### Changed¶

  * Script injection is no longer a required plugin permission
  * Settings: Invalid palettes will no longer cause the entire list of palettes to be removed, just the invalid palettes
  * Color editor: Duplicating palettes with the same name will now create or increment a counter instead of naming it "Palette (1) (1) (1) ..."
  * Color Properties: Changing color properties now uses the [Recording API](https://devforum.roblox.com/t/2512500)
  * API: Promises from the API no longer cancel if the user closes the prompt, they will now instead reject with `PromptError.PromptCancelled`
  * API: For `GradientPromptOptions`, the type of `InitialGradient` and the value of `GradientType` are no longer required to match
  * API: For `ColorPromptOptions`, the type of `InitialColor` and the value of `ColorType` are no longer required to match
  * API: The `API.PromptError` enum has been re-named to `API.PromptRejection`
  * API: The `API.PromptForColor` Promise now rejects with `SameAsInitial` instead of `PromptCancelled` if the initial and new colors are the same
  * API: The `API.PromptForGradient` Promise now rejects with `SameAsInitial` instead of `PromptCancelled` if the initial and new gradients are the same
  * API: The color tools of ColorPane have been spun off into their own library, and the old method of using ColorPane will no longer work. Please read the Integration page of the documentation for details on the updated integration method.

### Fixed¶

  * API: `API.PromptForColorSequence` (deprecated) now returns a Promise as expected
  * API: Promises returned by `API.PromptForColor` will no longer reject when the initial and new colors are the same even though you didn't specify an initial color
  * API: Promises returned by `API.PromptForGradient` will no longer reject when the initial and new gradients are the same even though you didn't specify an initial gradient

### Deprecated¶

  * API: `API.IsColorEditorOpen` is now deprecated, please use `API.IsColorPromptAvailable` for new work
  * API: `API.IsGradientEditorOpen` is now deprecated, please use `API.IsGradientPromptAvailable` for new work
  * API: `API.PromptError` is now deprecated, please use `API.PromptRejection` for new work
  * API: `API.Unloading` is now deprecated, you should use your plugin's [Unloading](https://create.roblox.com/docs/reference/engine/classes/Plugin#Unloading) event instead
  * API: `API.GetVersion` is now deprecated

### Removed¶

  * Removed the first-time use plugin permissions warning
  * Automatic update-checking has been removed
  * Color editor: Removed the Copic color palette

## [0.4.1] - 2022-09-30¶

### Fixed¶

  * Fixed a bug where the HSL saturation and lightness sliders would only show a red hue (this is _purely_ a visual bug and did not affect color selection)

## [0.4.0] - 2022-04-19¶

### Added¶

  * Added `API.GetVersion` which allows external applications to check which version of the plugin is installed
  * Added `API.PromptForGradient` as a replacement for `API.PromptForColorSequence`, which can prompt for either [Gradients](https://blupo.github.io/Color/api/gradient/) or [ColorSequences](https://developer.roblox.com/api-reference/datatype/ColorSequence)
  * Added color interpolation controls and ColorSequence code exporting to the Gradient Editor
  * Added the Color Tools section where the Color Info page used to be
  * Added HWB, Lab, Luv, LCh(ab/uv), xyY, and XYZ to Color Info
  * A first-time use prompt will now appear informing the user that script injection is required for exporting palettes to ModuleScripts and the API
  * Added a warning in the export dialog that script injection is required for exporting palettes to ModuleScripts
  * Added a color sorter that uses CIEDE2000 in the Color Tools section
  * Added a Picular palette (idea from csqrl's [Picular plugin](https://devforum.roblox.com/t/914148))
  * Added a Gradient picker tool which allows users to pick colors from their gradients
  * Color Properties now shows the color type of the each property
  * Right-clicking on a property in Color Properties now shows a menu to view the property documentation
  * Mouse drag inputs now work outside of editor windows

### Changed¶

  * `API.PromptForColor` now allows for prompting either [Colors](https://blupo.github.io/Color/api/color/) or [Color3s](https://developer.roblox.com/api-reference/datatype/Color3)
  * Improved keypoint dragging behaviour in the Gradient Editor
  * Improved performance (probably)
  * `API.PromptForColor` and `API.PromptForGradient` now reject with PromptErrors instead of message strings
  * Checking for updates now gracefully handles errors
  * Checking for updates no longer does excess work if an update notice has already been shown
  * Changed the message when notifying the user that a new version is available
  * Moved the Color Variations palette to the Color Tools section
  * API injection is now automatically done at startup
  * Releases now contain binary (rbxm) files, so file size is reduced
  * Terrain material color properties were renamed to "[Material] Material" (e.g. "Asphalt Material") from "[Material] Color" (e.g. "Asphalt Color")

### Fixed¶

  * Exporting palettes now lists color components correctly (components were listed in the order R _BG_ instead of R _GB_)
  * Changing palettes now deselects the selected color
  * Changing palettes in the export dialog now correctly persists the export type
  * Scrollbars no longer interfere with mouse drag inputs

### Deprecated¶

  * `API.PromptForColorSequence` has been deprecated, please use `API.PromptForGradient` for new work
  * `API.IsColorSequenceEditorOpen` has been deprecated, please use `API.IsGradientEditorOpen` for new work

### Removed¶

  * The "_Preview color changes before applying them when using Color Properties_ " setting was removed

## [0.3.1] - 2021-12-09¶

### Fixed¶

  * 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

## [0.3.0] - 2021-07-21¶

### Added¶

  * Added the ability to import palettes from ModuleScripts, StringValues, JSON files, or URLs
  * Added the ability to export palettes as ModuleScripts or StringValues
  * Users will now be notified at startup if their version of ColorPane is out-of-date, with the option to disable this in the Settings
  * Added a palette showing variations of the selected color, including hues, shades, tints, and tones
  * Added a [Copic](https://copic.jp/en/) color palette
  * Holding down either Shift key when selecting the option to delete a palette will now bypass the confirmation dialog
  * Users can now use the arrow keys to traverse palettes when a color is selected, as well as switch between keypoints in the ColorSequence editor when one is selected
  * Setting data will now automatically save instead of only when the plugin is unloaded or when the Settings window is closed, with options to disable this or modify the interval in the Settings
  * Users now have the option to cache the Roblox API data so that Color Properties can be used during testing or offline with the "Cache Roblox API data" setting
  * Added a gradient palette
  * Added a toolbar button to summon the Gradient Editor
  * Added a setting to toggle previewing color changes before applying them when using Color Properties

### Fixed¶

  * Fixed a bug that occurred when the API script was modified while the API wasn't loaded
  * Fixed a bug where trying to use the scroll wheel on the palette page picker would break the palettes page if the user didn't have any User Palettes
  * Fixed a bug that occurred if Color Properties tried referencing an object property that existed in the API dump but didn't exist on the object, most likely because the Studio and API dump versions were mismatched
  * Fixed a bug that occurred when a text input was focused and destroyed due to a re-render

### Changed¶

  * Testing sessions (e.g. Play Solo) can no longer modify settings or write data to disk
  * Changed the behaviour for data writing when multiple Studio sessions are open
  * Modified some setting descriptions to more accurately reflect what they actually do
  * Changed the "Load API" toolbar button's text and description to more accurately reflect what it actually does
  * Color Properties now shows a notice if the selection has no color properties instead of showing a blank window
  * Several text inputs, mainly for color components, will now select their entire text when you focus on them
  * Palette search will now update as the search text changes and no longer requires the user to release the TextBox's focus
  * Text inputs will now respond to overflow text and changes to the cursor position
  * When adding a new color to a palette, the search query will reset and the new color will be selected
  * Changed the icons for the Color and Gradient Editor toolbar buttons
  * Differentiated the icon denoting a removal from a subtraction
  * Removed the 99 quick palette color limit
  * Settings will now visually indicate to the user if saving is disabled

## [0.2.1] - 2021-03-29¶

### Fixed¶

  * The Color Properties window no longer tries to load in testing modes
  * The Color Properties window will now show the loading screen if it is enabled on startup instead of being blank

## [0.2.0] - 2021-03-29¶

### Added¶

  * Added a Settings window
  * Integrated the functionality of ColorProps into ColorPane, with the option to automatically load the window at startup in the Settings
  * You can now view palettes in either a grid or list layout
  * Added a palette of [web colors](https://www.w3.org/TR/2020/WD-css-color-4-20201112/#named-colors)
  * Added sections to the palette list to distinguish between built-in and user-created palettes
  * Added an editor page that lets you copy/paste between different color types

### Changed¶

  * API loading is no longer occurs at startup by default, the user must now explicitly load it or set the option to automatically load it in the Settings
  * Color Properties: You can now click anywhere inside a property list item to edit the color, not just on the item's color indicator
  * Changed the behaviour of the palette grid double-click shortcut: clicking on the color at any time after it has been selected will set the current color, not just within the amount of time that would be considered a "double click"
  * When searching for a palette color, if the selected color is included in the filtered list, it will now stay selected instead of being deselected
  * You will now be asked to input a name _before_ creating new palettes, with the option to disable this in the Settings
  * The palette naming prompt will now show you what the actual new name will be if the inputted name is already being used

### Fixed¶

  * The titles of the editor windows now reset to an identifiable name once they are closed
  * Setting the initial prompt value when calling `PromptForColor` no longer causes `OnColorChanged` to be called
  * Improved the performance of multiple components, the effects of which will be particularly noticable when resizing editor windows or using the palettes page
  * The editor page bar in the color editor window now correctly highlights the currently-chosen editor page
  * Editor pages in the color editor now have the proper minimum width, previously the calculations did not take padding into account and ended up making them slightly smaller than the minimum
  * Fixed improper behaviour in the color wheel due to some misplaced code: the color value should have updated when the left mouse button was pressed down on the saturation-brightness square, however it occurred when the mouse button was released instead
  * If you close the Color Properties window while editing a property, the color editor window(s) should now close

### Removed¶

  * Removed the undocumented `OpenColorEditor` function from the API
  * Removed the name restrictions on user-created palettes

## [0.1.2] - 2021-03-10¶

### Added¶

  * Added a toolbar button that lets the user attempt to drop the API script into CoreGui if it could not be done automatically
  * Added toolbar button icons
  * Added a warning when modifying the API script's Source

### Changed¶

  * Updated and fixed some documentation
  * Changed the name of the color editor toolbar button to "Color Editor" (from just "Editor")

### Removed¶

  * Removed the undocumented `OpenColorSequenceEditor` function from the API (`OpenColorEditor` will be removed in future update)

## [0.1.1] - 2021-03-09¶

### Changed¶

  * Now gracefully handles script injection

## [0.1.0] - 2021-03-09¶

### Added¶

  * ColorPane first release


[ ](https://github.com/Blupo/ColorPane/edit/develop/docs/developer-guide/api-reference.md "Edit this page") [ ](https://github.com/Blupo/ColorPane/raw/develop/docs/developer-guide/api-reference.md "View source of this page")

# ColorPane¶

Note

The pages in the Developer Guide are for plugin developers who want to integrate ColorPane in their projects. If you simply want to use the color tools, you're looking for the [the user guide](https://blupo.github.io/ColorPane/0.5/user-guide/color-editor/).

## Types¶

### ColorPromptOptions¶

    type ColorPromptOptions = {
        PromptTitle: string?,
        InitialColor: ([Color](https://blupo.github.io/Color/api/color/) | [Color3](https://create.roblox.com/docs/reference/engine/datatypes/Color3))?,
        ColorType: ("Color" | "Color3")?,
        OnColorChanged: ((([Color](https://blupo.github.io/Color/api/color/)) -> ()) | (([Color3](https://create.roblox.com/docs/reference/engine/datatypes/Color3)) -> ()))?

`ColorType` determines the type of value the Promise will resolve with, and the type of value passed to `OnColorChanged`.

### GradientPromptOptions¶

    type GradientPromptOptions = {
        PromptTitle: string?,
        InitialGradient: ([Gradient](https://blupo.github.io/Color/api/gradient/) | [ColorSequence](https://create.roblox.com/docs/reference/engine/datatypes/ColorSequence))?,
        InitialColorSpace: [MixableColorType](https://blupo.github.io/Color/api/color/#colormix)?,
        InitialHueAdjustment: [HueAdjustment](https://blupo.github.io/Color/api/color/#colormix)?,
        InitialPrecision: number?,
        GradientType: ("Gradient" | "ColorSequence")?,
        OnGradientChanged: ((([Gradient](https://blupo.github.io/Color/api/gradient/)) -> ()) | (([ColorSequence](https://create.roblox.com/docs/reference/engine/datatypes/ColorSequence)) -> ()))?

`GradientType` determines the type of value the Promise will resolve with, and the type of value passed to `OnGradientChanged`.

## Enums¶

### PromptRejection¶

        InvalidPromptOptions,
        PromptAlreadyOpen,
        ReservationProblem,
        PromptCancelled,
        SameAsInitial

  * `PromptRejection.InvalidPromptOptions`: One or more of the prompt configuration options was invalid (bad value, wrong type, etc.)
  * `PromptRejection.PromptAlreadyOpen`: The prompt you were trying to open is already open
  * `PromptRejection.ReservationProblem`: If you were trying to open the color prompt, then the gradient prompt is currently open. If you were trying to open the gradient prompt, the color prompt is currently open.
  * `PromptRejection.PromptCancelled`: The user closed the prompt without confirming a color/gradient
  * `PromptRejection.SameAsInitial`: If you provided an initial color/gradient value, the user confirmed the exact same value

### PromiseStatus¶

Same as [`Promise.Status`](https://eryn.io/roblox-lua-promise/api/Promise#Status).

        Started,
        Resolved,
        Rejected,
        Cancelled

## Functions¶

### IsColorPromptAvailable¶

    ColorPane.IsColorPromptAvailable(): boolean

Returns if a request to prompt for a color will succeed instead of immediately rejecting.

### IsGradientPromptAvailable¶

    ColorPane.IsGradientPromptAvailable(): boolean

Returns if a request to prompt for a gradient will succeed instead of immediately rejecting.

### PromptForColor¶

    ColorPane.PromptForColor(options: ColorPromptOptions?): Promise

Prompts the user for a color.

    local colorPromise = ColorPane.PromptForColor({
        PromptTitle = "Hello, world!",
        InitialColor = Color3.new(0.1, 0.2, 0.3),

        ColorType = "Color3",
        OnColorChanged = print,
    })

`OnColorChanged` must not yield. The specified `ColorType` and the type parameter to `OnColorChanged` should match, i.e.

  * `ColorType` is `"Color3"`, and `OnColorChanged` accepts a `Color3`, or
  * `ColorType` is `"Color"`, and `OnColorChanged` accepts a `Color`

but not

  * `ColorType` is `"Color3"`, and `OnColorChanged` accepts a `Color`, nor
  * `ColorType` is `"Color"`, and `OnColorChanged` accepts a `Color3`

### PromptForGradient¶

    ColorPane.PromptForGradient(options: GradientPromptOptions?): Promise

Prompts the user for a gradient.

    local gradientPromise = ColorPane.PromptForGradient({
        PromptTitle = "Hello, world!",
        InitialGradient = ColorSequence.new(Color3.new(0, 0, 0), Color3.new(1, 1, 1)),

        GradientType = "ColorSequence",
        OnGradientChanged = print,
    })

`OnGradientChanged` must not yield. The specified `GradientType` and the type parameter to `OnGradientChanged` should match, i.e.

  * `GradientType` is `"ColorSequence"`, and `OnGradientChanged` accepts a `ColorSequence`, or
  * `GradientType` is `"Gradient"`, and `OnGradientChanged` accepts a `Gradient`

but not

  * `GradientType` is `"ColorSequence"`, and `OnGradientChanged` accepts a `Gradient`, nor
  * `GradientType` is `"Gradient"`, and `OnGradientChanged` accepts a `ColorSequence`.


[ ](https://github.com/Blupo/ColorPane/edit/develop/docs/user-guide/color-editor.md "Edit this page") [ ](https://github.com/Blupo/ColorPane/raw/develop/docs/user-guide/color-rawor.md "View source of this page")

# The Color Editor¶

## Color Wheel¶

The buttons below the wheel let you select [color harmonies](https://en.wikipedia.org/wiki/Harmony_\(color\)), which will be marked on the wheel using squares, while the main color marker will be a circle.

## Sliders¶

The editor includes several sliders:

  * RGB
  * CMYK
  * HSB/L
  * Monochrome
  * Temperature

## Palettes¶

Warning

If you don't have the Companion plugin installed, you won't be able to create, edit, or import palettes.

Palettes let you store lists of colors. For most palettes, you will see (from top to bottom, left to right): a search bar, buttons to switch between grid or list layout, a button to add the current color to the palette, and the list of colors.

There are several built-in palettes, some of which have custom layouts:

  * BrickColors
  * ColorBrewer
  * Picular
  * Web Colors

The overflow menu (accessed using the  button) has several options such as creating new palettes, deleting existing palettes, and importing palettes.

### Layouts¶

The grid layout (pictured above) is the default layout, and allows for quick access to colors. Clicking on a color will select it, which then allows you to set the current color, remove the color, change its position in the palette, or rename it.

The list layout (pictured below) is useful for palettes where color names are important.

### Import and Export¶

Palettes can be imported and exported, for uses such as sharing them with collaborators or backing them up. You can access the import/export options from the overflow menu (the Export option does not appear for built-in palettes).

There are various ways to import palettes, but the UI will look similar for each method. After you extract the palette from the method you choose and it's in the [correct format](https://blupo.github.io/ColorPane/latest/developer-guide/palette-format/), the Import button will be enabled. You can also change the name of the palette before you import it, and the name input will be pre-filled with the name from the palette file/object.

Note

When importing via URL, you may be prompted by Studio to allow HTTP requests to the domain you're importing from.

Palettes can be exported as ModuleScripts or StringValues to ServerStorage, and the exported object will contain the JSON string for the palette (as well as some metadata for ModuleScripts).

Note

When exporting to a ModuleScript, you may be prompted by Studio to allow script injection.

Palettes cannot be exported to JSON files, as Studio does not have this capability. If you need a JSON file, you can copy the content of the JSON string into a file. For StringValue exports, you can copy the `Value` property. For ModuleScripts, copy the text inside the double-square-brackets (`[[...]]`).

### ColorBrewer Palette¶

[ColorBrewer](https://colorbrewer2.org) is a collection of color sets used in cartography. You can select the data type and number of classes, and the palette will display the various color sets that match the criteria.

### Picular Palette¶

[Picular](https://picular.co) is an online tool that lets you search "the color of anything". You can use the search bar to search for things you want the color of, e.g. "roblox". There is also a search history tab where you can view previous entries you have looked up.

## Color Tools¶

Various color tools are included, such as a color information tool, and a gradient picker.

### Color Info¶

The information tool shows the current color in different representations. You can copy text to paste somewhere else, and paste into the text boxes to change the current color (assuming what you paste follows the same format).

### Color Sorter¶

The sorter tool allows you to check how similar a list of colors is to a particular color, where the colors are listed from most to least similar after pressing Sort. The sorter uses [CIEDE2000](https://en.wikipedia.org/wiki/Color_difference#CIEDE2000).

### Color Variations¶

The variations tools shows various tints, tones, shades, and hue rotations of the current color, with an adjuster to change how many colors are shown.

### Gradient Pickers¶

The gradient pickers allow you to select a color from the different gradients in your gradient palette. Clicking anywhere on a gradient will set the current color to the color at that position. You can also click and drag to select colors as if it were a slider.

## Other Tools¶

The two colors in a large square at the bottom-left of the editor represent the current (top) and initial (bottom) colors. You can click on the initial color if you want to reset the current color. The hex input below it accepts either 3 (`ABC` = `AABBCC`) or 6 (`ABCDEF`) digits.

The list of colors to the right of the large square is the quick palette, and lets you temporarily store colors for quick access. You can add as many colors as you like, but you can't remove any colors. The number of colors that the quick palette displays depends on the size of the window (i.e. a larger window displays more colors).

The  button selects a random color.


[ ](https://github.com/Blupo/ColorPane/edit/develop/docs/developer-guide/api-reference.md "Edit this page") [ ](https://github.com/Blupo/ColorPane/raw/develop/docs/developer-guide/api-reference.md "View source of this page")

# ColorPane¶

Note

The pages in the Developer Guide are for plugin developers who want to integrate ColorPane in their projects. If you simply want to use the color tools, you're looking for the [the user guide](https://blupo.github.io/ColorPane/latest/user-guide/color-editor/).

## Types¶

### ColorPromptOptions¶

    type ColorPromptOptions = {
        PromptTitle: string?,
        InitialColor: ([Color](https://blupo.github.io/Color/api/color/) | [Color3](https://create.roblox.com/docs/reference/engine/datatypes/Color3))?,
        ColorType: ("Color" | "Color3")?,
        OnColorChanged: ((([Color](https://blupo.github.io/Color/api/color/)) -> ()) | (([Color3](https://create.roblox.com/docs/reference/engine/datatypes/Color3)) -> ()))?

`ColorType` determines the type of value the Promise will resolve with, and the type of value passed to `OnColorChanged`.

### GradientPromptOptions¶

    type GradientPromptOptions = {
        PromptTitle: string?,
        InitialGradient: ([Gradient](https://blupo.github.io/Color/api/gradient/) | [ColorSequence](https://create.roblox.com/docs/reference/engine/datatypes/ColorSequence))?,
        InitialColorSpace: [MixableColorType](https://blupo.github.io/Color/api/color/#colormix)?,
        InitialHueAdjustment: [HueAdjustment](https://blupo.github.io/Color/api/color/#colormix)?,
        InitialPrecision: number?,
        GradientType: ("Gradient" | "ColorSequence")?,
        OnGradientChanged: ((([Gradient](https://blupo.github.io/Color/api/gradient/)) -> ()) | (([ColorSequence](https://create.roblox.com/docs/reference/engine/datatypes/ColorSequence)) -> ()))?

`GradientType` determines the type of value the Promise will resolve with, and the type of value passed to `OnGradientChanged`.

## Enums¶

### PromptRejection¶

        InvalidPromptOptions,
        PromptAlreadyOpen,
        ReservationProblem,
        PromptCancelled,
        SameAsInitial

  * `PromptRejection.InvalidPromptOptions`: One or more of the prompt configuration options was invalid (bad value, wrong type, etc.)
  * `PromptRejection.PromptAlreadyOpen`: The prompt you were trying to open is already open
  * `PromptRejection.ReservationProblem`: If you were trying to open the color prompt, then the gradient prompt is currently open. If you were trying to open the gradient prompt, the color prompt is currently open.
  * `PromptRejection.PromptCancelled`: The user closed the prompt without confirming a color/gradient
  * `PromptRejection.SameAsInitial`: If you provided an initial color/gradient value, the user confirmed the exact same value

### PromiseStatus¶

Same as [`Promise.Status`](https://eryn.io/roblox-lua-promise/api/Promise#Status).

        Started,
        Resolved,
        Rejected,
        Cancelled

## Functions¶

### IsColorPromptAvailable¶

    ColorPane.IsColorPromptAvailable(): boolean

Returns if a request to prompt for a color will succeed instead of immediately rejecting.

### IsGradientPromptAvailable¶

    ColorPane.IsGradientPromptAvailable(): boolean

Returns if a request to prompt for a gradient will succeed instead of immediately rejecting.

### PromptForColor¶

    ColorPane.PromptForColor(options: ColorPromptOptions?): Promise

Prompts the user for a color.

    local colorPromise = ColorPane.PromptForColor({
        PromptTitle = "Hello, world!",
        InitialColor = Color3.new(0.1, 0.2, 0.3),

        ColorType = "Color3",
        OnColorChanged = print,
    })

`OnColorChanged` must not yield. The specified `ColorType` and the type parameter to `OnColorChanged` should match, i.e.

  * `ColorType` is `"Color3"`, and `OnColorChanged` accepts a `Color3`, or
  * `ColorType` is `"Color"`, and `OnColorChanged` accepts a `Color`

but not

  * `ColorType` is `"Color3"`, and `OnColorChanged` accepts a `Color`, nor
  * `ColorType` is `"Color"`, and `OnColorChanged` accepts a `Color3`

### PromptForGradient¶

    ColorPane.PromptForGradient(options: GradientPromptOptions?): Promise

Prompts the user for a gradient.

    local gradientPromise = ColorPane.PromptForGradient({
        PromptTitle = "Hello, world!",
        InitialGradient = ColorSequence.new(Color3.new(0, 0, 0), Color3.new(1, 1, 1)),

        GradientType = "ColorSequence",
        OnGradientChanged = print,
    })

`OnGradientChanged` must not yield. The specified `GradientType` and the type parameter to `OnGradientChanged` should match, i.e.

  * `GradientType` is `"ColorSequence"`, and `OnGradientChanged` accepts a `ColorSequence`, or
  * `GradientType` is `"Gradient"`, and `OnGradientChanged` accepts a `Gradient`

but not

  * `GradientType` is `"ColorSequence"`, and `OnGradientChanged` accepts a `Gradient`, nor
  * `GradientType` is `"Gradient"`, and `OnGradientChanged` accepts a `ColorSequence`.


[ ](https://github.com/Blupo/ColorPane/edit/develop/docs/user-guide/tips.md "Edit this page") [ ](https://github.com/Blupo/ColorPane/raw/develop/docs/user-guide/tips.md "View source of this page")

# Tips and Tricks¶

## Color Editor¶

### Page Pickers¶

  * On the Slider and Palette sections, you can use the scroll wheel with the mouse hovering over the dropdown button to quickly switch between pages.

### Palettes¶

  * If you have a color selected, you can use the `Up`, `Down`, `Left`, or `Right` keys to select a different color, and you can hold down the key to change selections faster.
  * You can skip the confirmation screen to delete a palette if you hold down the `Shift` key before you click the _Delete_ option.
  * If you prefer to name palettes _after_ you create them, there is an option in the [Settings](https://blupo.github.io/ColorPane/latest/user-guide/settings/) that lets you create palettes without naming them. They will have the default name _New Palette_.

## Gradient Editor¶

  * If you have a keypoint selected, you can use the `Left` or `Right` arrow keys to select a different keypoint.
  * You can right-click on a keypoint to delete it instead of having to use the  button.


[ ](https://github.com/Blupo/ColorPane/edit/develop/docs/user-guide/settings.md "Edit this page") [ ](https://github.com/Blupo/ColorPane/raw/develop/docs/user-guide/settings.md "View source of this page")

# Settings

Note

Settings can only be modified if you have the Companion plugin installed.

This page explains the various options in the Settings window, in the order that they appear.

## ColorPane Settings¶

These settings apply to all instances of ColorPane.

  * _Name palettes before creating them_ : If enabled, you will have the opportunity to change a palette's name _before_ you create it. If not, you can only do that _after_ the palette is created.
  * _Gradient keypoint snap %_ : The [gradient editor's](https://blupo.github.io/ColorPane/latest/user-guide/gradient-editor/) keypoint snap value.

## Companion Settings¶

These settings only apply to the Companion plugin itself.

  * _Automatically load the Roblox API data for Color Properties on startup_ : Used in [Color Properties](https://blupo.github.io/ColorPane/latest/user-guide/color-properties/). If enabled, the plugin will automatically load Roblox API data, which lets you use Color Properties without having to manually activate it.
  * _Cache Roblox API data for use during testing sessions_ : Used in Color Properties. If enabled, Roblox API data will be saved to plugin settings, which lets you use Color Properties while testing your games.

## Setting Controls¶

There are several buttons at the bottom of the settings page for settings management.

  * Import Settings: Allows you to restore backed-up settings information.
  * Export Settings: Allows you to back up your settings information.


[ ](https://github.com/Blupo/ColorPane/edit/develop/docs/developer-guide/integration.md "Edit this page") [ ](https://github.com/Blupo/ColorPane/raw/develop/docs/developer-guide/integration.md "View source of this page")

# Integration¶

Note

The pages in the Developer Guide are for plugin developers who want to integrate ColorPane in their projects. If you simply want to use the color tools, you're looking for the [the user guide](https://blupo.github.io/ColorPane/latest/user-guide/color-editor/).

First, you'll need to grab the module from the [Creator Store](https://create.roblox.com/store/asset/17844182825). If you use [Rojo](https://rojo.space), you can alternatively add the [GitHub repo](https://github.com/Blupo/ColorPane) as a submodule.

## Initialisation¶

Before we can start getting colors and gradients, we need to initialise the API. To do that, we'll simply call the function returned by the library script, which will give us the API.

    local ColorPaneInit = require(path.to.library)
    local ColorPane = ColorPaneInit(plugin, "MyProjectId")

The parameters for the initialisation function are (1) a [Plugin](https://create.roblox.com/docs/reference/engine/classes/Plugin) object and (2) a unique identifier, used to make sure each instance of ColorPane has its own plugin windows.

## Getting Colors¶

Note

Familiarity with the promise pattern, as well as the specific Promises from evaera's [roblox-lua-promise](https://eryn.io/roblox-lua-promise/) library, is recommended. While some explanation is given here, the additional reading may help you.

To prompt the user for colors, you will use [`PromptForColor`](https://blupo.github.io/ColorPane/latest/developer-guide/api-reference/#promptforcolor).

    local colorPromise = ColorPane.PromptForColor({
        PromptTitle = "Pick a color!"
        InitialColor = Color3.new(0.5, 0.5, 0.5),
    })

To customise the prompt, you can pass a table of options. The two options specified here are the most common. `PromptTitle` sets what the window text says, and `InitialColor` sets what color the user starts with (grey in this example).

The API will return a Promise. The basic idea is that a Promise represents a value that will be given _in the future_. That Promise will either be fulfilled (resolved), or broken (rejected). In this example, if the Promise resolves, it will resolve with a [Color3](https://create.roblox.com/docs/reference/engine/datatypes/Color3), and if it rejects, it will reject with an error object or message, depending on where the rejection came from.

We can attach callbacks onto the Promise to handle resolutions and rejections with `Promise:andThen()`.

    colorPromise
        :andThen(function(color)
            -- This function is called when the Promise resolves
        end, function(err)
            -- This function is called when the Promise rejects
        end)

The Promise may reject for a variety of reasons, including:

  * You passed some bad options into the function (e.g. setting `InitialColor` to a string)
  * The color editor is already open
  * The user decides to close the prompt without selecting a color

If you don't want or need to use the Promise pattern, you can use `Promise:await()` to turn it into a synchronous function (a yielding function, like [`task.wait`](https://create.roblox.com/docs/reference/engine/libraries/task#wait)). The function will return values in the same manner as [`pcall`](https://create.roblox.com/docs/reference/engine/globals/LuaGlobals#pcall): the first value tells you if the Promise resolved, and then any other values the Promise resolves/rejects with.

    local resolved, value = colorPromise:await()

    if (resolved) then
        -- do stuff with the color
    else
        -- do stuff with the error
    end

## Getting Gradients¶

The same rules for Promises apply here as they do for getting colors. To prompt the user for gradients, you'll use [`PromptForGradient`](https://blupo.github.io/ColorPane/latest/developer-guide/api-reference/#promptforgradient). The configuration options are slightly different here, and in this example, the Promise will resolve with a [ColorSequence](https://create.roblox.com/docs/reference/engine/datatypes/ColorSequence).

    local gradientPromise = ColorPane.PromptForGradient({
        PromptTitle = "Pick a gradient!",
        InitialGradient = ColorSequence.new(
            Color3.new(0, 0, 0),
            Color3.new(1, 1, 1)
        )
    })

    gradientPromise:andThen(function(gradient)
        -- resolved
    end, function(err)
        -- rejected
    end)

## Advanced¶

### Previewing Changes¶

An additional configuration option, `OnColorChanged` for [`PromptForColor`](https://blupo.github.io/ColorPane/latest/developer-guide/api-reference/#promptforcolor) and `OnGradientChanged` for [`PromptForGradient`](https://blupo.github.io/ColorPane/latest/developer-guide/api-reference/#promptforgradient), lets you "preview" color changes. This option is a callback that will be called every time the user makes a modification to the color or gradient. This is useful for letting the user see their changes before committing to them.

The callbacks you pass **must not** yield, meaning that you can't use [`task.wait()`](https://create.roblox.com/docs/reference/engine/libraries/task#wait), [`RBXScriptSignal:Wait()`](https://create.roblox.com/docs/reference/engine/datatypes/RBXScriptSignal#Wait), [`Instance:WaitForChild()`](https://create.roblox.com/docs/reference/engine/classes/Instance#WaitForChild) or any other function that yields or suspends a thread.

    ColorPane.PromptForColor({
        InitialColor = Color3.new(1, 1, 1),

        OnColorChanged = function(color)
            -- your code here
        end,
    })

    ColorPane.PromptForGradient({
        InitialGradient = ColorSequence.new(
            Color3.new(0, 0, 0),
            Color3.new(1, 1, 1)
        ),

        OnGradientChanged = function(gradient)
            -- your code here
        end,
    })

Warning

The values passed to `OnColorChanged`/`OnGradientChanged` are for **temporary use only**. If the user cancels color selection, anything you've changed with the preview colors should be changed back to their original values.

### Alternate Color Objects¶

If you're familiar with the [Color](https://blupo.github.io/Color/) library, the API also allows you to prompt for these types of colors instead of [Color3s](https://create.roblox.com/docs/reference/engine/datatypes/Color3) and [ColorSequences](https://create.roblox.com/docs/reference/engine/datatypes/ColorSequence). Note that this will also affect the types of the values passed to `OnColorChanged`/`OnGradientChanged`.

    ColorPane.PromptForColor({
        ColorType = "Color",
    })  -- Will resolve with a Color instead of a Color3

    ColorPane.PromptForGradient({
        GradientType = "Gradient",
    })  -- Will resolve with a Gradient instead of a ColorSequence

For Gradients, you can also specify the options used for generating intermediate colors:

    ColorPane.PromptForGradient({
        GradientType = "Gradient",
        InitialGradient = Gradient.fromColors(
            Color.new(0, 0, 0),
            Color.new(1, 1, 1)
        ),

        InitialColorSpace = "Lab",
        InitialHueAdjustment = "Longer",
        InitialPrecision = 0,
    })

## Plugin Permissions¶

ColorPane includes some functionality that requires certain plugin permissions. These permissions are not required, and the core functionality of ColorPane will still work without them. Your plugin itself, however, may need these permissions to work, and ColorPane will also be able to use them if granted.

  * Script injection
    * Exporting palettes into the DataModel as a ModuleScript
  * HTTP requests
    * The Picular palette sends HTTP requests to [backend.picular.co](https://backend.picular.co)
    * Importing palettes via URL, which can be from _any_ domain


[ ](https://github.com/Blupo/ColorPane/edit/develop/docs/developer-guide/palette-format.md "Edit this page") [ ](https://github.com/Blupo/ColorPane/raw/develop/docs/developer-guide/palette-format.md "View source of this page")

# Palette Format

When [importing](https://blupo.github.io/ColorPane/latest/user-guide/color-editor/#import-and-export) palettes, they must follow this JSON format:

        "name": "Palette Name",

        "colors": [
                "name": "Color Name",
                "color": [0, 0, 0]
            },

                "name": "Another Color Name",
                "color": [0.5, 0.5, 0.5]
            },

                "name": "Yet Another Color Name",
                "color": [1, 1, 1]

The color array of each color object is a 3-element array, with the elements representing the 3 sRGB channels, which typically range from [0, 1]. No two colors can share the same name, however any number of colors have have the same color array.

If importing from a ModuleScript, the palette can also be a Lua table in the same format, e.g.

        name = "Palette Name",

        colors = {
                name = "Color Name",
                color = {0, 0, 0}
            },

                name = "Another Color Name",
                color = {0.5, 0.5, 0.5}
            },

                name = "Yet Another Color Name",
                color = {1, 1, 1}


[ ](https://github.com/Blupo/ColorPane/edit/develop/docs/user-guide/gradient-editor.md "Edit this page") [ ](https://github.com/Blupo/ColorPane/raw/develop/docs/user-guide/gradient-rawor.md "View source of this page")

# The Gradient Editor¶

## Editing Keypoints¶

Keypoints can be added by clicking anywhere in the gradient view (as long as the cursor isn't snapped to another keypoint). Clicking on a keypoint will select it, which allows you to delete it, change its color or position, and use the left  or right  buttons (_not_ the arrow keys) to swap its color with the keypoint on the left or right, respectively. You can also change the position by dragging it around the gradient view.

## Other Controls¶

  * The  button reverses the order of the colors in the gradient
  * The _Snap_ input can be used to modify the interval at which keypoints snap
  * The Reset button resets the gradient to its initial value

The  button toggles showing the ColorSequence code for the gradient, if you wish to copy it. You'll probably have to increase the size of the window to view the whole code, but clicking on the text will select all of it, for quick copying.

## Gradient Palette¶

You can open the gradient palette using the  button. Similar to [color palettes](https://blupo.github.io/ColorPane/latest/user-guide/color-editor/#palettes), you can store gradients for later use. The first 3 gradients in the palette are built-in, so you cannot modify or delete them.

## Gradient Info¶

You can access gradient info with the  button. Editing gradient information is an advanced feature that allows you to create gradients with interpolation in different color spaces. The available options for the color space and hue interpolation are the same as those used in [Color.mix](https://blupo.github.io/Color/api/color/#colormix).

Increasing precision allows you to get a more visually-accurate gradient for the specified color space, but at the cost of the number of keypoints that you're allowed to insert.

For non-RGB color spaces, the precision should be at least 1, otherwise the gradient will not look any different from itself in RGB space. For RGB space, the precision should always be 0, since ColorSequences already use RGB interpolation.


[ ](https://github.com/Blupo/Color/edit/master/docs/api/color.md "Edit this page")

# Color

## Constructors¶

### Color.new¶

    Color.new(r: number, g: number, b: number): Color

Standard Color constructor. Arguments should be in the range [0, 1], similar to [Color3.new](https://developer.roblox.com/en-us/api-reference/datatype/Color3#constructors).

### Color.random¶

    Color.random(): Color

Creates a Color with random RGB components.

### Color.gray¶

    Color.gray(scale: number): Color

Creates an achromatic Color using the scale, which should be in the range [0, 1]. `0` corresponds to black, and `1` corresponds to white.

### Color.named¶

    Color.named(name: string): Color

Creates a Color based on a [named CSS color](https://www.w3.org/TR/2021/REC-css-color-3-20210805/#svg-color). Names are case-insensitive.

### Color.from¶

    Color.from(colorType: string, ...: any): Color

Creates a Color from various color types. See the Color Types section for the list of available conversions and what arguments they require.

Info

You can also use an alternative constructor using `Color.from[ColorType]` (e.g. `Color.fromColor3(...)` instead of `Color.from("Color3", ...)`), **except** for the `xyY` color type.

## Properties¶

### Color.R¶

    Color.R: number

The clipped red RGB channel of the color, in the range [0, 1].

### Color.G¶

    Color.G: number

The clipped green RGB channel of the color, in the range [0, 1].

### Color.B¶

    Color.B: number

The clipped blue RGB channel of the color, in the range [0, 1].

## Functions¶

### Color.isAColor¶

    Color.isAColor(color: any): boolean

Returns whether the provided value is a Color. Checks if the value is a table with the following properties:

  * The table is frozen
  * The table has keys `R`, `G`, `B`, `__r`, `__g`, `__b` with numeric values
  * The table has a `to` function

### Color.isClipped¶

    Color.isClipped(color: Color): boolean

Returns whether the Color's RGB components are clipped. Some conversions (e.g. XYZ to sRGB) may result in RGB components outside of the range [0, 1]. In this case, the components will be clipped to the range [0, 1].

    print(Color.new(1, 1, 1):isClipped()) --> false
    print(Color.new(2, 2, 2):isClipped()) --> true

### Color.unclippedEq¶

    Color.unclippedEq(refColor: Color, testColor: Color): boolean

Compares the unclipped components of the Colors for equality.

    print(Color.new(1, 1, 1) == Color.new(2, 2, 2)) --> true
    print(Color.new(1, 1, 1):unclippedEq(Color.new(2, 2, 2))) --> false

### Color.components¶

    Color.components(color: Color, unclipped: boolean? = false): (number, number, number)

Returns the RGB components of the Color, either clipped or unclipped.

You can also access the individual clipped components using Color.R, Color.G, and Color.B.

### Color.to¶

    Color.to(color: Color, colorType: string): ...any

Converts a Color to different formats. See the Color Types section for the list of available conversions and what values they output.

Info

You can also use an alternative converter using `Color.to[ColorType]`, e.g. `Color:toColor3()` instead of `Color:to("Color3")`.

### Color.invert¶

    Color.invert(color: Color): Color

Returns a Color with inverted RGB components.

### Color.mix¶

    Color.mix(startColor: Color, endColor: Color, ratio: number, mode: string? = "RGB", hueAdjustment: string? = "Shorter"): Color

Interpolates the start and end Colors in various color spaces. `ratio` should be in the range [0, 1]. Supported spaces are: `RGB` (default), `CMYK`, `HSB` (or `HSV`), `HWB`, `HSL`, `Lab`, `Luv`, `LChab` (or `LCh`), `LChuv`, `xyY`, and `XYZ` (`XYZ` interpolation can be used for linear RGB interpolation).

For color spaces with a hue component (e.g. HSB/L or LCh), there are different ways to interpolate the hue, and you can specify how it should be done by passing `hueAdjustment`: `Shorter` (default), `Longer`, `Increasing`, `Decreasing`, or `Specified`. These adjustments correspond to those specified in [CSS Color Module Level 4](https://www.w3.org/TR/css-color-4/#hue-interpolation).

Here are images of what the various interpolations look like, using red and aqua as example colors (with the default hue adjustment):

### Color.blend¶

    Color.blend(backgroundColor: Color, foregroundColor: Color, mode: string): Color

Blends the background and foreground Colors in various modes. The available blending modes are: `Normal`, `Multiply`, `Screen`, `Overlay`, `Darken`, `Lighten`, `ColorDodge`, `ColorBurn`, `HardLight`, `SoftLight`, `Difference`, and `Exclusion`. The blending modes correspond to those specified in [Compositing and Blending Level 1](https://www.w3.org/TR/2015/CR-compositing-1-20150113/#blendingseparable).

### Color.deltaE¶

    Color.deltaE(refColor: Color, testColor: Color, kL: number? = 1, kC: number? = 1, kH: number? = 1): number

Calculates the [color difference](https://en.wikipedia.org/wiki/Color_difference) of two Colors using [CIEDE2000](https://en.wikipedia.org/wiki/Color_difference#CIEDE2000), which can be used to compare the similarity (or difference) between colors. Smaller numbers correspond to greater similarity, while larger numbers correspond to less similarity.

### Color.luminance¶

    Color.luminance(color: Color): number

Returns the [relative luminance](https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef) of the Color.

### Color.contrast¶

    Color.contrast(refColor: Color, testColor: Color): number

Returns the [contrast ratio](https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef) between two Colors.

### Color.bestContrastingColor¶

    Color.bestContrastingColor(refColor: Color, ...: Color): (Color, number)

Returns the Color with the highest contrast ratio to the reference color, along with the contrast ratio itself.

### Color.brighten¶

    Color.brighten(color: Color, amount: number? = 1): Color

Brightens a Color by modifying its L* component.

### Color.darken¶

    Color.darken(color: Color, amount: number? = 1): Color

Equivalent to `Color.brighten(color, -amount)`.

### Color.saturate¶

    Color.saturate(color: Color, amount: number? = 1): Color

Saturates a Color by modifying its C* component.

### Color.desaturate¶

    Color.desaturate(color: Color, amount: number? = 1): Color

Equivalent to `Color.saturate(color, -amount)`.

### Color.harmonies¶

    Color.harmonies(color: Color, harmony: string, analogyAngle: number? = 60): array<Color>

Generates a list of Colors with a certain HSB [harmony](https://en.wikipedia.org/wiki/Harmony_\(color\)) to the reference Color. The available harmonies are: `Analogous`, `Complementary`, `SplitComplementary`, `Triadic`, `Tetradic` (sometimes known as _rectangle_), and `Square`.

You may also specify an angle for the `Analogous`, `SplitComplementary`, and `Tetradic` harmonies.

## Math Operations¶

### Color == Color¶

Comparing Colors with `==` returns whether their clipped RGB components are the same.

    print(Color.new(0, 0, 0) == Color.new(0, 0, 0)) --> true
    print(Color.new(0, 0, 0) == Color.new(1, 1, 1)) --> false
    print(Color.new(1, 1, 1) == Color.new(2, 2, 2)) --> true

## Color Types¶

### BrickColor¶

  * `color: BrickColor`

### Color3¶

  * `color: Color3`

### Hex¶

  * `hex: string`

The hex string can be in the format `ABC` or `AABBCC`, with or without a leading `#`.

### Number¶

  * `color: number` [0, 16777215]

### RGB¶

  * `r: number` [0, 255]
  * `g: number` [0, 255]
  * `b: number` [0, 255]

### HSB¶

  * `h: number` [0, 360) or NaN
  * `s: number` [0, 1]
  * `b: number` [0, 1]

For an explanation on HSB, you can read the [Wikipedia article](https://en.wikipedia.org/wiki/HSL_and_HSV) on it.

### HSV¶

Alias for `HSB`

### HWB¶

  * `h: number` [0, 360) or NaN
  * `w: number` [0, 1]
  * `b: number` [0, 1]

For an explanation on HWB, you can read the [Wikipedia article](https://en.wikipedia.org/wiki/HWB_color_model) on it.

### HSL¶

  * `h: number` [0, 360) or NaN
  * `s: number` [0, 1]
  * `l: number` [0, 1]

For an explanation on HSL, you can read the [Wikipedia article](https://en.wikipedia.org/wiki/HSL_and_HSV) on it.

### CMYK¶

  * `c: number` [0, 1]
  * `m: number` [0, 1]
  * `y: number` [0, 1]
  * `k: number` [0, 1]

For an explanation on CMYK, you can read the [Wikipedia article](https://en.wikipedia.org/wiki/CMYK_color_model) on it. The RGB-CMYK conversions are naive and do not take color profiles into account.

### Temperature¶

  * `kelvin: number`

For best results, use temperatures in the range [1000, 40000]. The RGB-Temperature conversions are on based on Neil Bartlett's [color-temperature](https://github.com/neilbartlett/color-temperature).

### XYZ¶

  * `x: number` [0, 1] (typical)
  * `y: number` [0, 1]
  * `z: number` [0, 1] (typical)

For an explanation on XYZ, you can read the [Wikipedia article](https://en.wikipedia.org/wiki/CIE_1931_color_space) on it. The RGB-XYZ conversions use [illuminant D65](https://en.wikipedia.org/wiki/Illuminant_D65).

### xyY¶

  * `x: number` [0, 1]
  * `y: number` [0, 1]
  * `Y: number` [0, 1]

[xyY](https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space) is a color space related to [XYZ](https://en.wikipedia.org/wiki/CIE_1931_color_space).

### Lab¶

  * `l: number` [0, 1]
  * `a: number` [-1.28, 1.27] (typically)
  * `b: number` [-1.28, 1.27] (typically)

For an explanation on CIELAB, you can read the [Wikipedia article](https://en.wikipedia.org/wiki/CIELAB_color_space) on it.

### LChab¶

  * `l: number` [0, 1]
  * `c: number` [0, 1.50] (typically)
  * `h: number` [0, 360)

LCh(ab) is the cylindrical model of [CIELAB](https://en.wikipedia.org/wiki/CIELAB_color_space#Cylindrical_model).

### LCh¶

Alias for `LChab`

### Luv¶

  * `l: number` [0, 1]
  * `u: number` [-1, 1] (typically)
  * `v: number` [-1, 1] (typically)

For an explanation on CIELUV, you can read the [Wikipedia article](https://en.wikipedia.org/wiki/CIELUV) on it.

### LChuv¶

  * `l: number` [0, 1]
  * `c: number` [0, 1.50] (typically)
  * `h: number` [0, 360)

LCh(uv) is the cylindrical model of [CIELUV](https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_\(CIELCh\)).


[ ](https://github.com/Blupo/Color/edit/master/docs/api/gradient.md "Edit this page")

# Gradient

## Types¶

### GradientKeypoint¶

        Time: number,
        Color: Color

`Time` must be in the range [0, 1].

## Constructors¶

### Gradient.new¶

    Gradient.new(keypoints: array<GradientKeypoint>): Gradient

Standard Gradient constructor. The first keypoint must have a `Time` of 0, and the last keypoint must have a `Time` of 1. (Consequently, there must be at least 2 keypoints.) The keypoint list must be sorted by time.

### Gradient.fromColors¶

    Gradient.fromColors(...: Color): Gradient

Creates a Gradient from one or more Colors. If one Color is passed, the start and end keypoints will have the same color. If two Colors are passed, the start and end keypoints will have the first and second color, respectively. If 3 or more Colors is passed, the keypoints will be equidistant with respect to time.

### Gradient.fromColorSequence¶

    Gradient.fromColorSequence(colorSequence: ColorSequence): Gradient

Creates a Gradient from a [ColorSequence](https://developer.roblox.com/en-us/api-reference/datatype/ColorSequence).

## Properties¶

### Gradient.Keypoints¶

    Gradient.Keypoints: array<GradientKeypoint>

## Functions¶

### Gradient.invert¶

    Gradient.invert(gradient: Gradient): Gradient

Returns a Gradient with reversed keypoints.

### Gradient.color¶

    Gradient.color(gradient: Gradient, time: number, mode: string? = "RGB", hueAdjustment: string? = "Shorter"): Color

Returns a Color from the Gradient at the specified time, mixing mode, and hue adjustment (see [Color.mix](https://blupo.github.io/Color/api/color/#colormix) for what those are). `time` should be in the range [0, 1].

### Gradient.colors¶

    Gradient.colors(gradient: Gradient, amount: number?, mode: string? = "RGB", hueAdjustment: string? = "Shorter"): array<Color>

Returns an array of `amount` equidistant colors, using the specified mixing mode and hue adjustment (see [Color.mix](https://blupo.github.io/Color/api/color/#colormix) for what those are).

### Gradient.colorSequence¶

    Gradient.colorSequence(gradient: Gradient, steps: number? = 20, mode: string? = "RGB", hueAdjustment: string? = "Shorter"): ColorSequence

Returns a [ColorSequence](https://developer.roblox.com/en-us/api-reference/datatype/ColorSequence) with `steps` equidistant colors. If the [mixing mode](https://blupo.github.io/Color/api/color/#colormix) is RGB, the ColorSequence will instead consist of the colors from the GradientKeypoints used to construct it.

Info

Due to an engine limitation that only allows up to 20 keypoints in a ColorSequence, you may notice differences between the ColorSequence's intermediate colors and the Gradient's intermediate colors if you are using a mixing mode other than RGB.

## Math Operations¶

### Gradient == Gradient¶

Comparing Gradients with `==` checks if they have the same number of keypoints, that the keypoints have the same Time values, and that the keypoints have the same Color values (using [Color.unclippedEq](https://blupo.github.io/Color/api/color/#colorunclippedeq)).

    local gradient1 = Gradient.fromColors(
        Color.new(0, 0, 0),
        Color.new(1, 1, 1)
    )

    local gradient2 = Gradient.new({
        {Time = 0, Color = Color.new(0, 0, 0)},
        {Time = 1, Color = Color.new(1, 1, 1)}
    })

    local gradient3 = Gradient.new({
        {Time = 0, Color = Color.new(1, 1, 1)},
        {Time = 1, Color = Color.new(0, 0, 0)}
    })

    print(gradient1 == gradient2) --> true
    print(gradient1 == gradient3) --> false
    print(gradient1 == gradient3:invert()) --> true


[ ](https://github.com/Blupo/Color/edit/master/docs/changelog.md "Edit this page")

# Changelog

## [0.2.2] - 2022-04-06¶

### Changed¶

  * Replaced the `Raw` hue adjustment option with `Specified` to match spec, however `Raw` will still work

## [0.2.1] - 2022-01-06¶

### Changed¶

  * The `Gradient.new` constructor now creates a copy of the input table instead of using the input table itself
  * `Gradient.Keypoints` is now correctly frozen, where previously it was possible to modify the individual keypoints but not the keypoint list itself

## [0.2.0] - 2021-12-01¶

### Added¶

  * Added links in the documentation for further reading on various color types
  * Added alternative from/to functions for the various color types
    * e.g. `Color.fromColor3(...)` instead of `Color.from("Color3", ...)`
    * e.g. `Color:toColor3()` instead of `Color:to("Color3")`
  * Added `Color.gray` as a shortcut for creating achromatic colors
  * Added `Color.harmonies` for generating color harmonies
  * Added `Color.deltaE` for calculating color differences
  * Added `Color.named` for referencing CSS colors
  * Added the `xyY` color type

### Removed¶

  * `lRGB` interpolation has been removed, since it can be done in `XYZ`

### Changed¶

  * Refined code to reduce type-check warnings
  * Documentation now reflects that the Hue component for some color types can be NaN
  * Static functions in the documentation now have a badge
  * Read-only properties in the documentation now have a badge
  * The Color and Gradient modules of the library are now split apart
    * You can access the modules using `[Module].Color` and `[Module].Gradient`
  * Updated the allowed interpolations for `Color.mix`
  * `Color.isAColor` should work for Colors from different versions of the library
  * `Color.components` now allows you to obtain unclipped components
  * `Color.luminance` compensates for the [error](https://www.w3.org/WAI/GL/wiki/index.php?title=Relative_luminance&oldid=11187) from the equation provided in WCAG 2
  * `Gradient.toColorSequence` was renamed to `Gradient.colorSequence`

## [0.1.0] - 2021-11-09¶

### Added¶

  * Initial release


# Studio Wally

Studio Wally is a plugin for Roblox Studio that lets you install and update [Wally](https://github.com/UpliftGames/wally) packages all from in studio.

This plugin is intended to be used by projects that aren't managed by Rojo, such as prototypes or legacy games.

This plugin relies on the experimental [Rojo headless API](https://github.com/rojo-rbx/rojo/pull/639) to connect to a server for syncing the packages in.
The headless API is currently not available in the main branch of Rojo, and must be installed from a fork,
which is available on the [Roblox Library](https://www.roblox.com/library/11092943149/Rojo-Boatly).

## How to get

You can get the latest version of the plugin from [Roblox Library](https://www.roblox.com/library/11121595926/Studio-Wally),
or download a build of the plugin from [GitHub Releases](https://github.com/fewkz/studio-wally/releases)

You will also need the [Rojo Boatly](https://www.roblox.com/library/11092943149/Rojo-Boatly) plugin installed in order for it to work.

## How to use

The plugin adds two buttons to the plugin toolbar, the "Edit Packages" button will open the studio wally manifest,
which stores the configuration for studio wally and what packages to install.

The "Install Packages" button will send a request to the server to download the packages, which will use Rojo to sync the packages in.

Make sure to check the output if something unexpected happened, as it gives errors when something goes wrong. Feel free to open an issue if you run into any problems.


# Roblox-Utils

A set of modules I've built for my games, now available as wally packages!
More to follow soon :)


# Luau Cryptography

**Luau Cryptography** is a library of cryptographic algorithims written in Luau. It supports Post-Quantum (PQ), Elliptic Curve Cryptography (ECC), authenticated encryption and CSPRNG with many utilities.

## Authors

**daily3014** - Developer - [@daily3014](https://github.com/daily3014)
**Xoifail** - Developer - [@xoifail](https://github.com/xoifaii)

### Acknowledgments

- Thanks to those who gave feedback and testing
- Special thanks to all contributors and bug reporters
- AES was originally made by @RobloxGamerPro200007
- XChaCha20 was originally made by @littleBitsman
- Murmur3 hash was originally made by @kohltastrophe

## Disclaimer

While this library has extensive testing, it's always recommended that you do your own tests. Keep in mind that there may be timing vulnerabilities that cannot be fixed due to how Luau compiles functions. **This library is NOT intended for exploitation, harassment, illegal activities, or explicit content.** All security issues should be reported in the Discord server.

## Documentation

## Installation

### Wally

```toml
[dependencies]
cryptography = "daily3014/cryptography@3.1.0"

### Pesde

```yaml
pesde add daily3014/cryptography

### Manual Installation

Download the latest release from GitHub and place it in your Roblox Studio project.

## List of Algorithms

### Elliptic Curve Cryptography

**Digital Signature Schemes**

- [Ed25519](https://github.com/daily3014/rbx-cryptography/blob/main/src/Verification/EdDSA) signatures with masked operations for side-channel protection

**Key Exchange**

- [X25519](https://github.com/daily3014/rbx-cryptography/blob/main/src/Verification/EdDSA/X25519.luau): Elliptic curve Diffie-Hellman over Curve25519

### Post-Quantum Cryptography

**KEM: Key Encapsulation Methods**

- [ML-KEM](https://github.com/daily3014/rbx-cryptography/tree/main/src/Verification/MlKEM): modes 512, 768, 1024 (Kyber-based, NIST standardized)

**Digital Signature Schemes**

- [ML-DSA](https://github.com/daily3014/rbx-cryptography/tree/main/src/Verification/MlDSA): modes 44, 65, 87 (Dilithium-based, [FIPS 204](https://doi.org/10.6028/NIST.FIPS.204))

### Symmetric Cryptography

**Hash Functions**

- **SHA-2 Family**: SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256 with optional salt support
- **SHA-3 Family**: SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE-128, SHAKE-256 ([FIPS 202](https://doi.org/10.6028/NIST.FIPS.202))
- **BLAKE Family**: [BLAKE3](https://github.com/daily3014/rbx-cryptography/blob/main/src/Hashing/Blake3.luau) (fastest available), BLAKE3-Keyed, BLAKE3-DeriveKey, [BLAKE2b](https://github.com/daily3014/rbx-cryptography/blob/main/src/Hashing/Blake2b.luau)

**Non-cryptographic Hash Functions**

- [XXH32](https://github.com/daily3014/rbx-cryptography/blob/main/src/Hashing/XXH32.luau): Ultra-fast non-cryptographic hash
- [Murmur3](https://github.com/daily3014/rbx-cryptography/blob/main/src/Hashing/Murmur.luau): Fast non-cryptographic hash

**Message Authentication**

- [HMAC](https://github.com/daily3014/rbx-cryptography/blob/main/src/Hashing/HMAC.luau): Hash-based Message Authentication Code (works with any hash function)

- [KMAC](https://github.com/daily3014/rbx-cryptography/blob/main/src/Hashing/KMAC.luau): Hash-based Message Authentication Code (uses Keccak)

**Authenticated Encryption**

- [ChaCha20-Poly1305](https://github.com/daily3014/rbx-cryptography/blob/main/src/Encryption/AEAD): AEAD construction ([RFC 8439](https://doi.org/10.17487/RFC8439))
- [AES-GCM](https://github.com/daily3014/rbx-cryptography/blob/main/src/Encryption/AES.luau): Galois/Counter Mode

**Stream & Block Ciphers**

- [ChaCha20](https://github.com/daily3014/rbx-cryptography/tree/main/src/Encryption/AEAD): Stream cipher ([RFC 8439](https://doi.org/10.17487/RFC8439))
- [AES-GCM](https://github.com/daily3014/rbx-cryptography/blob/main/src/Encryption/AES.luau): Advanced Encryption Standard
- [Simon](https://github.com/daily3014/rbx-cryptography/blob/main/src/Encryption/Simon.luau): Lightweight block cipher
- [Speck](https://github.com/daily3014/rbx-cryptography/blob/main/src/Encryption/Speck.luau): Lightweight block cipher
- [XOR](https://github.com/daily3014/rbx-cryptography/blob/main/src/Encryption/XOR.luau): Simple additive cipher

**Checksums**

- [CRC32](https://github.com/daily3014/rbx-cryptography/blob/main/src/Checksums/CRC32.luau): Cyclic Redundancy Check (JAM/ISO modes)
- [Adler-32](https://github.com/daily3014/rbx-cryptography/blob/main/src/Checksums/Adler.luau): Checksum algorithm

### Utilities

**Encoding & Conversion**

- [Base64](https://github.com/daily3014/rbx-cryptography/blob/main/src/Utilities/Base64.luau): Encode and decode
- [Hexadecimal](https://github.com/daily3014/rbx-cryptography/blob/main/src/Utilities/Conversions.luau): Buffer to/from hex string conversion

**Random Generation**

- [CSPRNG](https://github.com/daily3014/rbx-cryptography/blob/main/src/Utilities/CSPRNG): Cryptographically Secure Pseudo-Random Number Generator with entropy management
- Random strings and bytes generation

## Performance

Performance benchmarks conducted in Roblox Studio on AMD Ryzen 5 7600X using Benchmarker by @boatbomber.

### Hashing / Checksum

| Algorithm | Data Size | This Library | HashLib | Alternative | Other Libraries | Improvement |
|-----------|-----------|--------------|---------|-------------|-----------------|-------------|
| SHA-256 | 20k | **271 μs** | 2058 μs | 493 μs (Old Version) | 596 μs (Dekkonot) | **7.6x faster** than HashLib |
| SHA-512 | 20k | **421 μs** | 4348 μs | 1066 μs (Dekkonot) | - | **10.3x faster** than HashLib |
| SHA3-512 | 20k | **826 μs** | 10.60 ms | - | - | **12.8x faster** than HashLib |
| BLAKE3 | 20k | **133 μs** | - | - | - | - |
| HMAC-BLAKE3 | 20k | **145 μs** | - | - | - | - |
| KMAC-128 | 20k | **443 μs** | - | - | - | - |
| KMAC-256 | 20k | **501 μs** | - | - | - | - |
| Adler-32 | 200k | **163 μs** | - | 1.65 ms (Naive Approach) | - | **10.1x faster** |
| CRC32 | 200k | **1.43 ms** | - | 6.26 ms (DevForum) | - | **4.4x faster** |

### Encryption

| Algorithm | Data Size | This Library | Alternative | Other Libraries | Improvement |
|-----------|-----------|--------------|-------------|-----------------|-------------|
| ChaCha20 (Encrypt) | 20k | **177 μs** | 7.87 ms (EncryptedNet) | - | **44.5x faster** |
| ChaCha20 (Roundtrip) | 20k | **338 μs** | ~15 ms (EncryptedNet) | - | **44.4x faster** |
| ChaCha20-Poly1305 (Encrypt) | 20k | **232 μs** | - | - | - |
| ChaCha20-Poly1305 (Roundtrip) | 20k | **448 μs** | - | - | - |
| Simon (Encrypt) | 20k | **239 μs** | - | - | - |
| Simon (Roundtrip) | 20k | **466 μs** | - | - | - |
| Speck (Encrypt) | 20k | **193 μs** | - | - | - |
| Speck (Roundtrip) | 20k | **388 μs** | - | - | - |
| AES-GCM (Encrypt) | 20k | **833 μs** | 1.877 ms (RobloxGamerPro200007 AES256-CTR) | - | **2.3x faster** |
| AES-GCM (Roundtrip) | 20k | **1.5 ms** | - | - | - |
| XOR (Encrypt) | 1 million | **1.10 ms** | ~49.5 ms (Devfourm) | ~171000 ms (daily) | **155,454x faster** |
| XOR (Roundtrip) | 1 million | **2.20 ms** | 98.9 ms (Devfourm) | ~342000 ms (daily) | **155,454x faster** |

### Digital Signatures & Key Exchange

| Algorithm | Operation | Time | Alternative | Improvement |
|-----------|-----------|------|-------------|-------------|
| EdDSA (Roundtrip) | Sign+Verify | **691 μs** | - | - |
| ML-DSA-44 (Roundtrip) | Sign+Verify | **3.65 ms** | - | - |
| ML-KEM-512 (Roundtrip) | Encap+Decap | **754 μs** | - | - |

### Utilities

| Algorithm | Data Size | Time | Alternative | Improvement |
|-----------|-----------|------|-------------|-------------|
| Base64 (Roundtrip) | 1 million | **3.77ms** | Lute: 9.11msReselim: 12.08ms | **2.4x faster** than Lute**3.2x faster** than Reselim |

*Roundtrip: Complete encrypt/decrypt or sign/verify cycle*

## Testing and Benchmarking

### Running Tests

To run the complete test suite:

```bash
bash scripts/test.sh

This will launch Roblox Studio, execute all tests, and display results in your terminal.

### Development Testing

For continuous testing during development:

```bash
bash scripts/dev.sh

This starts a Rojo server. Open Roblox Studio and sync Rojo into a Baseplate. Whenever you run the game server, the test suites will run and results will show in the Output widget.

## Contributing

To contribute, fork this repository and make your changes, and then make a Pull Request. A Pull Request needs approval.

Please read the [CONTRIBUTING.md file](CONTRIBUTING.md) for detailed guidelines.

## License

This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details.

[DevForum](https://devforum.roblox.com/t/fastest-cryptography-library-for-roblox/3680271) • [Discord](https://discord.gg/Fg3sM8qKPp) • [Docs](https://xoifaii.github.io/) • [Wally](https://wally.run/package/daily3014/cryptography) • [Pesde](https://pesde.dev/packages/daily3014/cryptography)


# daily3014/cryptography

v3.1.1 Â· published ...

Luau implementations of popular hashing/encryption algorithms

Target

Luau

# Luau Cryptography

[](https://xoifaii.github.io/) [](https://discord.gg/Fg3sM8qKPp) [](https://wally.run/package/daily3014/cryptography) [](https://pesde.dev/packages/daily3014/cryptography)

**Luau Cryptography** is a library of cryptographic algorithims written in Luau. It supports Post-Quantum (PQ), Elliptic Curve Cryptography (ECC), authenticated encryption and CSPRNG with many utilities.

## Authors

**daily3014** \- Developer - [@daily3014](https://github.com/daily3014)
**Xoifail** \- Developer - [@xoifail](https://github.com/xoifaii)

### Acknowledgments

  * Thanks to those who gave feedback and testing
  * Special thanks to all contributors and bug reporters
  * AES was originally made by @RobloxGamerPro200007
  * XChaCha20 was originally made by @littleBitsman
  * Murmur3 hash was originally made by @kohltastrophe

## Disclaimer

While this library has extensive testing, it's always recommended that you do your own tests. Keep in mind that there may be timing vulnerabilities that cannot be fixed due to how Luau compiles functions. **This library is NOT intended for exploitation, harassment, illegal activities, or explicit content.** All security issues should be reported in the Discord server.

## Documentation

[](https://xoifaii.github.io/)

## Installation

### Wally

    [dependencies]
    cryptography = "daily3014/[[email protected]](https://pesde.dev/cdn-cgi/l/email-protection)"

### Pesde

    pesde add daily3014/cryptography

### Manual Installation

Download the latest release from GitHub and place it in your Roblox Studio project.

## List of Algorithms

### Elliptic Curve Cryptography

**Digital Signature Schemes**

  * [Ed25519](https://github.com/daily3014/rbx-cryptography/blob/main/src/Verification/EdDSA) signatures with masked operations for side-channel protection

**Key Exchange**

  * [X25519](https://github.com/daily3014/rbx-cryptography/blob/main/src/Verification/EdDSA/X25519.luau): Elliptic curve Diffie-Hellman over Curve25519

### Post-Quantum Cryptography

**KEM: Key Encapsulation Methods**

  * [ML-KEM](https://github.com/daily3014/rbx-cryptography/tree/main/src/Verification/MlKEM): modes 512, 768, 1024 (Kyber-based, NIST standardized)

**Digital Signature Schemes**

  * [ML-DSA](https://github.com/daily3014/rbx-cryptography/tree/main/src/Verification/MlDSA): modes 44, 65, 87 (Dilithium-based, [FIPS 204](https://doi.org/10.6028/NIST.FIPS.204))

### Symmetric Cryptography

**Hash Functions**

  * **SHA-2 Family**: SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256 with optional salt support
  * **SHA-3 Family**: SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE-128, SHAKE-256 ([FIPS 202](https://doi.org/10.6028/NIST.FIPS.202))
  * **BLAKE Family**: [BLAKE3](https://github.com/daily3014/rbx-cryptography/blob/main/src/Hashing/Blake3.luau) (fastest available), BLAKE3-Keyed, BLAKE3-DeriveKey, [BLAKE2b](https://github.com/daily3014/rbx-cryptography/blob/main/src/Hashing/Blake2b.luau)

**Non-cryptographic Hash Functions**

  * [XXH32](https://github.com/daily3014/rbx-cryptography/blob/main/src/Hashing/XXH32.luau): Ultra-fast non-cryptographic hash
  * [Murmur3](https://github.com/daily3014/rbx-cryptography/blob/main/src/Hashing/Murmur.luau): Fast non-cryptographic hash

**Message Authentication**

  * [HMAC](https://github.com/daily3014/rbx-cryptography/blob/main/src/Hashing/HMAC.luau): Hash-based Message Authentication Code (works with any hash function)

  * [KMAC](https://github.com/daily3014/rbx-cryptography/blob/main/src/Hashing/KMAC.luau): Hash-based Message Authentication Code (uses Keccak)

**Authenticated Encryption**

  * [ChaCha20-Poly1305](https://github.com/daily3014/rbx-cryptography/blob/main/src/Encryption/AEAD): AEAD construction ([RFC 8439](https://doi.org/10.17487/RFC8439))
  * [AES-GCM](https://github.com/daily3014/rbx-cryptography/blob/main/src/Encryption/AES.luau): Galois/Counter Mode

**Stream & Block Ciphers**

  * [ChaCha20](https://github.com/daily3014/rbx-cryptography/tree/main/src/Encryption/AEAD): Stream cipher ([RFC 8439](https://doi.org/10.17487/RFC8439))
  * [AES-GCM](https://github.com/daily3014/rbx-cryptography/blob/main/src/Encryption/AES.luau): Advanced Encryption Standard
  * [Simon](https://github.com/daily3014/rbx-cryptography/blob/main/src/Encryption/Simon.luau): Lightweight block cipher
  * [Speck](https://github.com/daily3014/rbx-cryptography/blob/main/src/Encryption/Speck.luau): Lightweight block cipher
  * [XOR](https://github.com/daily3014/rbx-cryptography/blob/main/src/Encryption/XOR.luau): Simple additive cipher

**Checksums**

  * [CRC32](https://github.com/daily3014/rbx-cryptography/blob/main/src/Checksums/CRC32.luau): Cyclic Redundancy Check (JAM/ISO modes)
  * [Adler-32](https://github.com/daily3014/rbx-cryptography/blob/main/src/Checksums/Adler.luau): Checksum algorithm

### Utilities

**Encoding & Conversion**

  * [Base64](https://github.com/daily3014/rbx-cryptography/blob/main/src/Utilities/Base64.luau): Encode and decode
  * [Hexadecimal](https://github.com/daily3014/rbx-cryptography/blob/main/src/Utilities/Conversions.luau): Buffer to/from hex string conversion

**Random Generation**

  * [CSPRNG](https://github.com/daily3014/rbx-cryptography/blob/main/src/Utilities/CSPRNG): Cryptographically Secure Pseudo-Random Number Generator with entropy management
  * Random strings and bytes generation

## Performance

Performance benchmarks conducted in Roblox Studio on AMD Ryzen 5 7600X using Benchmarker by @boatbomber.

### Hashing / Checksum

Algorithm| Data Size| This Library| HashLib| Alternative| Other Libraries| Improvement
---|---|---|---|---|---|---
SHA-256| 20k| **271 Î¼s**| 2058 Î¼s| 493 Î¼s (Old Version)| 596 Î¼s (Dekkonot)| **7.6x faster** than HashLib
SHA-512| 20k| **421 Î¼s**| 4348 Î¼s| 1066 Î¼s (Dekkonot)| -| **10.3x faster** than HashLib
SHA3-512| 20k| **826 Î¼s**| 10.60 ms| -| -| **12.8x faster** than HashLib
BLAKE3| 20k| **133 Î¼s**| -| -| -| -
HMAC-BLAKE3| 20k| **145 Î¼s**| -| -| -| -
KMAC-128| 20k| **443 Î¼s**| -| -| -| -
KMAC-256| 20k| **501 Î¼s**| -| -| -| -
Adler-32| 200k| **163 Î¼s**| -| 1.65 ms (Naive Approach)| -| **10.1x faster**
CRC32| 200k| **1.43 ms**| -| 6.26 ms (DevForum)| -| **4.4x faster**

### Encryption

Algorithm| Data Size| This Library| Alternative| Other Libraries| Improvement
---|---|---|---|---|---
ChaCha20 (Encrypt)| 20k| **177 Î¼s**| 7.87 ms (EncryptedNet)| -| **44.5x faster**
ChaCha20 (Roundtrip)| 20k| **338 Î¼s**| ~15 ms (EncryptedNet)| -| **44.4x faster**
ChaCha20-Poly1305 (Encrypt)| 20k| **232 Î¼s**| -| -| -
ChaCha20-Poly1305 (Roundtrip)| 20k| **448 Î¼s**| -| -| -
Simon (Encrypt)| 20k| **239 Î¼s**| -| -| -
Simon (Roundtrip)| 20k| **466 Î¼s**| -| -| -
Speck (Encrypt)| 20k| **193 Î¼s**| -| -| -
Speck (Roundtrip)| 20k| **388 Î¼s**| -| -| -
AES-GCM (Encrypt)| 20k| **833 Î¼s**| 1.877 ms (RobloxGamerPro200007 AES256-CTR)| -| **2.3x faster**
AES-GCM (Roundtrip)| 20k| **1.5 ms**| -| -| -
XOR (Encrypt)| 1 million| **1.10 ms**| ~49.5 ms (Devfourm)| ~171000 ms (daily)| **155,454x faster**
XOR (Roundtrip)| 1 million| **2.20 ms**| 98.9 ms (Devfourm)| ~342000 ms (daily)| **155,454x faster**

### Digital Signatures & Key Exchange

Algorithm| Operation| Time| Alternative| Improvement
---|---|---|---|---
EdDSA (Roundtrip)| Sign+Verify| **691 Î¼s**| -| -
ML-DSA-44 (Roundtrip)| Sign+Verify| **3.65 ms**| -| -
ML-KEM-512 (Roundtrip)| Encap+Decap| **754 Î¼s**| -| -

### Utilities

Algorithm| Data Size| Time| Alternative| Improvement
---|---|---|---|---
Base64 (Roundtrip)| 1 million| **3.77ms**| Lute: 9.11ms
Reselim: 12.08ms| **2.4x faster** than Lute
**3.2x faster** than Reselim

_Roundtrip: Complete encrypt/decrypt or sign/verify cycle_

## Testing and Benchmarking

### Running Tests

To run the complete test suite:

    bash scripts/test.sh

This will launch Roblox Studio, execute all tests, and display results in your terminal.

### Development Testing

For continuous testing during development:

    bash scripts/dev.sh

This starts a Rojo server. Open Roblox Studio and sync Rojo into a Baseplate. Whenever you run the game server, the test suites will run and results will show in the Output widget.

## Contributing

To contribute, fork this repository and make your changes, and then make a Pull Request. A Pull Request needs approval.

Please read the [CONTRIBUTING.md file](https://pesde.dev/packages/daily3014/CONTRIBUTING.md) for detailed guidelines.

## License

This project is licensed under the MIT License. See the [LICENSE](https://pesde.dev/packages/daily3014/LICENSE) file for details.

[DevForum](https://devforum.roblox.com/t/fastest-cryptography-library-for-roblox/3680271) â¢ [Discord](https://discord.gg/Fg3sM8qKPp) â¢ [Docs](https://xoifaii.github.io/) â¢ [Wally](https://wally.run/package/daily3014/cryptography) â¢ [Pesde](https://pesde.dev/packages/daily3014/cryptography)


# rbx-cryptography

The fastest cryptography library for Roblox

[Get Started](https://xoifaii.github.io/docs/intro)[GitHub](https://github.com/daily3014/rbx-cryptography)

    local Crypto = require("@daily3014/cryptography")

    -- Hash
    local Hash = Crypto.Hashing.Blake3.Digest(Data)

    -- Encrypt
    local Ciphertext, Tag = Crypto.Encryption.AEAD.Encrypt(Data, Key, Nonce)

    -- Sign
    local Signature = Crypto.Verification.EdDSA.Sign(Message, SecretKey, PublicKey)

### Comprehensive

SHA2, SHA3, BLAKE, HMAC, ChaCha20 Poly1305, AES GCM, Ed25519, X25519, ML DSA, ML KEM

### Blazing Fast

Optimized for Luau with native compilation. Includes algorithmic optimizations like shoup tables.

### Secure

Constanttime operations. Builtin CSPRNG. Post quantum algorithms. Wycheproof tested.

### Post Quantum Ready

ML DSA and ML KEM implementations for quantum resistant signatures and key exchange.

## Everything You Need

#### Hashing

  * SHA 224/256/384/512
  * SHA3 224/256/384/512
  * BLAKE2b, BLAKE3
  * HMAC, HKDF, KMAC

#### Encryption

  * ChaCha20 Poly1305
  * XChaCha20 Poly1305
  * AES 128/192/256 GCM
  * Simon, Speck

#### Signatures

  * Ed25519
  * ML DSA 44/65/87

#### Key Exchange

  * X25519
  * ML KEM 512/768/1024

## Quick Install

#### Wally

    Cryptography = "daily3014/cryptography@3.0.1"

#### Pesde

    pesde add daily3014/cryptography

## Developers

[daily3014](https://github.com/daily3014)[Xoifail](https://github.com/XoifaiI)


# daily3014/cryptography

v3.1.1 Â· published ...

Luau implementations of popular hashing/encryption algorithms

Target

Luau

## Dev Dependencies

### [pesde/rojo ](https://pesde.dev/packages/pesde/rojo/latest/lune)

^7.4.4 Â· lune

### [pesde/scripts_rojo ](https://pesde.dev/packages/pesde/scripts_rojo/latest/lune)

^0.1.0 Â· lune


# daily3014/cryptography

v3.1.1 Â· published ...

Luau implementations of popular hashing/encryption algorithms

Target

Luau

## [3.1.1 (latest)](https://pesde.dev/packages/daily3014/cryptography/3.1.1/any)

... Â·  Luau

## [3.1.0 ](https://pesde.dev/packages/daily3014/cryptography/3.1.0/any)

... Â·  Luau

## [3.0.1 ](https://pesde.dev/packages/daily3014/cryptography/3.0.1/any)

... Â·  Luau

## [3.0.0 ](https://pesde.dev/packages/daily3014/cryptography/3.0.0/any)

... Â·  Luau

## [2.9.2 ](https://pesde.dev/packages/daily3014/cryptography/2.9.2/any)

... Â·  Luau

## [2.9.1 ](https://pesde.dev/packages/daily3014/cryptography/2.9.1/any)

... Â·  Luau

## [2.9.0 ](https://pesde.dev/packages/daily3014/cryptography/2.9.0/any)

... Â·  Luau

## [2.8.0 ](https://pesde.dev/packages/daily3014/cryptography/2.8.0/any)

... Â·  Luau

## [2.7.3 ](https://pesde.dev/packages/daily3014/cryptography/2.7.3/any)

... Â·  Luau

## [2.7.1 ](https://pesde.dev/packages/daily3014/cryptography/2.7.1/any)

... Â·  Luau

## [2.7.0 ](https://pesde.dev/packages/daily3014/cryptography/2.7.0/any)

... Â·  Luau

## [2.6.3 ](https://pesde.dev/packages/daily3014/cryptography/2.6.3/any)

... Â·  Luau

## [2.6.1 ](https://pesde.dev/packages/daily3014/cryptography/2.6.1/any)

... Â·  Luau

## [2.6.0 ](https://pesde.dev/packages/daily3014/cryptography/2.6.0/any)

... Â·  Luau

## [2.5.4 ](https://pesde.dev/packages/daily3014/cryptography/2.5.4/any)

... Â·  Luau

## [2.5.3 ](https://pesde.dev/packages/daily3014/cryptography/2.5.3/any)

... Â·  Luau

## [2.5.2 ](https://pesde.dev/packages/daily3014/cryptography/2.5.2/any)

... Â·  Luau

## [2.5.1 ](https://pesde.dev/packages/daily3014/cryptography/2.5.1/any)

... Â·  Luau

## [2.5.0 ](https://pesde.dev/packages/daily3014/cryptography/2.5.0/any)

... Â·  Luau

## [2.4.0 ](https://pesde.dev/packages/daily3014/cryptography/2.4.0/any)

... Â·  Luau

## [2.3.0 ](https://pesde.dev/packages/daily3014/cryptography/2.3.0/any)

... Â·  Luau

## [2.2.1 ](https://pesde.dev/packages/daily3014/cryptography/2.2.1/any)

... Â·  Luau

## [2.2.0 ](https://pesde.dev/packages/daily3014/cryptography/2.2.0/any)

... Â·  Luau

## [2.1.1 ](https://pesde.dev/packages/daily3014/cryptography/2.1.1/any)

... Â·  Luau

## [2.1.0 ](https://pesde.dev/packages/daily3014/cryptography/2.1.0/any)

... Â·  Luau

## [2.0.0 ](https://pesde.dev/packages/daily3014/cryptography/2.0.0/any)

... Â·  Luau

## [1.11.0 ](https://pesde.dev/packages/daily3014/cryptography/1.11.0/any)

... Â·  Luau

## [1.10.0 ](https://pesde.dev/packages/daily3014/cryptography/1.10.0/any)

... Â·  Luau

## [1.9.5 ](https://pesde.dev/packages/daily3014/cryptography/1.9.5/any)

... Â·  Luau

## [1.9.4 ](https://pesde.dev/packages/daily3014/cryptography/1.9.4/any)

... Â·  Luau

## [1.9.3 ](https://pesde.dev/packages/daily3014/cryptography/1.9.3/any)

... Â·  Luau

## [1.9.2 ](https://pesde.dev/packages/daily3014/cryptography/1.9.2/any)

... Â·  Luau

## [1.9.1 ](https://pesde.dev/packages/daily3014/cryptography/1.9.1/any)

... Â·  Luau

## [1.9.0 ](https://pesde.dev/packages/daily3014/cryptography/1.9.0/any)

... Â·  Luau

## [1.8.0 ](https://pesde.dev/packages/daily3014/cryptography/1.8.0/any)

... Â·  Luau

## [1.7.0 ](https://pesde.dev/packages/daily3014/cryptography/1.7.0/any)

... Â·  Luau

## [1.6.1 ](https://pesde.dev/packages/daily3014/cryptography/1.6.1/any)

... Â·  Luau

## [1.6.0 ](https://pesde.dev/packages/daily3014/cryptography/1.6.0/any)

... Â·  Luau

## [1.5.4 ](https://pesde.dev/packages/daily3014/cryptography/1.5.4/any)

... Â·  Luau

## [1.5.3 ](https://pesde.dev/packages/daily3014/cryptography/1.5.3/any)

... Â·  Luau

## [1.5.2 ](https://pesde.dev/packages/daily3014/cryptography/1.5.2/any)

... Â·  Luau

## [1.5.1 ](https://pesde.dev/packages/daily3014/cryptography/1.5.1/any)

... Â·  Luau

## [1.5.0 ](https://pesde.dev/packages/daily3014/cryptography/1.5.0/any)

... Â·  Luau

## [1.4.0 ](https://pesde.dev/packages/daily3014/cryptography/1.4.0/any)

... Â·  Luau

## [1.3.3 ](https://pesde.dev/packages/daily3014/cryptography/1.3.3/any)

... Â·  Luau

## [1.3.2 ](https://pesde.dev/packages/daily3014/cryptography/1.3.2/any)

... Â·  Luau

## [1.3.1 ](https://pesde.dev/packages/daily3014/cryptography/1.3.1/any)

... Â·  Luau

## [1.3.0 ](https://pesde.dev/packages/daily3014/cryptography/1.3.0/any)

... Â·  Luau

## [1.2.0 ](https://pesde.dev/packages/daily3014/cryptography/1.2.0/any)

... Â·  Luau

## [1.1.6 ](https://pesde.dev/packages/daily3014/cryptography/1.1.6/any)

... Â·  Luau

## [1.1.5 ](https://pesde.dev/packages/daily3014/cryptography/1.1.5/any)

... Â·  Luau

## [1.1.4 ](https://pesde.dev/packages/daily3014/cryptography/1.1.4/any)

... Â·  Luau

## [1.1.3 ](https://pesde.dev/packages/daily3014/cryptography/1.1.3/any)

... Â·  Luau

## [1.1.2 ](https://pesde.dev/packages/daily3014/cryptography/1.1.2/any)

... Â·  Luau

## [1.1.1 ](https://pesde.dev/packages/daily3014/cryptography/1.1.1/any)

... Â·  Luau

## [1.1.0 ](https://pesde.dev/packages/daily3014/cryptography/1.1.0/any)

... Â·  Luau

## [1.0.4 ](https://pesde.dev/packages/daily3014/cryptography/1.0.4/any)

... Â·  Roblox

## [1.0.3 ](https://pesde.dev/packages/daily3014/cryptography/1.0.3/any)

... Â·  Roblox

## [1.0.2 ](https://pesde.dev/packages/daily3014/cryptography/1.0.2/any)

... Â·  Roblox

## [1.0.1 ](https://pesde.dev/packages/daily3014/cryptography/1.0.1/any)

... Â·  Roblox

## [1.0.0 ](https://pesde.dev/packages/daily3014/cryptography/1.0.0/any)

... Â·  Roblox

## [0.2.1 ](https://pesde.dev/packages/daily3014/cryptography/0.2.1/any)

... Â·  Roblox

## [0.1.1 ](https://pesde.dev/packages/daily3014/cryptography/0.1.1/any)

... Â·  Roblox

## [0.1.0 ](https://pesde.dev/packages/daily3014/cryptography/0.1.0/any)

... Â·  Roblox