pulse-rb 1.2.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +225 -0
  2. package/adapters/linoria.lua +233 -0
  3. package/adapters/windui.llms.txt +366 -0
  4. package/adapters/windui.lua +505 -0
  5. package/bin/rb.js +2 -0
  6. package/dist/index.js +3285 -0
  7. package/package.json +59 -0
  8. package/pulse/dev/debuggui.lua +1206 -0
  9. package/pulse/dev/devconfig.lua +81 -0
  10. package/pulse/dev/ui/9_DevPanel.lua +384 -0
  11. package/pulse/helpers/aim.lua +193 -0
  12. package/pulse/helpers/cache.lua +68 -0
  13. package/pulse/helpers/cleaner.lua +110 -0
  14. package/pulse/helpers/conn.lua +33 -0
  15. package/pulse/helpers/cooldown.lua +47 -0
  16. package/pulse/helpers/draw.lua +122 -0
  17. package/pulse/helpers/hitbox.lua +63 -0
  18. package/pulse/helpers/input.lua +24 -0
  19. package/pulse/helpers/log.lua +228 -0
  20. package/pulse/helpers/loop.lua +58 -0
  21. package/pulse/helpers/memory.lua +48 -0
  22. package/pulse/helpers/narrate.lua +160 -0
  23. package/pulse/helpers/notify.lua +51 -0
  24. package/pulse/helpers/perf.lua +48 -0
  25. package/pulse/helpers/remote.lua +128 -0
  26. package/pulse/helpers/restore.lua +59 -0
  27. package/pulse/helpers/store.lua +39 -0
  28. package/pulse/helpers/team.lua +83 -0
  29. package/pulse/helpers/testmode.lua +80 -0
  30. package/pulse/helpers/trace.lua +111 -0
  31. package/pulse/helpers/track.lua +85 -0
  32. package/pulse/helpers/vec.lua +52 -0
  33. package/pulse/helpers/world.lua +51 -0
  34. package/pulse/runtime.lua +343 -0
  35. package/pulse/ui/linoria_settings.lua +55 -0
  36. package/pulse/ui/windui_settings.lua +87 -0
  37. package/templates/AGENTS.md +177 -0
  38. package/templates/CLAUDE.md +424 -0
  39. package/templates/deploy_config.example +17 -0
  40. package/templates/example_esp.rblua +69 -0
  41. package/templates/example_fov.rblua +20 -0
  42. package/templates/example_speed.rblua +25 -0
  43. package/templates/gitignore +4 -0
  44. package/templates/globals.lua +66 -0
  45. package/templates/layout.rblua +28 -0
  46. package/templates/module.lua +7 -0
  47. package/templates/module.rblua +32 -0
  48. package/templates/page_home.rblua +9 -0
  49. package/templates/remote.lua +6 -0
  50. package/templates/remotes.lua +14 -0
  51. package/vscode/language-configuration.json +35 -0
  52. package/vscode/package.json +35 -0
  53. package/vscode/src/extension.js +397 -0
  54. package/vscode/syntaxes/rblua.tmLanguage.json +126 -0
