local function q()local q=workspace.CurrentCamera local f=q.CFrame.p local P=q.CFrame.lookVector local C=(Constants.FOV_FUDGE_FACTOR*rad((q.FieldOfView*q.ViewportSize.x)/q.ViewportSize.y))/2.0 for q,f in pairs(dynamicInstances)do local P=q.source.WorldPosition local C=q.drain.WorldPosition-P if C.magnitude<.001 then C=Vector3.new(0,0,-0.001)end q.length=C.magnitude q.cframe=Util.makeOrientation(P,C)q.part.CFrame=q.cframe q.part.Emitter.CFrame=CFrame.new(q.length/2,0,0)q.part.Emitter.PointLight.Range=q.length end for q,m in pairs(arcInstances)do local z=q.cframe.p-f local h=q.cframe*vec3(q.length,0,0)-f if acos(dot(z.unit,P))>C and acos(dot(h.unit,P))>C then if q.visible then q.visible=false q.segmentsFolder.Parent=nil end elseif not q.visible then q.visible=true q.segmentsFolder.Parent=MainFolder end q.distance=(z.magnitude+h.magnitude)/2 end for q,f in pairs(arcInstances)do if q.visible then if q.changed then q.part.CFrame=q.cframe q.part.Emitter.CFrame=CFrame.new(q.length/2,0,0)q.part.Emitter.PointLight.Range=q.length q.changed=false end if q.distance<Constants.MAX_DISTANCE then q.arcRenderAmount=q.arcRenderAmount+min(q.numArcs/3,Constants.ARCS_PER_UPDATE*min(1,throttleDistanceModifier/q.distance))updateArc(q)end end end frameCount=frameCount+1 local m=tick()-frameTick if m>Constants.AUTO_THROTTLE_FRAME_INTERVAL then autoThrottleRatio=max(0,min(1,autoThrottleRatio+Constants.AUTO_THROTTLE_INCREMENT*(frameCount/m-Constants.AUTO_THROTTLE_TARGET)))segmentPerArc=floor((Constants.SEGMENT_PER_ARC_MIN+difSegmentsPerArc*autoThrottleRatio)+.5)throttleDistanceModifier=Constants.THROTTLE_DISTANCE_MODIFIER_MIN+difDistanceModifier*autoThrottleRatio frameCount=0 frameTick=tick()end end local function f()if numInstances<=0 then if heartbeatConnection then heartbeatConnection:Disconnect()heartbeatConnection=nil end else if not heartbeatConnection then heartbeatConnection=RunService.Heartbeat:Connect(q)end end end
-- Global update loop on heartbeat
-- (for performance / user-friendliness reasons, it is better to do a global loop over all
-- objects at Heartbeat rather than exposing an API method to update individual objects)
local function onHeartbeat()
	-- Cache camera-related values and references
	local camera = workspace.CurrentCamera
	local camPos = camera.CFrame.p
	local look = camera.CFrame.lookVector

	local fov = Constants.FOV_FUDGE_FACTOR
		* rad(camera.FieldOfView * camera.ViewportSize.x / camera.ViewportSize.y)
		/ 2.0

	for v, _ in pairs(dynamicInstances) do
		local source = v.source.WorldPosition
		local axis = v.drain.WorldPosition - source
		if axis.magnitude < 0.001 then
			axis = Vector3.new(0, 0, -0.001)
		end
		v.length = axis.magnitude
		v.cframe = Util.makeOrientation(source, axis)
		v.part.CFrame = v.cframe
		v.part.Emitter.CFrame = CFrame.new(v.length / 2, 0, 0)
		v.part.Emitter.PointLight.Range = v.length
	end

	-- Check if objects are on/off-screen
	for v, _ in pairs(arcInstances) do
		local camToSource = v.cframe.p - camPos
		local camToDrain = v.cframe * vec3(v.length, 0, 0) - camPos

		-- Check if on-screen:
		if acos(dot(camToSource.unit, look)) > fov and acos(dot(camToDrain.unit, look)) > fov then
			-- Else, make visible and reparent, if not already done
			-- Not on-screen, turn invisible and unparent if not already
			if v.visible then
				v.visible = false
				v.segmentsFolder.Parent = nil
			end
		elseif not v.visible then
			v.visible = true
			v.segmentsFolder.Parent = MainFolder
		end

		-- Set average distance to camera for throttling purposes
		v.distance = (camToSource.magnitude + camToDrain.magnitude) / 2
	end

	-- Check if objects should be updated and do so
	for v, _ in pairs(arcInstances) do
		-- Only update enabled and visible objects
		if v.visible then
			-- Update CFrame/Size of instances if object values were changed
			if v.changed then
				v.part.CFrame = v.cframe
				v.part.Emitter.CFrame = CFrame.new(v.length / 2, 0, 0)
				v.part.Emitter.PointLight.Range = v.length
				v.changed = false
			end

			-- Update amount of arcs that can be rendered in this step (can be real, not just integer)
			if v.distance < Constants.MAX_DISTANCE then
				v.arcRenderAmount = v.arcRenderAmount
					+ min(v.numArcs / 3, Constants.ARCS_PER_UPDATE * min(1, throttleDistanceModifier / v.distance))
				updateArc(v)
			end
		end
	end

	-- Increase frame count
	frameCount = frameCount + 1

	-- Calculate time since last throttling check
	local deltaTime = tick() - frameTick

	-- Check if auto-throttling window has passed
	if deltaTime > Constants.AUTO_THROTTLE_FRAME_INTERVAL then
		-- Update auto-throttling ratio based on observed FPS w.r.t. target FPS
		autoThrottleRatio = max(
			0,
			min(
				1,
				autoThrottleRatio
					+ Constants.AUTO_THROTTLE_INCREMENT * (frameCount / deltaTime - Constants.AUTO_THROTTLE_TARGET)
			)
		)

		-- Update variables dependent on auto-throttling rate
		segmentPerArc = floor(Constants.SEGMENT_PER_ARC_MIN + (difSegmentsPerArc * autoThrottleRatio) + 0.5)
		throttleDistanceModifier = Constants.THROTTLE_DISTANCE_MODIFIER_MIN + (difDistanceModifier * autoThrottleRatio)

		-- Reset tracking variables
		frameCount = 0
		frameTick = tick()
	end
end

local function updateConnection()
	if numInstances <= 0 then
		if heartbeatConnection then
			heartbeatConnection:Disconnect()
			heartbeatConnection = nil
		end
	else
		if not heartbeatConnection then
			heartbeatConnection = RunService.Heartbeat:Connect(onHeartbeat)
		end
	end
end
