local J=200 local Y=false local U=1 local u=40 local e=25 local Z=80 local V=.5 local L=360 local l=4 local D=100 local v=.61 local o=Vector2.new(0,150)local R={}local p=8 local W=.7 local i=.9 local C={}local h=0 local H={}local q=script.Parent.IgnoreGuiInset and game.GuiService:GetGuiInset()or Vector2.new(0,0)local I=(script.Parent.AbsoluteSize.Y+q.Y)+100 local O=script.Parent.AbsoluteSize.X local G=math.random local P=math.min local N=math.sin local E=math.cos local Q=math.pi*2 local B=math.abs local w=Instance.new("\070\114\097\109\101")w.Size=UDim2.new(0,0,0,0)w.ZIndex=Z w.AnchorPoint=Vector2.new(.5,.5)w.BorderSizePixel=0 function updateScreenSize()I=script.Parent.AbsoluteSize.Y+100 O=script.Parent.AbsoluteSize.X end updateScreenSize();(script.Parent:GetPropertyChangedSignal("\065\098\115\111\108\117\116\101\083\105\122\101")):connect(updateScreenSize)for J=1,p,1 do local Y=Color3.fromHSV(J/p,W,i)table.insert(R,Y)end function randomDirection(J)local Y=G()*Q return Vector2.new(N(Y),E(Y))*(J or 1)end function createConfetti(u,e)local Z=h>=J if Z and(Y and G())then local Y=G(1,J)for U,u in pairs(H)do Y=Y-1 if Y<=0 then U:Destroy()h=h-1 H[U]=nil Z=h>=J break end end end if not Z then h=h+1 local J=R[G(1,#R)]local Y,Z,l=Color3.toHSV(J)local D=Color3.fromHSV(Y,Z,l*.7)local v=G()*360 local o={flickerTime=V*(.75+G()*.5);rotVel=(G()*2-1)*L,rot=v,color=J;darkColor=D;pos=(u or Vector2.new(0,0))+q,vel=e or Vector2.new(0,0);scale=(.5+G()*.5)*U}local p=w:Clone()p.Rotation=v p.BackgroundColor3=o.color H[p]=o p.Parent=script.Parent end end function explode(J)local Y=script.Parent.EffectFrame.AbsolutePosition+script.Parent.EffectFrame.AbsoluteSize*.5 local U=J local u=700 for J=1,U,1 do local U=randomDirection(u)*G()^.5 createConfetti(Y,U)end end function rain(J,Y)local U=J or 50 local u=Y or 20 for J=1,U,1 do local Y=randomDirection(u)*G()^.5 local U=Vector2.new(G()*O,G()*-100)createConfetti(U,Y)end end;(game:GetService("\082\117\110\083\101\114\118\105\099\101")).Heartbeat:Connect(function(J)local Y=tick()local Z=v^J for V,L in pairs(H)do if V.Parent then local v=L.scale local R=(Y/L.flickerTime)%1 if G()<l*J then L.rotVel=L.rotVel+(G()*2-1)*180 L.vel=L.vel+Vector2.new(D*(G()*2-1),D*(G()*.5))end L.vel=L.vel*Z+(o*J)*U L.pos=L.pos+L.vel*J L.rotVel=L.rotVel*Z L.rot=L.rot+L.rotVel*J V.BackgroundColor3=R>.5 and L.color or L.darkColor V.Position=UDim2.new(0,L.pos.x,0,L.pos.y)V.Size=UDim2.new(0,u*v,0,(e*B(N(R*Q)))*v)V.Rotation=L.rot if V.AbsolutePosition.Y>I then V:Destroy()h=h-1 H[V]=nil end else h=h-1 H[V]=nil end end end)C.CreateConfetti=createConfetti C.Explode=explode C.Rain=rain return C
-- Only require on client
-- Example test-code at bottom of script

local MAX_CONFETTI = 200
local REMOVE_OLD_AT_MAX = false -- Can be slow when max is hit

local MASTER_SCALE = 1
local CONFETTI_WIDTH = 40
local CONFETTI_HEIGHT = 25
local Z_INDEX = 80

local AVG_FLICKER_TIME = 0.5
local MAX_ROTATION_SPEED = 360
local NUDGE_CHANCE_PER_SECOND = 4
local NUDGE_SPEED = 100

local DRAG = 0.61
local GRAVITY = Vector2.new(0, 150)

local CONFETTI_COLORS = {}
local GENERATED_COLORS = 8
local GENERATED_COLOR_SATURATION = 0.7 --.5
local GENERATED_COLOR_VALUE = 0.9

local module = {}
local confettiCount = 0
local confettis = {}
local topbarOffset = (script.Parent.IgnoreGuiInset and game.GuiService:GetGuiInset()) or Vector2.new(0, 0)
local killzone = script.Parent.AbsoluteSize.Y + topbarOffset.Y + 100
local screenWidth = script.Parent.AbsoluteSize.X
local random = math.random
local min = math.min
local sin = math.sin
local cos = math.cos
local tau = math.pi * 2
local abs = math.abs

local confettiTemplate = Instance.new("Frame")
confettiTemplate.Size = UDim2.new(0, 0, 0, 0)
confettiTemplate.ZIndex = Z_INDEX
confettiTemplate.AnchorPoint = Vector2.new(0.5, 0.5)
confettiTemplate.BorderSizePixel = 0

function updateScreenSize()
	killzone = script.Parent.AbsoluteSize.Y + 100
	screenWidth = script.Parent.AbsoluteSize.X
end
updateScreenSize()
script.Parent:GetPropertyChangedSignal("AbsoluteSize"):connect(updateScreenSize)

for i = 1, GENERATED_COLORS do
	local color = Color3.fromHSV(i / GENERATED_COLORS, GENERATED_COLOR_SATURATION, GENERATED_COLOR_VALUE)
	table.insert(CONFETTI_COLORS, color)
end

function randomDirection(speed)
	local direction = random() * tau
	return Vector2.new(sin(direction), cos(direction)) * (speed or 1)
end

function createConfetti(pos, vel)
	local maxedOut = confettiCount >= MAX_CONFETTI
	if maxedOut and REMOVE_OLD_AT_MAX and random() then
		-- This is the best method I can figure for removing a random item from a dictionary of known length
		local removeCoutndown = random(1, MAX_CONFETTI)
		for confetti, _ in pairs(confettis) do
			removeCoutndown = removeCoutndown - 1
			if removeCoutndown <= 0 then
				confetti:Destroy()
				confettiCount = confettiCount - 1
				confettis[confetti] = nil
				maxedOut = confettiCount >= MAX_CONFETTI
				break
			end
		end
	end
	if not maxedOut then
		confettiCount = confettiCount + 1
		local color = CONFETTI_COLORS[random(1, #CONFETTI_COLORS)]
		local h, s, v = Color3.toHSV(color)
		local darkColor = Color3.fromHSV(h, s, v * 0.7)
		local rot = random() * 360
		local data = {
			flickerTime = AVG_FLICKER_TIME * (0.75 + random() * 0.5),
			rotVel = (random() * 2 - 1) * MAX_ROTATION_SPEED,
			rot = rot,
			color = color,
			darkColor = darkColor,
			pos = (pos or Vector2.new(0, 0)) + topbarOffset,
			vel = vel or Vector2.new(0, 0),
			scale = (0.5 + random() * 0.5) * MASTER_SCALE,
		}
		local confetti = confettiTemplate:Clone()
		confetti.Rotation = rot
		confetti.BackgroundColor3 = data.color
		confettis[confetti] = data
		confetti.Parent = script.Parent
	end
end

function explode(count)
	local pos = script.Parent.EffectFrame.AbsolutePosition + script.Parent.EffectFrame.AbsoluteSize * 0.5
	local count = count
	local speed = 700 -- or 300
	for i = 1, count do
		local vel = randomDirection(speed) * (random() ^ 0.5)
		createConfetti(pos, vel)
	end
end

function rain(count, speed)
	local count = count or 50
	local speed = speed or 20
	for i = 1, count do
		local vel = randomDirection(speed) * (random() ^ 0.5)
		local pos = Vector2.new(random() * screenWidth, random() * -100)
		createConfetti(pos, vel)
	end
end

game:GetService("RunService").Heartbeat:Connect(function(delta)
	local t = tick()
	local drag = DRAG ^ delta
	for confetti, data in pairs(confettis) do
		if confetti.Parent then
			local scale = data.scale
			local flickerPercent = (t / data.flickerTime) % 1
			if random() < NUDGE_CHANCE_PER_SECOND * delta then
				data.rotVel = data.rotVel + ((random() * 2 - 1) * 180)
				data.vel = data.vel + Vector2.new(NUDGE_SPEED * (random() * 2 - 1), NUDGE_SPEED * (random() * 0.5))
			end
			data.vel = (data.vel * drag) + GRAVITY * delta * MASTER_SCALE
			data.pos = data.pos + data.vel * delta
			data.rotVel = data.rotVel * drag
			data.rot = data.rot + data.rotVel * delta
			confetti.BackgroundColor3 = flickerPercent > 0.5 and data.color or data.darkColor
			confetti.Position = UDim2.new(0, data.pos.x, 0, data.pos.y)
			confetti.Size =
				UDim2.new(0, CONFETTI_WIDTH * scale, 0, CONFETTI_HEIGHT * abs(sin(flickerPercent * tau)) * scale)
			confetti.Rotation = data.rot
			if confetti.AbsolutePosition.Y > killzone then
				confetti:Destroy()
				confettiCount = confettiCount - 1
				confettis[confetti] = nil
			end
		else
			confettiCount = confettiCount - 1
			confettis[confetti] = nil
		end
	end
end)

module.CreateConfetti = createConfetti --(pos, vel)
module.Explode = explode --(pos, count, speed)
module.Rain = rain --(count)

return module
