ImagePlus
Roblox doesn’t give us many options when it comes to UI design. So, I wanted to create a resource for both me and other developers who might feel held back by the limitations of “vanilla” Roblox.
ImagePlus is a module that utilizes viewport frames to add new effects to an image including color overlay and stroke. (More features may be added in future updates!)
Here are some examples of how the module could be used:
Example 1 (Left is the original image, right is the same image with a color overlay and stroke added):
Eaxmple 2 (Combination of color overlay and stroke):
Documentation
ImagePlus.newImage(imageId: string)
Create and return a new ImagePlus object.
- imageId: string - ID of the image to create.
ImagePlus.newOverlay(imageId: string, {
color: Color3,
transparency: number
})
Create and return new color overlay.
- imageId: string - ID of the image to create.
- color: Color3 - Color of the overlay. Default: Color3.new(1, 1, 1)
- transparency: number - Transparency of the overlay. Default: 0
ImagePlus.newStroke(imageId: string, {
color: Color3,
transparency: number,
thickness: number,
steps: number
})
Create and return a new stroke.
- imageId: string - ID of the image to create.
- color: Color3 - Color of the stroke. Default: Color3.new(0, 0, 0)
- transparency: number - Transparency of the stroke. Default: 0
- thickness: number - Thickness of the stroke. Default: 1
- steps: number - The number of ViewportFrames created for the stroke; higher steps, higher fidelty. Default: 20
ImagePlus:addOverlay(imagePlusObject: Frame, {
color: Color3,
transparency: number
})
Add a new color overlay to an existing ImagePlus object.
- imagePlusObject: Frame - ImagePlus object to add the overlay to.
- color: Color3 - Color of the overlay. Default: Color3.new(1, 1, 1)
- transparency: number - Transparency of the overlay. Default: 0
ImagePlus:addStroke(imagePlusObject: Frame, {
color: Color3,
transparency: number,
thickness: number,
steps: number
})
Add a new color stroke to an existing ImagePlus object.
- imagePlusObject: Frame - ImagePlus object to add the stroke to.
- color: Color3 - Color of the stroke. Default: Color3.new(0, 0, 0)
- transparency: number - Transparency of the stroke. Default: 0
- thickness: number - Thickness of the stroke. Default: 1
- steps: number - The number of ViewportFrames created for the stroke; higher steps, higher fidelty. Default: 20
ImagePlus:updateOverlay(overlay: CanvasGroup, {
color: Color3,
transparency: number
})
Update the properties of an existing color overlay. Only updates passed properties.
- overlay: CanvasGroup - Overlay to update the properties of.
- color: Color3 - Color of the overlay. (Optional)
- transparency: number - Transparency of the overlay. (Optional)
ImagePlus:updateStroke(stroke: CanvasGroup, {
color: Color3,
transparency: number,
thickness: number,
steps: number
})
Update the properties of an existing stroke. Only updates passed properties.
- stroke: CanvasGroup - Stroke to update the properties of.
- color: Color3 - Color of the stroke. (Optional)
- transparency: number - Transparency of the stroke. (Optional)
- thickness: number - Thickness of the stroke. (Optional)
- steps: number - The number of ViewportFrames created for the stroke; higher steps, higher fidelty. (Optional)
Example Codes
Example 1: Adding an overlay and stroke to a profile image
-- assumes the LocalScript is the child of a ScreenGui
-- and the module is in ReplicatedStorage
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ImagePlus = require(ReplicatedStorage.ImagePlus)
local player = Players.LocalPlayer
local gui = script.Parent
-- get player's profile image ID
local id = "https://www.roblox.com/headshot-thumbnail/image?userId=" .. player.UserId .. "&width=420&height=420&format=png"
-- create new ImagePlus object
local image = ImagePlus.newImage(id)
image.AnchorPoint = Vector2.new(.5, .5)
image.Position = UDim2.fromScale(.5, .5)
image.Size = UDim2.fromOffset(400, 400)
image.Parent = gui
task.wait(2)
-- add color overlay
local overlay = ImagePlus:addOverlay(image, {
color = Color3.new(1, 0, 0), -- overlay will have red color
transparency = .5 -- overlay will have 50% transparency
})
-- add stroke
local stroke = ImagePlus:addStroke(image, {
color = Color3.new(1, 1, 0), -- stroke will have yellow color
thickness = 8, -- stroke will have thickness of 8 pixels
transparency = 0, -- stroke will be fully visible
steps = 20 -- 20 viewport frames will be created for this stroke
})
Example 2: Image’s overlay and thickness changes when mouse enters/leaves
-- assumes the LocalScript is the child of a ScreenGui
-- and the module is in ReplicatedStorage
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ImagePlus = require(ReplicatedStorage.ImagePlus)
local player = Players.LocalPlayer
local gui = script.Parent
-- get player's profile image ID
local id = "https://www.roblox.com/headshot-thumbnail/image?userId=" .. player.UserId .. "&width=420&height=420&format=png"
-- create new ImagePlus object
local image = ImagePlus.newImage(id)
image.AnchorPoint = Vector2.new(.5, .5)
image.Position = UDim2.fromScale(.5, .5)
image.Size = UDim2.fromOffset(400, 400)
image.Parent = gui
-- add color overlay
local overlay = ImagePlus:addOverlay(image, {
color = Color3.new(1, 0, 0), -- overlay will have red color
transparency = 0 -- overlay will be fully visible
})
-- add stroke
local stroke = ImagePlus:addStroke(image, {
color = Color3.new(1, 0, 0), -- stroke will have red color
thickness = 8, -- stroke will have thickness of 8 pixels
transparency = 0, -- stroke will be fully visible
steps = 20 -- 20 viewport frames will be created for this stroke
})
-- mouse hovers over image
image.MouseEnter:Connect(function()
-- update overlay
ImagePlus:updateOverlay(overlay, {
color = Color3.new(0, 1, 0) -- overlay will have green color
})
-- update stroke
ImagePlus:updateStroke(stroke, {
color = Color3.new(0, 1, 0), -- stroke will have green color
thickness = 16 -- stroke will have thickness of 16 pixels
})
end)
-- mouse leaves image
image.MouseLeave:Connect(function()
-- update overlay
ImagePlus:updateOverlay(overlay, {
color = Color3.new(1, 0, 0) -- overlay will have red color
})
-- update stroke
ImagePlus:updateStroke(stroke, {
color = Color3.new(1, 0, 0), -- stroke will have red color
thickness = 8 -- stroke will have thickness of 8 pixels
})
end)
Limitations
- The module only supports square images for now.
- A large number of viewport frames and parts are created for a stroke, which can cause performance issues if there are too many strokes.
Get the Module:
Special thanks to @boatbomber for their Image Clipping Module, as the idea of using viewport frames came from their resource.
Please feel free to leave any suggestions or questions. Thank you for reading!

