Pulse.Track
Pulse.Track handles the "apply on entry, remove on exit" pattern that comes up constantly in ESP and effect features. You register entities and their cleanup functions; the tracker handles when to call them.
The problem
Without a tracker, ESP code looks like:
local _active = {}
-- Apply on new entities
if not _active[titan] then
applyHighlight(titan)
_active[titan] = true
end
-- Remove dead ones
for titan in pairs(_active) do
if func.IsTitanDead(titan) then
removeHighlight(titan)
_active[titan] = nil
end
end
-- Remove all on disable
for titan in pairs(_active) do
removeHighlight(titan)
end
_active = {}
This boilerplate appears in every feature. Pulse.Track encapsulates it.
API
local tracker = Pulse.Track.new()
-- Mark an entity as tracked, with a cleanup function
tracker:apply(entity, function(e)
removeHighlight(e) -- called when entity is removed from the tracker
end)
tracker:remove(entity) -- remove one, run its cleanup
tracker:cleanup(predicateFn) -- remove all where predicate returns true
tracker:clear() -- remove everything, run all cleanups
tracker:has(entity) -- bool: is this entity tracked?
tracker:count() -- number of tracked entities
tracker:each(fn) -- call fn(entity) for every tracked entity
Complete ESP example
defineComponent('TitanESP', () => {
const enabled = signal(false)
const tracker = Pulse.Track.new()
function applyESP(titan: Model) {
const hb = titan.FindFirstChild('Hitboxes')
const nape = hb?.FindFirstChild('Nape') as BasePart | undefined
if (!nape) return
Pulse.Draw.highlight(nape, 'TitanESP', {
fill: Color3.fromRGB(255, 255, 0),
outline: Color3.fromRGB(255, 0, 0),
})
tracker.apply(titan, (t) => {
const h = t.FindFirstChild('Hitboxes')
if (h) Pulse.Draw.removeHighlight(h.FindFirstChild('Nape') as BasePart, 'TitanESP')
})
}
const loop = Pulse.Loop.new(1.0, () => {
tracker.cleanup(func.IsTitanDead)
for (const t of func.GetCachedTitans()) {
if (!tracker.has(t)) applyESP(t as Model)
}
})
on.signal(enabled, (v) => {
if (v) {
loop.start()
} else {
loop.stop()
tracker.clear()
}
})
return [toggle('Titan ESP').bind(enabled)]
})
Limitations
- The cleanup function is called synchronously — don't yield inside it.
tracker:cleanup(fn)removes and cleans in one pass — efficient, but the predicate must not error.- Trackers don't auto-cleanup on component unmount. Always call
tracker:clear()when disabling the feature.