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.heartbeat | Use Pulse.Loop |
|---|---|
Need character helpers (_PulseGetHumanoid, etc.) | Interval is 0.5s or longer |
Need when / every options | Logic can run independently of frame timing |
| Per-frame rendering or camera logic | Need explicit start/stop from signal handler |
| Interval < 0.1s | Loop 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.