Skip to main content

Pulse.Loop

Pulse.Loop manages a repeating interval. It wraps task.spawn and task.wait with clean start/stop semantics, automatic error throttling, and optional logging.


Why not just use task.spawn?

-- Raw task.spawn loop — common but fragile
task.spawn(function()
while enabled() do
pcall(function()
-- do work
end)
task.wait(1)
end
end)

Problems:

  • Hard to stop from outside (you need a flag variable)
  • If an error escapes the pcall, the loop silently dies
  • No logging when it starts or stops
  • If started twice, two loops run simultaneously

Pulse.Loop handles all of this.


Basic usage

local _loop = Pulse.Loop.new(1.0, function()
-- runs every 1 second
-- errors are caught, throttle-logged, and the loop keeps running
-- return false to self-stop
end)

_loop:start() -- begin
_loop:stop() -- stop (safe to call when not running)
_loop:running() -- → true/false
_loop:setInterval(2) -- change interval while running

The standard pattern

Almost every feature that polls on an interval uses this exact pattern:

defineComponent('MyFeature', () => {
const enabled = signal(false)

const loop = Pulse.Loop.new(1.0, () => {
// scan for targets, apply ESP, update hitboxes, etc.
})

on.signal(enabled, (v) => {
if (v) loop.start() else loop.stop()
})

return [toggle('Enable').bind(enabled)]
})

When enabled turns on → loop starts. When it turns off → loop stops. Clean, explicit, no edge cases.


Self-stopping loops

Return false from the body to stop the loop:

local _loop = Pulse.Loop.new(0.1, function()
if not target or not target.Parent then
return false -- target gone, stop
end
-- track the target
end)

Dynamic interval

Change the interval while the loop is running:

local _loop = Pulse.Loop.new(1.0, function()
_loop:setInterval(MyComp.scanRate()) -- adapt to slider value
-- scan
end)

Error handling

If your loop body throws, Pulse.Loop catches the error and logs it at warn level, throttled to once every 5 seconds per unique error. The loop keeps running.

This prevents one bad call (e.g., a nil access on a titan that just died) from killing your whole feature silently.

You still get logs about it — check the dev overlay for throttled warnings.


Choosing between Pulse.Loop and on.heartbeat

Use on.heartbeatUse Pulse.Loop
Need character helpers (_PulseGetHumanoid, etc.)Interval is 0.5s or longer
Need when / every optionsLogic can run independently of frame timing
Per-frame rendering or camera logicNeed explicit start/stop from signal handler
Interval < 0.1sLoop body might throw occasionally

Most ESP, hitbox, and detection features use Pulse.Loop at 0.5–2s intervals. Per-frame lock-on and drawing logic uses on RenderStepped or BindToRenderStep.