@@ -0,0 +1,68 @@
1
+ -- ── Pulse.Cache ──────────────────────────────────────────────────────────────
2
+ -- Timed key-value cache and fetch-wrapper.
3
+ -- Usage:
4
+ -- local c = Pulse.Cache.new(2) -- 2-second TTL per key
5
+ -- c:set("titans", titanList)
6
+ -- local list = c:get("titans") -- nil after 2 s
7
+ --
8
+ -- local getTitans = Pulse.Cache.wrap(2, function()
9
+ -- return workspace.Titans.Alive:GetChildren()
10
+ -- end)
11
+
12
+ Pulse.Cache = (function()
13
+ local C = {}
14
+
15
+ -- Create a new timed key-value cache.
16
+ -- ttl: seconds until entries expire; pass nil for entries that never expire.
17
+ function C.new(ttl)
18
+ local self = { _d = {}, _t = {}, _ttl = ttl }
19
+
20
+ function self:get(key)
21
+ if self._ttl then
22
+ local ts = self._t[key]
23
+ if ts and (tick() - ts) > self._ttl then
24
+ self._d[key] = nil; self._t[key] = nil; return nil
25
+ end
26
+ end
27
+ return self._d[key]
28
+ end
29
+
30
+ function self:set(key, value)
31
+ self._d[key] = value
32
+ if self._ttl then self._t[key] = tick() end
33
+ end
34
+
35
+ function self:has(key) return self:get(key) ~= nil end
36
+ function self:del(key) self._d[key] = nil; self._t[key] = nil end
37
+ function self:clear() self._d = {}; self._t = {} end
38
+
39
+ function self:keys()
40
+ local result = {}
41
+ for k in pairs(self._d) do
42
+ if self:has(k) then result[#result + 1] = k end
43
+ end
44
+ return result
45
+ end
46
+
47
+ return self
48
+ end
49
+
50
+ -- Wrap a fetcher so its return value is cached for `ttl` seconds.
51
+ -- Passes through all arguments to fetcher on cache miss.
52
+ function C.wrap(ttl, fetcher)
53
+ local _v, _t = nil, 0
54
+ return function(...)
55
+ local now = tick()
56
+ if _v ~= nil and (now - _t) < ttl then return _v end
57
+ local ok, result = pcall(fetcher, ...)
58
+ if ok and result ~= nil then
59
+ _v = result; _t = now
60
+ else
61
+ _v = nil; _t = 0
62
+ end
63
+ return _v or {}
64
+ end
65
+ end
66
+
67
+ return C
68
+ end)()
@@ -0,0 +1,110 @@
1
+ -- ── Pulse.Cleaner ─────────────────────────────────────────────────────────────
2
+ -- Scheduled object-removal scheduler with optional filtering and a named registry.
3
+ -- Pulse.Loop is referenced lazily (inside start()), so load order doesn't matter.
4
+ --
5
+ -- Usage — one-shot cleaner:
6
+ -- local c = Pulse.Cleaner.new({
7
+ -- collect = function() return workspace.Map.Decor:GetChildren() end,
8
+ -- interval = 1.0,
9
+ -- })
10
+ -- c:start() c:stop() c:running()
11
+ --
12
+ -- Usage — named registry (cross-component access):
13
+ -- Pulse.Cleaner.register("mapDecor", { collect = ..., interval = 1 })
14
+ -- Pulse.Cleaner.get("mapDecor"):start()
15
+ -- Pulse.Cleaner.stopAll()
16
+
17
+ Pulse.Cleaner = (function()
18
+ local C = {}
19
+ local _registry = {}
20
+
21
+ -- Create a new cleaner.
22
+ -- opts:
23
+ -- collect — function() → {Instance,...} required
24
+ -- filter — function(inst) → bool optional; return false to skip removal
25
+ -- interval — seconds between sweeps default 1.0
26
+ -- onSweep — function(removedCount) optional callback after each sweep
27
+ function C.new(opts)
28
+ opts = opts or {}
29
+ local self = {
30
+ totalRemoved = 0,
31
+ _interval = opts.interval or 1.0,
32
+ _collect = opts.collect or function() return {} end,
33
+ _filter = opts.filter,
34
+ _onSweep = opts.onSweep,
35
+ _loop = nil,
36
+ }
37
+
38
+ function self:_sweep()
39
+ local ok, list = pcall(self._collect)
40
+ if not ok or type(list) ~= "table" or #list == 0 then return end
41
+ local removed = 0
42
+ for _, obj in ipairs(list) do
43
+ local skip = false
44
+ if self._filter then
45
+ local fok, keep = pcall(self._filter, obj)
46
+ skip = fok and not keep
47
+ end
48
+ if not skip then
49
+ if pcall(function() obj:Destroy() end) then
50
+ removed = removed + 1
51
+ end
52
+ end
53
+ end
54
+ self.totalRemoved = self.totalRemoved + removed
55
+ if removed > 0 and self._onSweep then
56
+ pcall(self._onSweep, removed)
57
+ end
58
+ end
59
+
60
+ function self:start()
61
+ self:stop()
62
+ self._loop = Pulse.Loop.new(self._interval, function()
63
+ self:_sweep()
64
+ end)
65
+ self._loop:start()
66
+ end
67
+
68
+ function self:stop()
69
+ if self._loop then
70
+ self._loop:stop()
71
+ self._loop = nil
72
+ end
73
+ end
74
+
75
+ function self:running()
76
+ return self._loop ~= nil and self._loop:running()
77
+ end
78
+
79
+ function self:setInterval(n)
80
+ self._interval = n
81
+ if self._loop then self._loop:setInterval(n) end
82
+ end
83
+
84
+ function self:reset()
85
+ self.totalRemoved = 0
86
+ end
87
+
88
+ return self
89
+ end
90
+
91
+ -- Named registry — register once, access from any component.
92
+ function C.register(name, opts)
93
+ local c = C.new(opts)
94
+ _registry[name] = c
95
+ return c
96
+ end
97
+
98
+ function C.get(name) return _registry[name] end
99
+ function C.startAll() for _, c in pairs(_registry) do c:start() end end
100
+ function C.stopAll() for _, c in pairs(_registry) do c:stop() end end
101
+
102
+ function C.registeredNames()
103
+ local names = {}
104
+ for k in pairs(_registry) do names[#names + 1] = k end
105
+ table.sort(names)
106
+ return names
107
+ end
108
+
109
+ return C
110
+ end)()
@@ -0,0 +1,33 @@
1
+ -- ── Pulse.Conn ────────────────────────────────────────────────────────────────
2
+ -- Named connection manager — one live connection per name, auto-disconnects on rebind.
3
+ -- Replaces the manual func.BindConnection / func.Disconnect pattern.
4
+ -- Usage:
5
+ -- Pulse.Conn.bind("ESP", RunService.Heartbeat:Connect(fn))
6
+ -- Pulse.Conn.disconnect("ESP")
7
+ -- Pulse.Conn.disconnectAll()
8
+
9
+ Pulse.Conn = (function()
10
+ local C = {}
11
+ local _named = {}
12
+
13
+ function C.bind(name, connection)
14
+ if _named[name] then pcall(function() _named[name]:Disconnect() end) end
15
+ _named[name] = connection
16
+ end
17
+
18
+ function C.disconnect(name)
19
+ if _named[name] then
20
+ pcall(function() _named[name]:Disconnect() end)
21
+ _named[name] = nil
22
+ end
23
+ end
24
+
25
+ function C.disconnectAll()
26
+ for _, conn in pairs(_named) do
27
+ pcall(function() conn:Disconnect() end)
28
+ end
29
+ _named = {}
30
+ end
31
+
32
+ return C
33
+ end)()
@@ -0,0 +1,47 @@
1
+ -- ── Pulse.Cooldown ───────────────────────────────────────────────────────────
2
+ -- Per-entity (or global) cooldown tracking.
3
+ -- Replaces manual `lastFireTimes = {}` tables scattered across components.
4
+ -- Usage:
5
+ -- local cd = Pulse.Cooldown.new(1.0) -- single shared cooldown
6
+ -- if cd:ready() then cd:use(); fireRemote() end
7
+ --
8
+ -- local pcd = Pulse.Cooldown.perEntity(0.5) -- one timer per entity
9
+ -- if pcd:ready(player) then pcd:use(player); applyEffect(player) end
10
+ -- pcd:purge(isDead) -- drop entries for dead entities
11
+
12
+ Pulse.Cooldown = (function()
13
+ local C = {}
14
+
15
+ -- A single shared cooldown (one timestamp).
16
+ function C.new(duration)
17
+ local self = { _last = 0, _dur = duration }
18
+ function self:ready() return (tick() - self._last) >= self._dur end
19
+ function self:use() self._last = tick() end
20
+ function self:reset() self._last = 0 end
21
+ function self:set(d) self._dur = d end
22
+ return self
23
+ end
24
+
25
+ -- One cooldown timer per entity (keyed by any value).
26
+ function C.perEntity(duration)
27
+ local self = { _times = {}, _dur = duration }
28
+ function self:ready(key)
29
+ local t = self._times[key]
30
+ return not t or (tick() - t) >= self._dur
31
+ end
32
+ function self:use(key) self._times[key] = tick() end
33
+ function self:reset(key)
34
+ if key then self._times[key] = nil else self._times = {} end
35
+ end
36
+ function self:set(d) self._dur = d end
37
+ -- Remove entries where isDeadFn(entity) returns true.
38
+ function self:purge(isDeadFn)
39
+ for key in pairs(self._times) do
40
+ if isDeadFn(key) then self._times[key] = nil end
41
+ end
42
+ end
43
+ return self
44
+ end
45
+
46
+ return C
47
+ end)()
@@ -0,0 +1,122 @@
1
+ -- ── Pulse.Draw ───────────────────────────────────────────────────────────────
2
+ -- Highlight / Drawing / SelectionBox creation helpers.
3
+ -- Usage:
4
+ -- local hl = Pulse.Draw.highlight(part, "HitboxESP", { fill = Color3.new(1,0,0), fillAlpha = 0.5 })
5
+ -- Pulse.Draw.removeHighlight(part, "HitboxESP")
6
+ -- local ring = Pulse.Draw.circle({ radius = 300, color = Color3.new(1,1,1) })
7
+ -- Pulse.Draw.remove(ring)
8
+
9
+ Pulse.Draw = (function()
10
+ local D = {}
11
+
12
+ -- Create or replace a named Highlight on an instance.
13
+ -- opts: fill, outline, fillAlpha (0–1), outlineAlpha (0–1), adornee, alwaysOnTop
14
+ function D.highlight(target, name, opts)
15
+ if not target then return nil end
16
+ opts = opts or {}
17
+ local old = target:FindFirstChild(name)
18
+ if old then old:Destroy() end
19
+ local h = Instance.new("Highlight")
20
+ h.Name = name
21
+ h.FillColor = opts.fill or Color3.fromRGB(255, 0, 0)
22
+ h.OutlineColor = opts.outline or Color3.fromRGB(255, 255, 255)
23
+ h.FillTransparency = opts.fillAlpha ~= nil and opts.fillAlpha or 0.5
24
+ h.OutlineTransparency = opts.outlineAlpha ~= nil and opts.outlineAlpha or 0
25
+ h.Adornee = opts.adornee or target
26
+ if opts.alwaysOnTop then
27
+ h.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop
28
+ end
29
+ h.Parent = target
30
+ return h
31
+ end
32
+
33
+ -- Destroy a named Highlight on target (no-op if missing).
34
+ function D.removeHighlight(target, name)
35
+ if not target then return end
36
+ local h = target:FindFirstChild(name)
37
+ if h then h:Destroy() end
38
+ end
39
+
40
+ -- Create a Drawing circle (FOV ring, radar dot, etc.).
41
+ -- opts: color, thickness, alpha, filled, radius, visible, sides, position
42
+ function D.circle(opts)
43
+ opts = opts or {}
44
+ local c = Drawing.new("Circle")
45
+ c.Color = opts.color or Color3.fromRGB(255, 255, 255)
46
+ c.Thickness = opts.thickness or 2
47
+ c.Transparency = opts.alpha ~= nil and opts.alpha or 0.8
48
+ c.Filled = opts.filled ~= nil and opts.filled or false
49
+ c.Radius = opts.radius or 100
50
+ c.NumSides = opts.sides or 64
51
+ c.Visible = opts.visible == nil and true or opts.visible
52
+ c.Position = opts.position or Vector2.new(0, 0)
53
+ return c
54
+ end
55
+
56
+ -- Safely remove any Drawing object.
57
+ function D.remove(drawing)
58
+ if drawing then pcall(function() drawing:Remove() end) end
59
+ end
60
+
61
+ -- Create or replace a SelectionBox on target.
62
+ -- opts: color, thickness
63
+ function D.selectionBox(target, name, opts)
64
+ if not target then return nil end
65
+ opts = opts or {}
66
+ local old = target:FindFirstChild(name)
67
+ if old then old:Destroy() end
68
+ local sb = Instance.new("SelectionBox")
69
+ sb.Name = name
70
+ sb.Color3 = opts.color or Color3.fromRGB(255, 0, 0)
71
+ sb.LineThickness = opts.thickness or 0.05
72
+ sb.Adornee = target
73
+ sb.Parent = target
74
+ return sb
75
+ end
76
+
77
+ -- Create or replace a BillboardGui label on a part (name tag, distance, etc.).
78
+ -- opts: text, color, size (UDim2), offset (Vector3), alwaysOnTop, fontSize
79
+ function D.billboard(target, name, opts)
80
+ if not target then return nil end
81
+ opts = opts or {}
82
+ local old = target:FindFirstChild(name)
83
+ if old then old:Destroy() end
84
+ local bg = Instance.new("BillboardGui")
85
+ bg.Name = name
86
+ bg.Size = opts.size or UDim2.new(0, 120, 0, 28)
87
+ bg.StudsOffset = opts.offset or Vector3.new(0, 3, 0)
88
+ bg.AlwaysOnTop = opts.alwaysOnTop ~= false
89
+ bg.Adornee = target
90
+ bg.Parent = target
91
+ local lbl = Instance.new("TextLabel")
92
+ lbl.Size = UDim2.new(1, 0, 1, 0)
93
+ lbl.BackgroundTransparency = 1
94
+ lbl.Text = opts.text or ""
95
+ lbl.TextColor3 = opts.color or Color3.fromRGB(255, 255, 255)
96
+ lbl.TextScaled = true
97
+ lbl.Font = Enum.Font.GothamBold
98
+ lbl.Parent = bg
99
+ return bg
100
+ end
101
+
102
+ -- Destroy a named BillboardGui on target (no-op if missing).
103
+ function D.removeBillboard(target, name)
104
+ if not target then return end
105
+ local b = target:FindFirstChild(name)
106
+ if b then b:Destroy() end
107
+ end
108
+
109
+ -- Destroy every child named `name` found anywhere under `parent`.
110
+ -- Useful for batch cleanup after e.g. a Highlights pass.
111
+ function D.removeAll(name, parent)
112
+ parent = parent or workspace
113
+ local list = parent:GetDescendants()
114
+ for i = 1, #list do
115
+ if list[i].Name == name then
116
+ pcall(function() list[i]:Destroy() end)
117
+ end
118
+ end
119
+ end
120
+
121
+ return D
122
+ end)()
@@ -0,0 +1,63 @@
1
+ -- ── Pulse.Hitbox ──────────────────────────────────────────────────────────────
2
+ -- Uniform size-expansion manager for BaseParts (hitbox stretching).
3
+ -- Game-agnostic: works on any BasePart regardless of game/character structure.
4
+ -- Saves original sizes on first apply and restores them cleanly.
5
+ --
6
+ -- Usage:
7
+ -- local hm = Pulse.Hitbox.new("enemyHitbox")
8
+ -- hm:apply(part, 30) -- expand to 30×30×30, saving original
9
+ -- hm:apply(part, 30) -- idempotent: original already saved
10
+ -- hm:restore(part) -- restore this part to saved size
11
+ -- hm:restoreAll() -- restore all managed parts
12
+ -- hm:isExpanded(part) -- true if part is currently expanded
13
+ --
14
+ -- For visual indicators use Pulse.Draw.selectionBox / Pulse.Draw.highlight separately.
15
+
16
+ Pulse.Hitbox = {}
17
+
18
+ function Pulse.Hitbox.new(tag)
19
+ local self = {}
20
+ local _orig = {} -- part → Vector3 original Size
21
+ local _tag = tag or "hitbox"
22
+
23
+ -- Expand part to a uniform size³ cube, saving the original on first call.
24
+ function self:apply(part, size)
25
+ if not part or not part:IsA("BasePart") then return end
26
+ if not _orig[part] then
27
+ _orig[part] = part.Size
28
+ end
29
+ part.Size = Vector3.new(size, size, size)
30
+ end
31
+
32
+ -- Restore a single part to its saved size. No-op if not managed.
33
+ function self:restore(part)
34
+ if not part then return end
35
+ local orig = _orig[part]
36
+ if orig then
37
+ if part.Parent then pcall(function() part.Size = orig end) end
38
+ _orig[part] = nil
39
+ end
40
+ end
41
+
42
+ -- Restore all managed parts and clear state.
43
+ function self:restoreAll()
44
+ local n = 0
45
+ for part, orig in pairs(_orig) do
46
+ if part and part.Parent then
47
+ pcall(function() part.Size = orig end)
48
+ end
49
+ n = n + 1
50
+ end
51
+ _orig = {}
52
+ if n > 0 and Pulse.Log then
53
+ Pulse.Log.debug(_tag, "restoreAll", { count = n })
54
+ end
55
+ end
56
+
57
+ -- Returns true if this part is currently expanded by this manager.
58
+ function self:isExpanded(part)
59
+ return _orig[part] ~= nil
60
+ end
61
+
62
+ return self
63
+ end
@@ -0,0 +1,24 @@
1
+ -- ── Pulse.Input ──────────────────────────────────────────────────────────────
2
+ -- Key-press simulation using VirtualInputManager + UserInputService.
3
+ -- Usage:
4
+ -- Pulse.Input.simulateKey(Enum.KeyCode.T)
5
+
6
+ Pulse.Input = (function()
7
+ local I = {}
8
+
9
+ function I.simulateKey(keyCode)
10
+ pcall(function()
11
+ _VIM:SendKeyEvent(true, keyCode, false, game)
12
+ task.wait(0.1)
13
+ _VIM:SendKeyEvent(false, keyCode, false, game)
14
+ end)
15
+ pcall(function()
16
+ local ev = { KeyCode = keyCode, UserInputType = Enum.UserInputType.Keyboard }
17
+ _PulseUIS.InputBegan:Fire(ev, false)
18
+ task.wait(0.05)
19
+ _PulseUIS.InputEnded:Fire(ev, false)
20
+ end)
21
+ end
22
+
23
+ return I
24
+ end)()