Circular / Radial Progress Bar [Rounded]

ProgressBar

Version 2.0

Get Module :page_with_curl: Download Place


Introduction

Recently I’ve been looking at scripts that make circular progress bars, but their design wasn’t appealing to me. So I’ve decided to make my own module for making circular / radial progress bars!

This module was based on AstrealDev’s Radial Progress Bar module:


How do you use it?

To change the fill of the progress bar you need to either edit the rotation property or the progress property. (Rotation from 0 to 360 degrees, progress from 0 to 100)

Or you can use the :Tween() method!

Code example
local ProgressCircle = require(game.Players.LocalPlayer.PlayerScripts:WaitForChild("MainModule"))

--Fill using loops
local LoadCircle1 = ProgressCircle.new({Position = UDim2.fromScale(0.2,0.4)})
local Speed = 80
game:GetService("RunService").RenderStepped:Connect(function(Delta)
	LoadCircle1.Rotation += Speed * Delta
end)

--Tweening
local LoadCircle2 = ProgressCircle.new({BGColor = Color3.fromRGB(23, 27, 85)})
local TweenInfo = TweenInfo.new(5, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out)
task.wait(1) 
LoadCircle2:Tween(TweenInfo, {
	AnchorPoint = Vector2.new(0.5,0.5), 
	Position = UDim2.fromScale(0.5, 0.5),
	Progress = 90
}) -- Tweens the load circle to middle and fills it to 90% with the EasingStyle of bounce

--Animating with presets (you can try to make your own too)
local LoadCircle3 = ProgressCircle.new()
LoadCircle3.AnchorPoint = Vector2.new(0, 1)
LoadCircle3:Animate("InfSpin3")

More preset animations are provided in the downloadable Roblox place.

Is it customizable?

Yes it is. There are a few properties you can mess around with on my module,
you can:

  • Change the color of the circle and background
  • Change the transparency
  • Change it’s thickness and size
  • Change the background roundness
  • Position it

customization examples

But can I modify it even more?

Yes you can.

If you want to edit the actual frame manually then you can do it like this

local ProgressCircle = require(game.Players.LocalPlayer.PlayerScripts:WaitForChild("MainModule"))

local LoadCircle = ProgressCircle.new()
LoadCircle.Instance.BG.BackgroundColor3 = Color3.fromRGB(255, 0, 0)
-- This will only color the rounded BG, which makes the load circle look strange

If you want to do this you should probably know the hierarchy.

RobloxStudioBeta_vxkWrUv7XZ

Sadly it’s impossible to remove the background of the progress bar, because of the way it’s made.

How do you change the properties?

There are two ways

You can do it like this
local LoadCircle2 = ProgressCircle.new({
	Position = UDim2.fromScale(0.04, 0.65), 
	Color = Color3.fromRGB(255, 69, 72),
	BGRoundness = 1,
	Thickness = 0.5
})
Or like this
local LoadCircle3 = ProgressCircle.new()
LoadCircle3.BGColor = Color3.fromRGB(23, 27, 85)
LoadCircle3.Color = Color3.fromRGB(89, 164, 255)
LoadCircle3.BGRoundness = 0.1
LoadCircle3.AnchorPoint = Vector2.new(0.5, 0.5)
Or maybe even tween and animate it!
-- New progress circle
local LoadCircle1 = ProgressCircle.new()
LoadCircle1.AnchorPoint = Vector2.new(0, 1)
LoadCircle1:Animate("InfSpin1")

local TweenInf = TweenInfo.new(3, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out)
local TweenProperties = {
  Color = Color3.fromRGB(89, 164, 255), 
  AnchorPoint = Vector2.new(0.5,0.5),
  Position = UDim2.fromScale(0.5, 0.5)
}
LoadCircle1:Tween(TweenInf, TweenProperties) -- Tweens the load circle to middle and changes color

Here are all of the properties and their default values.

All Properties
ProgressCircle.Progress = 0 -- from 0 to 100 -|interchangable
ProgressCircle.Rotation = 0 -- from 0 to 360 -|interchangable

ProgressCircle.Position = UDim2.fromScale(0.04, 0.95)
ProgressCircle.AnchorPoint = Vector2.new(0, 0)
ProgressCircle.Size = 0.2 -- from 0 to 1
ProgressCircle.Thickness = 0.3 -- from 0 to 1
ProgressCircle.CircleSize = 0.7 -- from 0 to 1

ProgressCircle.Color = Color3.fromRGB(255, 255, 255)
ProgressCircle.BGColor = Color3.fromRGB(30, 30, 30)
ProgressCircle.Transparency = 0 --from 0 to 1
ProgressCircle.BGRoundness = 0.2 -- from 0 to 1

ProgressCircle.Rounded = true -- if you want the rounded look or not

ProgressCircle.Parent = nil -- gets parented to a ScreenGui in LocalPlayer soon after

