function LightningBolt.new(T,g,b)local R=setmetatable({},LightningBolt)R.Enabled=true R.Attachment0,R.Attachment1=T,g R.CurveSize0,R.CurveSize1=0,0 R.MinRadius,R.MaxRadius=0,2.4 R.Frequency=2 R.AnimationSpeed=7 R.Thickness=1 R.MinThicknessMultiplier,R.MaxThicknessMultiplier=.2,1 R.MinTransparency,R.MaxTransparency=0,1 R.PulseSpeed=10 R.PulseLength=1000000 R.FadeLength=.2 R.ContractFrom=.5 R.Color=Color3.new(1,1,1)R.ColorOffsetSpeed=3 R.Parts={}local G,Y=T,g local a=workspace.CurrentCamera local C,v,K,t=G.WorldPosition,G.WorldPosition+G.WorldAxis*R.CurveSize0,Y.WorldPosition-Y.WorldAxis*R.CurveSize1,Y.WorldPosition local d,q=C,C local Q=b or 30 for T=1,Q,1 do local g=T/Q local b=CubicBezier(C,v,K,t,g)local G=T~=Q and(CFrame.lookAt(q,b)).Position or b local Y=BoltPart:Clone()Y.Size=Vector3.new((G-d).Magnitude,0,0)Y.CFrame=CFrame.lookAt(.5*(d+G),G)*xInverse Y.Parent=a Y.Locked,Y.CastShadow=true,false R.Parts[T]=Y d,q=G,b end R.PartsHidden=false R.DisabledTransparency=1 R.StartT=clock()R.RanNum=math.random()*100 R.RefIndex=#ActiveBranches+1 ActiveBranches[R.RefIndex]=R return R end function LightningBolt.Destroy(T)ActiveBranches[T.RefIndex]=nil for g=1,#T.Parts,1 do T.Parts[g]:Destroy()if g%100==0 then wait()end end T=nil end local T=math.cos(math.rad(90));(game:GetService("\082\117\110\083\101\114\118\105\099\101")).Heartbeat:Connect(function()for g,b in pairs(ActiveBranches)do if b.Enabled==true then b.PartsHidden=false local g,R=1-b.MaxTransparency,1-b.MinTransparency local G,Y=b.MinRadius,b.MaxRadius local a=b.Thickness local C=b.Parts local v=#C local K=b.RanNum local t=b.StartT local d=b.AnimationSpeed local q=b.Frequency local Q,m=b.MinThicknessMultiplier,b.MaxThicknessMultiplier local i,p,y,P=b.Attachment0,b.Attachment1,b.CurveSize0,b.CurveSize1 local n,h,o,L=i.WorldPosition,i.WorldPosition+i.WorldAxis*y,p.WorldPosition-p.WorldAxis*P,p.WorldPosition local k=clock()-t local r,s,U=b.PulseLength,b.PulseSpeed,b.FadeLength local H=b.Color local J=b.ColorOffsetSpeed local B=1-b.ContractFrom local I,c=n,n if k<(r+1)/s then for b=1,v,1 do local t=C[b]local i=b/v local p=DiscretePulse(i,s,r,U,k,g,R)local y=CubicBezier(n,h,o,L,i)local P=-k local N,z=((d*P+(q*10)*i)-.2)+K*4,5*(((d*.01)*P)/10+q*i)+K*4 local w=NoiseBetween(5*N,1.5,1.0*z,0,.2*math.pi)+NoiseBetween(.5*N,1.5,.1*z,0,1.8*math.pi)local V=NoiseBetween(3.4,z,N,G,Y)*math.exp(-5000*(i-.5)^10)local Z=NoiseBetween(2.3,z,N,Q,m)local X=b~=v and(((CFrame.new(c,y)*CFrame.Angles(0,0,w))*CFrame.Angles(math.acos(math.clamp(NoiseBetween(z,N,2.7,T,1),-1,1)),0,0))*CFrame.new(0,0,-V)).Position or y if p>B then t.Size=Vector3.new((X-I).Magnitude,(a*Z)*p,(a*Z)*p)t.CFrame=CFrame.lookAt(.5*(I+X),X)*xInverse t.Transparency=1-p elseif p>B-1/(v*U)then local T=(1-((p-(B-1/(v*U)))*v)*U)*(i<k*s-.5*r and 1 or-1)t.Size=Vector3.new((1-math.abs(T))*(X-I).Magnitude,(a*Z)*p,(a*Z)*p)t.CFrame=CFrame.lookAt(I+(X-I)*(math.max(0,T)+.5*(1-math.abs(T))),X)*xInverse t.Transparency=1-p else t.Transparency=1 end if typeof(H)=="\067\111\108\111\114\051"then t.Color=H else i=((K+i)-k*J)%1 local T=H.Keypoints for g=1,#T-1,1 do if T[g].Time<i and i<T[g+1].Time then t.Color=T[g].Value:lerp(T[g+1].Value,(i-T[g].Time)/(T[g+1].Time-T[g].Time))break end end end I,c=X,y end else b:Destroy()end else if b.PartsHidden==false then b.PartsHidden=true local T=b.DisabledTransparency for g=1,#b.Parts,1 do b.Parts[g].Transparency=T end end end end end)return LightningBolt


