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