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



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 = .5
local MAX_ROTATION_SPEED = 360
local NUDGE_CHANCE_PER_SECOND = 4
local NUDGE_SPEED = 100

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

local CONFETTI_COLORS = {}
local GENERATED_COLORS = 8
local GENERATED_COLOR_SATURATION = .7--.5
local GENERATED_COLOR_VALUE = .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(.5,.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*.7)
		local rot = random()*360
		local data = {
			flickerTime = AVG_FLICKER_TIME*(.75+random()*.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 = (.5+random()*.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()^.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()^.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()*.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 > .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