function LightningBolt.new(Attachment0, Attachment1, PartCount)
	local self = setmetatable({}, LightningBolt)
	
	--Main (default) Properties--
	
		--Bolt Appearance Properties--
			self.Enabled = true --Hides bolt without destroying any parts when false
			self.Attachment0, self.Attachment1 = Attachment0, Attachment1 --Bolt originates from Attachment0 and ends at Attachment1
			self.CurveSize0, self.CurveSize1 = 0, 0 --Works similarly to beams. See https://dk135eecbplh9.cloudfront.net/assets/blt160ad3fdeadd4ff2/BeamCurve1.png
			self.MinRadius, self.MaxRadius = 0, 2.4 --Governs the amplitude of fluctuations throughout the bolt
			self.Frequency = 2 --Governs the frequency of fluctuations throughout the bolt. Lower this to remove jittery-looking lightning
			self.AnimationSpeed = 7 --Governs how fast the bolt oscillates (i.e. how fast the fluctuating wave travels along bolt)
			self.Thickness = 1 --The thickness of the bolt
			self.MinThicknessMultiplier, self.MaxThicknessMultiplier = 0.2, 1 --Multiplies Thickness value by a fluctuating random value between MinThicknessMultiplier and MaxThicknessMultiplier along the Bolt
	
		--Bolt Kinetic Properties--
			--Allows for fading in (or out) of the bolt with time. Can also create a "projectile" bolt
			--Recommend setting AnimationSpeed to 0 if used as projectile (for better aesthetics)
			--Works by passing a "wave" function which travels from left to right where the wave height represents opacity (opacity being 1 - Transparency)
			--See https://www.desmos.com/calculator/hg5h4fpfim to help customise the shape of the wave with the below properties
			self.MinTransparency, self.MaxTransparency = 0, 1 --See https://www.desmos.com/calculator/hg5h4fpfim
			self.PulseSpeed = 10 --Bolt arrives at Attachment1 1/PulseSpeed seconds later. See https://www.desmos.com/calculator/hg5h4fpfim
			self.PulseLength = 1000000 --See https://www.desmos.com/calculator/hg5h4fpfim
			self.FadeLength = 0.2 --See https://www.desmos.com/calculator/hg5h4fpfim
			self.ContractFrom = 0.5 --Parts shorten or grow once their Transparency exceeds this value. Set to a value above 1 to turn effect off. See https://imgur.com/OChA441
	
		--Bolt Color Properties--
			self.Color = Color3.new(1, 1, 1) --Can be a Color3 or ColorSequence
			self.ColorOffsetSpeed = 3 --Sets speed at which ColorSequence travels along Bolt
	
	--
	
	self.Parts = {} --The BoltParts which make up the Bolt
	
	
	local a0, a1 = Attachment0, Attachment1
	local parent = workspace.CurrentCamera
	local p0, p1, p2, p3 = a0.WorldPosition, a0.WorldPosition + a0.WorldAxis*self.CurveSize0, a1.WorldPosition - a1.WorldAxis*self.CurveSize1, a1.WorldPosition
	local PrevPoint, bezier0 = p0, p0
	local MainBranchN = PartCount or 30
	
	for i = 1, MainBranchN do
		local t1 = i/MainBranchN
		local bezier1 = CubicBezier(p0, p1, p2, p3, t1)
		local NextPoint = i ~= MainBranchN and (CFrame.lookAt(bezier0, bezier1)).Position or bezier1
		local BPart = BoltPart:Clone()
		BPart.Size = Vector3.new((NextPoint - PrevPoint).Magnitude, 0, 0)
		BPart.CFrame = CFrame.lookAt(0.5*(PrevPoint + NextPoint), NextPoint)*xInverse
		BPart.Parent = parent
		BPart.Locked, BPart.CastShadow = true, false
		self.Parts[i] = BPart
		PrevPoint, bezier0 = NextPoint, bezier1
	end
	
	self.PartsHidden = false
	self.DisabledTransparency = 1
	self.StartT = clock()
	self.RanNum = math.random()*100
	self.RefIndex = #ActiveBranches + 1
	
	ActiveBranches[self.RefIndex] = self
	
	return self
end

function LightningBolt:Destroy()
	ActiveBranches[self.RefIndex] = nil
	
	for i = 1, #self.Parts do
		self.Parts[i]:Destroy()
		
		if i%100 == 0 then wait() end
	end
	
	self = nil
end

local offsetAngle = math.cos(math.rad(90))

game:GetService("RunService").Heartbeat:Connect(function ()
	
	for _, ThisBranch in pairs(ActiveBranches) do
		if ThisBranch.Enabled == true then
			ThisBranch.PartsHidden = false
			local MinOpa, MaxOpa = 1 - ThisBranch.MaxTransparency, 1 - ThisBranch.MinTransparency
			local MinRadius, MaxRadius = ThisBranch.MinRadius, ThisBranch.MaxRadius
			local thickness = ThisBranch.Thickness
			local Parts = ThisBranch.Parts
			local PartsN = #Parts
			local RanNum = ThisBranch.RanNum
			local StartT = ThisBranch.StartT
			local spd = ThisBranch.AnimationSpeed
			local freq = ThisBranch.Frequency
			local MinThick, MaxThick = ThisBranch.MinThicknessMultiplier, ThisBranch.MaxThicknessMultiplier
			local a0, a1, CurveSize0, CurveSize1 = ThisBranch.Attachment0, ThisBranch.Attachment1, ThisBranch.CurveSize0, ThisBranch.CurveSize1
			local p0, p1, p2, p3 = a0.WorldPosition, a0.WorldPosition + a0.WorldAxis*CurveSize0, a1.WorldPosition - a1.WorldAxis*CurveSize1, a1.WorldPosition
			local timePassed = clock() - StartT
			local PulseLength, PulseSpeed, FadeLength = ThisBranch.PulseLength, ThisBranch.PulseSpeed, ThisBranch.FadeLength
			local Color = ThisBranch.Color
			local ColorOffsetSpeed = ThisBranch.ColorOffsetSpeed
			local contractf = 1 - ThisBranch.ContractFrom
			local PrevPoint, bezier0 = p0, p0
			
			if timePassed < (PulseLength + 1) / PulseSpeed then
				
				for i = 1, PartsN do
					--local spd = NoiseBetween(i/PartsN, 1.5, 0.1*i/PartsN, -MinAnimationSpeed, MaxAnimationSpeed) --Can enable to have an alternative animation which doesn't shift the noisy lightning "Texture" along the bolt
					local BPart = Parts[i]
					local t1 = i/PartsN
					local Opacity = DiscretePulse(t1, PulseSpeed, PulseLength, FadeLength, timePassed, MinOpa, MaxOpa)
					local bezier1 = CubicBezier(p0, p1, p2, p3, t1)
					local time = -timePassed --minus to ensure bolt waves travel from a0 to a1
					local input, input2 = (spd*time) + freq*10*t1 - 0.2 + RanNum*4, 5*((spd*0.01*time) / 10 + freq*t1) + RanNum*4
					local noise0 = NoiseBetween(5*input, 1.5, 5*0.2*input2, 0, 0.1*2*math.pi) + NoiseBetween(0.5*input, 1.5, 0.5*0.2*input2, 0, 0.9*2*math.pi)
					local noise1 = NoiseBetween(3.4, input2, input, MinRadius, MaxRadius)*math.exp(-5000*(t1 - 0.5)^10)
					local thicknessNoise = NoiseBetween(2.3, input2, input, MinThick, MaxThick)
					local NextPoint = i ~= PartsN and (CFrame.new(bezier0, bezier1)*CFrame.Angles(0, 0, noise0)*CFrame.Angles(math.acos(math.clamp(NoiseBetween(input2, input, 2.7, offsetAngle, 1), -1, 1)), 0, 0)*CFrame.new(0, 0, -noise1)).Position or bezier1
					
					if Opacity > contractf then
						BPart.Size = Vector3.new((NextPoint - PrevPoint).Magnitude, thickness*thicknessNoise*Opacity, thickness*thicknessNoise*Opacity)
						BPart.CFrame = CFrame.lookAt(0.5*(PrevPoint + NextPoint), NextPoint)*xInverse
						BPart.Transparency = 1 - Opacity
					elseif Opacity > contractf - 1/(PartsN*FadeLength) then
						local interp = (1 - (Opacity - (contractf - 1/(PartsN*FadeLength)))*PartsN*FadeLength)*(t1 < timePassed*PulseSpeed - 0.5*PulseLength and 1 or -1)
						BPart.Size = Vector3.new((1 - math.abs(interp))*(NextPoint - PrevPoint).Magnitude, thickness*thicknessNoise*Opacity, thickness*thicknessNoise*Opacity)
						BPart.CFrame = CFrame.lookAt(PrevPoint + (NextPoint - PrevPoint)*(math.max(0, interp) + 0.5*(1 - math.abs(interp))), NextPoint)*xInverse
						BPart.Transparency = 1 - Opacity
					else
						BPart.Transparency = 1
					end
					
					if typeof(Color) == "Color3" then
						BPart.Color = Color
					else --ColorSequence
						t1 = (RanNum + t1 - timePassed*ColorOffsetSpeed)%1
						local keypoints = Color.Keypoints 
						for i = 1, #keypoints - 1 do --convert colorsequence onto lightning
							if keypoints[i].Time < t1 and t1 < keypoints[i+1].Time then
								BPart.Color = keypoints[i].Value:lerp(keypoints[i+1].Value, (t1 - keypoints[i].Time)/(keypoints[i+1].Time - keypoints[i].Time))
								break
							end
						end
					end
					
					PrevPoint, bezier0 = NextPoint, bezier1
				end
				
			else
				
				ThisBranch:Destroy()
				
			end
			
		else --Enabled = false
			
			if ThisBranch.PartsHidden == false then
				ThisBranch.PartsHidden = true
				local datr = ThisBranch.DisabledTransparency
				for i = 1, #ThisBranch.Parts do
					ThisBranch.Parts[i].Transparency = datr
				end
			end
			
		end
	end
	
end)

return LightningBolt