IMPORTANT NOTES!

  • Remember to call :Destroy() when done
  • It’s recommended to use the ScreenGui that the module creates instead of making your own.
    (If you want to move the ScreenGui to a different directory then index ProgressCircle.Parent.Parent and set it to another location)
  • If you decide to create a new ScreenGui instead then make sure to set ZIndexBehaviour to Sibling
    (if you need Global then read the version 1.5 notes)

How do i get it?

You can open the Roblox place and copy the module from there or get it from this link:
Get Module

Roblox place
Download Place (65.8 KB)

The Roblox place also shows a few examples on how to use it. You can find the example scripts at:
StarterPlayer > StarterPlayerScripts > ProgressCircles
StarterPlayer > StarterPlayerScripts > Progress3D

Updates

New version 2.0 | 01/21/2023

Changes:

  • New constructor .fromViewport()
  • New constructor .fromWorldspace()

Fixes:

  • Setting the parent later will now correctly delete the default ScreenGui that was created

For more information:


Version 1.5 | 01/15/2023

Changes:

  • ProgressCircle hierarchy changes
  • New transparency property
  • Moved a few functions to utility
  • A few new examples in the test place showcasing what’s to come

Fixes:

  • The progress bar now works with ScreenGuis that use ZIndexBehaviour of Sibling
    (To revert to using ScreenGui Global behaviour you must first set the ZIndexBehaviour to that then set ProgressCircle.BG ZIndex to 9)

Big changes coming in the next update . . .

Version 1.5 Place (47.6 KB)


Version 1.2 | 01/17/2022

Changes:

  • Added support for other TweenInfo properties for the :Tween() method
    (DelayTime, RepeatCount, Reverses)
  • Added new :Animate() method (used for running the built in animation presets)
  • Added new :Destroy() method
    Important to use when you want to get rid of the load circle as it disconnects all the loops that are currently running for the progress bar (animations and tweens).
  • Added new rounded property (you can disable the rounded look)

Version 1.2 Place (34.3 KB)


Version 1.1 | 01/12/2022

Changes:

  • :Update() method removed
  • :UpdateFill() method removed
  • Added the :Tween() method
  • Changed the default AnchorPoint from (0, 1) to (0, 0)

The :Update() and :UpdateFill() methods were removed because with this update all of it is done automatically now.
The new :Tween() method can be used to tween any of the properties of the load circle


Thank you for reading! :grin:

69 Likes

Really nice improvements! Glad to see more resources on radial progress bars since they are visually great but difficult to implement.

1 Like

Hey, I’m having an issue with it.

local function LoadingCircle()
	local ProgressCircle = require(game.Players.LocalPlayer.PlayerScripts.LoadingAnims)
	local LoadCircle3 = ProgressCircle.new({BGColor = Color3.fromRGB(9, 9, 9), Position = UDim2.fromScale(0.04, 0.65)})
	LoadCircle3.Color = Color3.new(1, 1, 1)
	LoadCircle3.BGRoundness = 0.1
	LoadCircle3.AnchorPoint = Vector2.new(0.5, 0.5)
	LoadCircle3:Animate("InfSpin3")

	local TweenInf = TweenInfo.new(1, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
	LoadCircle3:Tween(TweenInf, {Color = Color3.fromRGB(64, 131, 255), AnchorPoint = Vector2.new(0.5,0.5), Position = UDim2.fromScale(0.5, 0.5)})
end

image

That’s all it does.

Sorry for the 13 day late reply, as I was inactive.
After running your code on a baseplate I was not able to replicate your issue, did you get any errors?

This is the code running on a baseplate:
Video Clip

The place I used:
Classic Baseplate.rbxl (33.7 KB)

1 Like

image
Testing 9it in a game, now it’s only doing this? I didn’t modify any code.

aND NO, i GOT NO ERRORS.

(2) PreloadService Testing - Roblox

PreloadService Testing.rbxl (252.3 KB)

I think I found out what the issue was.
For some reason the progress circle UI had an incorrect size which caused it to not show up.
Just replace your LoadingAnims module with this one and it should work

Module:
LoadingAnims.rbxm (7.6 KB)
(To put it in your game just download it and drag it into your Roblox studio window)

2 Likes

image
That only did this now


I tried it in the rbxl I sent you, and it did this.
image
image

The other place (real one) has no error, but it’s the correct rounding.

Have you tried checking if the module hierarchy looks like this?
image

Open this place, try running it, and see if you can copy everything from there not sure how to fix it otherwise
CircularProgress.rbxl (34.9 KB)

1 Like

It worked in game, but not in studio, thanks!

Hey there, love the module!
I apologize for bumping this old thread but I think I found a bug and I’m not sure what is causing it.
Basically, if you parent the ProgressCircle inside another frame, this visual glitch happens:
Proof

The “rounded” edge of the progress bar only appears once its half-filled. This is the code:

local LoadCircle = ProgressCircle.new({Position = UDim2.fromScale(0,0),
	BGRoundness = 1, Thickness = 0.25,
})

LoadCircle.Instance.Parent = game.Players.LocalPlayer.PlayerGui:WaitForChild("ScreenGui"):WaitForChild("Frame")
LoadCircle.Instance.Size = UDim2.fromScale(1,1)

local Speed = 50
game:GetService("RunService").RenderStepped:Connect(function(Delta)
	LoadCircle.Rotation += Speed * Delta
end)

Any idea on how to fix it?

Sorry I wasn’t able to answer, I was on development hiatus for a while.

I believe the issue here was with the ZIndex order. This should be somewhat fixed with the newest update. (Check changelog for more information)

But there are a two small problems with your code.

  1. When parenting the instance to somewhere else you should do it like this to prevent the module from creating a GUI:
    ProgressCircle.new({Parent = ScreenGui})

    (no longer an issue)
  2. With the newest update the ScreenGui should have ZIndexBehaviour set to Sibling

Even more stuff and improvements will be coming in the next updates!

1 Like

Thank you so much, will try it again and let you know. I ended up using another method but I’ll give yours another try.

BIG UPDATE!

Version 2.0

New constructors!

  • ProgressCircle.fromViewport()
  • ProgressCircle.fromWorldspace()

These new constructors give you way more control over the look of the progress bar than ever before.

Differences between .fromViewport() and .fromWorldspace()

With the new .fromViewport() constructor you’re no longer forced to have a background for the progress bar and you can fully adjust its transparency.

  • Inherits all properties from .fromWorldspace() constructor
  • Transparency and Color properties adjust the viewport instead of each part
  • Has Size and Position properties which adjust the size and position of the viewport
  • Has Zoom property which adjusts the zoom for the viewport camera
  • Creates the viewport correctly for you
  • Parents itself to PlayerGui if parent is not initialized
Modified Properties of Viewport progress circle
ProgressCircle.Size = UDim2.fromScale(0.4, 0.4)
ProgressCircle.Position = UDim2.fromScale(0, 0)
ProgressCircle.Zoom = 5

ProgressCircle.Parent = nil -- gets parented to a ScreenGui in PlayerGui soon after

However the .fromWorldspace() constructor gives you the ability to place a progress bar in the world of your game. (not sure what you’d use this for but i guess it’s interesting)

  • Transparency and color properties adjust each part
    (transparency looks strange)
  • Position property adjusts position in world
  • Parents itself to Workspace if parent is not initialized
All Properties of Worldspace progress circle
ProgressCircle.Progress = 0 -- from 0 to 100 -|interchangable
ProgressCircle.Rotation = 0 -- from 0 to 360 -|interchangable
	
ProgressCircle.Rotation = Vector3.new(0, 0, 0)
ProgressCircle.Position = Vector3.new(0, 0, 0)
ProgressCircle.Accuracy = 3 --from 2 to 10
ProgressCircle.Thickness = 4 --from 2 to 12
ProgressCircle.Radius = 10 -- from 0 to 10
	
ProgressCircle.Color = Color3.fromRGB(255, 255, 255)
ProgressCircle.Transparency = 0

ProgressCircle.Rounded = true -- if you want the rounded look or not

ProgressCircle.Parent = nil -- gets parented to Workspace soon after

See it in action

With ProgressCircle.fromViewport()


With ProgressCircle.fromWorldspace()

Play with the properties here!


The Pros and Cons
of using .fromViewport() rather than .new()


Pros
Cons
  • Control transparency
  • No background
  • Place it in the world
  • Costs more performance
    (adjustable with accuracy)
  • Can look slightly pixelated
    if quality isn’t set to max

With max graphics and transparency set to 0.2

With low graphics

Performance

Max graphics with Accuracy of 1

Max graphics with accuracy of 10

Progress circle with old constructor

4 Likes

Hello, I like your module, especially after 2.0 update.
It’s very cool that people like you help this community for free and even update their creations after 1 year!
I added roblox-ts typings for your module, so roblox-ts devs could use your module (even if they don’t, I will use it myself at least). I slightly changed your module, to make it more compatible with typings:

  • UI now created inside module.
  • CircularProgress.PresetAnimations now contains all animation presets, so you should add here new animation presets. Example:
CircularProgress.PresetAnimations["Test"] = (instance) => instance.Rounded = false;
  • Viewport instance constructor (.new function) that accepts properties argument will add properties to Metatable. Btw, why you didn’t make it default behavior?

Package: link.
Install using command in package description, because I’m not a member of @rbxts organization to add package in there.

1 Like

Can it be used for making players status bars ? For example: Health Bars etc.

I cannot tween. Is this a bug?

local CircularUi = require(game.ReplicatedStorage.CircularUi)

local Settings = {
	Progress = 0,
	
	Transparency = 0,
	
	Position = UDim2.fromScale(0.04, 0.8),
}

local Circle = CircularUi.new(Settings)

CircularUi:Tween(TweenInfo.new(1,Enum.EasingStyle.Cubic,Enum.EasingDirection.Out),{Progress = 50})

error: