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.
- package/README.md +225 -0
- package/adapters/linoria.lua +233 -0
- package/adapters/windui.llms.txt +366 -0
- package/adapters/windui.lua +505 -0
- package/bin/rb.js +2 -0
- package/dist/index.js +3285 -0
- package/package.json +59 -0
- package/pulse/dev/debuggui.lua +1206 -0
- package/pulse/dev/devconfig.lua +81 -0
- package/pulse/dev/ui/9_DevPanel.lua +384 -0
- package/pulse/helpers/aim.lua +193 -0
- package/pulse/helpers/cache.lua +68 -0
- package/pulse/helpers/cleaner.lua +110 -0
- package/pulse/helpers/conn.lua +33 -0
- package/pulse/helpers/cooldown.lua +47 -0
- package/pulse/helpers/draw.lua +122 -0
- package/pulse/helpers/hitbox.lua +63 -0
- package/pulse/helpers/input.lua +24 -0
- package/pulse/helpers/log.lua +228 -0
- package/pulse/helpers/loop.lua +58 -0
- package/pulse/helpers/memory.lua +48 -0
- package/pulse/helpers/narrate.lua +160 -0
- package/pulse/helpers/notify.lua +51 -0
- package/pulse/helpers/perf.lua +48 -0
- package/pulse/helpers/remote.lua +128 -0
- package/pulse/helpers/restore.lua +59 -0
- package/pulse/helpers/store.lua +39 -0
- package/pulse/helpers/team.lua +83 -0
- package/pulse/helpers/testmode.lua +80 -0
- package/pulse/helpers/trace.lua +111 -0
- package/pulse/helpers/track.lua +85 -0
- package/pulse/helpers/vec.lua +52 -0
- package/pulse/helpers/world.lua +51 -0
- package/pulse/runtime.lua +343 -0
- package/pulse/ui/linoria_settings.lua +55 -0
- package/pulse/ui/windui_settings.lua +87 -0
- package/templates/AGENTS.md +177 -0
- package/templates/CLAUDE.md +424 -0
- package/templates/deploy_config.example +17 -0
- package/templates/example_esp.rblua +69 -0
- package/templates/example_fov.rblua +20 -0
- package/templates/example_speed.rblua +25 -0
- package/templates/gitignore +4 -0
- package/templates/globals.lua +66 -0
- package/templates/layout.rblua +28 -0
- package/templates/module.lua +7 -0
- package/templates/module.rblua +32 -0
- package/templates/page_home.rblua +9 -0
- package/templates/remote.lua +6 -0
- package/templates/remotes.lua +14 -0
- package/vscode/language-configuration.json +35 -0
- package/vscode/package.json +35 -0
- package/vscode/src/extension.js +397 -0
- package/vscode/syntaxes/rblua.tmLanguage.json +126 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# AGENTS.md — {NAME}
|
|
2
|
+
|
|
3
|
+
Roblox script project built with the **rb / Pulse** framework.
|
|
4
|
+
Run `rb docs` (or read `PULSE_DOCS.md` if it exists) for the complete framework reference.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Build
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
rb build # compile + obfuscate → build/script.lua
|
|
12
|
+
rb build --no-obfuscate # compile only
|
|
13
|
+
rb copy # compile + copy to clipboard
|
|
14
|
+
rb lint # static analysis: dead signals, ghost refs, orphan funcs
|
|
15
|
+
rb check # syntax-check compiled output
|
|
16
|
+
rb docs # generate PULSE_DOCS.md full reference
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Architecture rules
|
|
22
|
+
|
|
23
|
+
- Each `.rblua` file = one **component**. Filename = component name.
|
|
24
|
+
- All files in `src/` concatenate into **one flat Lua chunk** — no `require()`, no module system.
|
|
25
|
+
- `local` variables from files compiled earlier are visible in files compiled later.
|
|
26
|
+
- Load order: `globals.lua` → `remotes.lua` → feature modules (alphabetical) → UI files → defaults runner.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Component rules
|
|
31
|
+
|
|
32
|
+
```rblua
|
|
33
|
+
component {
|
|
34
|
+
signal enabled = false -- reactive state
|
|
35
|
+
shared { Key = "value" } -- Pulse.Store cross-component entry
|
|
36
|
+
remote Foo = "Remotes/Foo" -- FireServer wrapper
|
|
37
|
+
invoke Bar = "Remotes/Bar" -- InvokeServer wrapper
|
|
38
|
+
|
|
39
|
+
ui {
|
|
40
|
+
toggle "Enable" -> enabled default=true tip="..."
|
|
41
|
+
slider "Radius" -> radius [50, 800]
|
|
42
|
+
dropdown "Mode" -> mode ["A","B"] default="B"
|
|
43
|
+
button "Reset" -> Reset()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
init {
|
|
47
|
+
local _loop = Pulse.Loop.new(1.0, fn)
|
|
48
|
+
local function privateHelper() ... end -- PRIVATE
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
on enabled { ... } -- signal change (v = new value)
|
|
52
|
+
on Heartbeat when enabled { } -- service event with guard
|
|
53
|
+
on CharacterAdded { } -- fires on spawn/respawn
|
|
54
|
+
on InputBegan(input, gpe) { } -- user input
|
|
55
|
+
|
|
56
|
+
func Toggle() { enabled(not enabled()) } -- PUBLIC method
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Private vs public:**
|
|
61
|
+
- `local function` in `init {}` = private (component-scoped)
|
|
62
|
+
- `func Name() {}` DSL = public (`Component:Name()` callable externally)
|
|
63
|
+
- `func.X = function()` inside `init {}` = **BANNED** (global pollution)
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Signal access
|
|
68
|
+
|
|
69
|
+
| Context | Read | Write |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| `on X {}` handlers | bare name `radius` (auto-mirrored) | `radius(newValue)` |
|
|
72
|
+
| `func {}` / `init {}` | `ComponentName.radius()` | `ComponentName.radius(newValue)` |
|
|
73
|
+
| Other component | `Aimbot.radius()` | `Aimbot.radius(true)` |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Key globals
|
|
78
|
+
|
|
79
|
+
```lua
|
|
80
|
+
_LocalPlayer -- game.Players.LocalPlayer
|
|
81
|
+
_PulseRS -- RunService
|
|
82
|
+
_PulseUIS -- UserInputService
|
|
83
|
+
_PulseGetChar() -- Character (nil-safe)
|
|
84
|
+
_PulseGetHRP() -- HumanoidRootPart (nil-safe)
|
|
85
|
+
func.GetCachedPlayers() -- cached player list (1.5 s TTL)
|
|
86
|
+
Pulse.Notify("msg", secs) -- in-game toast (preferred over _Library direct call)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Key Pulse helpers
|
|
92
|
+
|
|
93
|
+
```lua
|
|
94
|
+
-- Tasks / timing
|
|
95
|
+
Pulse.Loop.new(interval, fn) -- managed repeating task
|
|
96
|
+
Pulse.Cooldown.new(dur) -- shared cooldown
|
|
97
|
+
Pulse.Cooldown.perEntity(dur) -- per-entity cooldown with .purge(isDeadFn)
|
|
98
|
+
|
|
99
|
+
-- Connections / store
|
|
100
|
+
Pulse.Conn.bind("name", conn) -- named connection manager
|
|
101
|
+
Pulse.Conn.disconnect("name")
|
|
102
|
+
Pulse.Store.define/get/set/watch("key") -- cross-component reactive KV
|
|
103
|
+
|
|
104
|
+
-- Combat / targeting
|
|
105
|
+
Pulse.Aim.findNearest(list, opts) -- nearest entity search
|
|
106
|
+
Pulse.Aim.inFOV(pos, radius) -- FOV circle check
|
|
107
|
+
Pulse.Hitbox.new("tag") -- BasePart size-expansion manager
|
|
108
|
+
local r = Pulse.Team.resolver(opts) -- enemy/ally classifier (.isEnemy/.filter/.partition)
|
|
109
|
+
|
|
110
|
+
-- Drawing / ESP
|
|
111
|
+
Pulse.Draw.highlight(inst, "tag", opts)
|
|
112
|
+
Pulse.Draw.removeHighlight(inst, "tag")
|
|
113
|
+
|
|
114
|
+
-- Data / caching
|
|
115
|
+
Pulse.Restore.new() -- save/restore instance properties
|
|
116
|
+
Pulse.Cache.wrap(ttl, fn) -- timed caching of any function
|
|
117
|
+
Pulse.Track.new() -- entity lifecycle tracking
|
|
118
|
+
|
|
119
|
+
-- Notifications (always available)
|
|
120
|
+
Pulse.Notify("msg") -- instant toast
|
|
121
|
+
Pulse.Notify.onToggle(signal, "Name") -- auto on/off toast on signal change
|
|
122
|
+
|
|
123
|
+
-- Executor capability
|
|
124
|
+
Pulse.Memory.supports("writefile") -- bool: UNC fn exists
|
|
125
|
+
Pulse.Memory.requireFrom("Mod", "Child") -- safe Character child require
|
|
126
|
+
|
|
127
|
+
-- Input simulation
|
|
128
|
+
Pulse.Input.simulateKey(Enum.KeyCode.T)
|
|
129
|
+
|
|
130
|
+
-- Live debug monitor (always available)
|
|
131
|
+
Pulse.Monitor.set("key", value) -- track a named value in the debug GUI
|
|
132
|
+
Pulse.Monitor.tick("key") -- increment counter (stops = loop died)
|
|
133
|
+
|
|
134
|
+
-- Logging (dev-only; no-ops in prod)
|
|
135
|
+
Pulse.Log.info/warn/error("Tag", "msg")
|
|
136
|
+
Pulse.Log.throttle("Tag", 5, "debug", "msg") -- at most once per 5 s
|
|
137
|
+
Pulse.Log.watchSignal(signal, "Tag", "name") -- log every signal change
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Game-load guard
|
|
143
|
+
|
|
144
|
+
Wrap features that use Roblox services in `task.spawn` + load check when injecting before the game finishes loading:
|
|
145
|
+
|
|
146
|
+
```lua
|
|
147
|
+
task.spawn(function()
|
|
148
|
+
if not game:IsLoaded() then game.Loaded:Wait() end
|
|
149
|
+
RS:BindToRenderStep("__Key__", Enum.RenderPriority.Last.Value, fn)
|
|
150
|
+
end)
|
|
151
|
+
-- cleanup bind outside spawn so it always fires
|
|
152
|
+
MyComponent:bind("_rs", { Disconnect = function() RS:UnbindFromRenderStep("__Key__") end })
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Obfuscator (Prometheus)
|
|
158
|
+
|
|
159
|
+
`rb/prometheus_config.lua` overrides the default preset when present. Exclude these steps — they break Roblox runtime:
|
|
160
|
+
|
|
161
|
+
| Step | Reason |
|
|
162
|
+
|---|---|
|
|
163
|
+
| `Vmify` | Breaks member-access patterns |
|
|
164
|
+
| `AntiTamper` | Requires `debug` library — unavailable in exploits |
|
|
165
|
+
| `EncryptStrings` | Corrupts strings used as service/member names |
|
|
166
|
+
|
|
167
|
+
Safe: `ConstantArray` (StringsOnly) + `NumbersToExpressions` + `WrapInFunction`.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## What NOT to do
|
|
172
|
+
|
|
173
|
+
- No `require()` — flat compilation
|
|
174
|
+
- No `func.X = function()` inside component `init {}` — use `local function`
|
|
175
|
+
- No `GetChildren()` in tight loops — use `func.GetCachedPlayers()` / cached helpers
|
|
176
|
+
- No game-specific code in `rb/pulse/helpers/` — framework is game-agnostic
|
|
177
|
+
- No `wait()` / `spawn()` — use `task.wait()` / `task.spawn()` / `task.delay()`
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
# CLAUDE.md — Pulse Framework Reference
|
|
2
|
+
|
|
3
|
+
> **Project:** `{NAME}` — Roblox script built with the **rb / Pulse** framework.
|
|
4
|
+
> **Architecture:** flat-compiled reactive DSL. All `.rblua` and `.lua` files in `src/` are concatenated into one Lua chunk at build time.
|
|
5
|
+
> Run `rb docs` to generate `PULSE_DOCS.md` in this directory for the full framework reference.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Build commands
|
|
10
|
+
|
|
11
|
+
| Command | Description |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `rb build` | Compile + obfuscate → `build/script.lua` |
|
|
14
|
+
| `rb build --no-obfuscate` | Compile only, no obfuscation |
|
|
15
|
+
| `rb copy` | Compile and copy to clipboard |
|
|
16
|
+
| `rb watch` | Auto-rebuild on file save |
|
|
17
|
+
| `rb lint` | Dead signals, ghost refs, orphan funcs |
|
|
18
|
+
| `rb docs` | Generate `PULSE_DOCS.md` full reference |
|
|
19
|
+
| `rb check` | Syntax-check compiled output |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Project layout
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
src/
|
|
27
|
+
misc/helpers/globals.lua ← compiled first — defines local func = {}
|
|
28
|
+
misc/remotes.lua ← func.Remote_X fire-server wrappers
|
|
29
|
+
<category>/<Name>.rblua ← components (one per feature)
|
|
30
|
+
ui/layout.rblua ← window title / size / toggle key
|
|
31
|
+
ui/pages/*.rblua ← tab layout (mount components)
|
|
32
|
+
build/
|
|
33
|
+
script.lua ← compiled output (never edit directly)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Component structure
|
|
39
|
+
|
|
40
|
+
```rblua
|
|
41
|
+
component {
|
|
42
|
+
-- reactive state
|
|
43
|
+
signal enabled = false
|
|
44
|
+
signal radius = 400
|
|
45
|
+
signal mode = "Normal"
|
|
46
|
+
|
|
47
|
+
-- cross-component reactive store entry
|
|
48
|
+
shared {
|
|
49
|
+
GlobalKey = "defaultValue"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
-- fire-server remote wrapper
|
|
53
|
+
remote Attack = "Remotes/Combat/Attack"
|
|
54
|
+
|
|
55
|
+
-- invoke-server remote wrapper (returns a value)
|
|
56
|
+
invoke GetStats = "Remotes/Combat/GetStats"
|
|
57
|
+
|
|
58
|
+
-- UI widgets (auto-wired to signals, compiled into Linoria)
|
|
59
|
+
ui {
|
|
60
|
+
toggle "Enable" -> enabled default=true tip="Tooltip text"
|
|
61
|
+
slider "Radius" -> radius [50, 800]
|
|
62
|
+
dropdown "Mode" -> mode ["Normal", "Big"] default="Big"
|
|
63
|
+
button "Reset" -> Reset()
|
|
64
|
+
separator
|
|
65
|
+
label "Section heading"
|
|
66
|
+
keybind "Toggle" key="F" -> Toggle()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
-- constructor: private locals and helper functions
|
|
70
|
+
init {
|
|
71
|
+
local lockedTarget = nil
|
|
72
|
+
|
|
73
|
+
local function findTarget()
|
|
74
|
+
-- private: NOT accessible outside this component
|
|
75
|
+
end
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
-- signal change handler (v = new value)
|
|
79
|
+
on enabled {
|
|
80
|
+
if v then ... else ... end
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
-- service event handlers
|
|
84
|
+
on Heartbeat when enabled {
|
|
85
|
+
guard h = humanoid
|
|
86
|
+
guard r = hrp
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
on Heartbeat when enabled every 0.5 {
|
|
90
|
+
-- throttled to at most once per 0.5 s
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
on Heartbeat when enabled every interval {
|
|
94
|
+
-- throttle uses the 'interval' signal value dynamically
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
on CharacterAdded {
|
|
98
|
+
lockedTarget = nil
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
on CharacterRemoving {
|
|
102
|
+
-- cleanup before character is removed
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
on InputBegan(input, gpe) when enabled debounce 0.2 {
|
|
106
|
+
if gpe then return end
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
-- public method (callable as Component:Name() from anywhere)
|
|
110
|
+
func Toggle() {
|
|
111
|
+
enabled(not enabled())
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
func GetTarget() {
|
|
115
|
+
return lockedTarget
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Private vs public — the golden rule
|
|
123
|
+
|
|
124
|
+
| Pattern | Visibility | Use for |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| `local function name()` in `init {}` | Component-private | Internal helpers |
|
|
127
|
+
| `func Name() {}` DSL block | Public (Component:Name()) | API for other components |
|
|
128
|
+
| `func.X = function()` in `init {}` | **BANNED** — global pollution | Never |
|
|
129
|
+
|
|
130
|
+
The `func` table is a shared global used for cross-file helpers defined in `.lua` files.
|
|
131
|
+
Assigning `func.X` from inside a component's `init {}` pollutes that global. Always use `local function` instead.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Signals — reading and writing
|
|
136
|
+
|
|
137
|
+
```lua
|
|
138
|
+
-- Inside handlers (on X {}) — read as bare name (transpiler mirrors it)
|
|
139
|
+
on Heartbeat when enabled {
|
|
140
|
+
if radius > 500 then ... end -- bare read
|
|
141
|
+
radius(200) -- write (call as function)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
-- Inside func {} blocks or init {} — call as function to read
|
|
145
|
+
func PrintState() {
|
|
146
|
+
print(enabled(), radius())
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
-- From another component
|
|
150
|
+
Aimbot.enabled(true) -- write
|
|
151
|
+
local r = Aimbot.radius() -- read
|
|
152
|
+
Aimbot:Toggle() -- call public method
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Events reference
|
|
158
|
+
|
|
159
|
+
| Name | Fires |
|
|
160
|
+
|---|---|
|
|
161
|
+
| `Heartbeat` | Every frame (~60 fps) |
|
|
162
|
+
| `RenderStepped` | Before camera renders |
|
|
163
|
+
| `Stepped` | Physics step |
|
|
164
|
+
| `InputBegan` | Key or mouse button pressed |
|
|
165
|
+
| `InputEnded` | Key or mouse button released |
|
|
166
|
+
| `CharacterAdded` | Player spawned or respawned |
|
|
167
|
+
| `CharacterRemoving` | Character about to be removed |
|
|
168
|
+
| `Respawn` | Legacy alias for CharacterAdded |
|
|
169
|
+
| `signalName` | When that signal changes (v = new value) |
|
|
170
|
+
|
|
171
|
+
**Modifiers:**
|
|
172
|
+
|
|
173
|
+
```rblua
|
|
174
|
+
on Heartbeat when enabled { } -- skip if enabled is false
|
|
175
|
+
on Heartbeat every 0.5 { } -- throttle: at most once per 0.5 s
|
|
176
|
+
on Heartbeat every interval { } -- throttle using signal value
|
|
177
|
+
on Heartbeat when enabled debounce 0.3 { } -- cooldown after firing
|
|
178
|
+
on InputBegan(input, gpe) when enabled { } -- pass event params
|
|
179
|
+
after 2.5 { } -- delayed task (runs once on load)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Guard — nil-safe early return
|
|
185
|
+
|
|
186
|
+
```rblua
|
|
187
|
+
guard h = humanoid -- local h = humanoid; if not h then return end
|
|
188
|
+
guard r = hrp -- same for HumanoidRootPart
|
|
189
|
+
guard character -- return if falsy, no capture
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Character refs** (auto-resolved anywhere in handlers):
|
|
193
|
+
|
|
194
|
+
| Name | Value |
|
|
195
|
+
|---|---|
|
|
196
|
+
| `humanoid` | `Character.Humanoid` |
|
|
197
|
+
| `hrp` | `Character.HumanoidRootPart` |
|
|
198
|
+
| `character` | `LocalPlayer.Character` |
|
|
199
|
+
| `alive` | `true` if Humanoid.Health > 0 |
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Pulse helpers
|
|
204
|
+
|
|
205
|
+
```lua
|
|
206
|
+
-- Managed task loop
|
|
207
|
+
local _loop = Pulse.Loop.new(interval, fn)
|
|
208
|
+
_loop:start() _loop:stop() _loop:running() _loop:setInterval(n)
|
|
209
|
+
-- fn already wrapped in pcall; return false from fn to self-stop
|
|
210
|
+
|
|
211
|
+
-- Cooldowns
|
|
212
|
+
local cd = Pulse.Cooldown.new(1.0) -- single shared cooldown
|
|
213
|
+
cd:ready() cd:use() cd:reset() cd:set(dur)
|
|
214
|
+
|
|
215
|
+
local pcd = Pulse.Cooldown.perEntity(0.5) -- one timer per entity key
|
|
216
|
+
pcd:ready(key) pcd:use(key) pcd:reset(key) pcd:set(dur)
|
|
217
|
+
pcd:purge(isDeadFn) -- drop entries where fn(key) is true
|
|
218
|
+
|
|
219
|
+
-- Named connection manager
|
|
220
|
+
Pulse.Conn.bind("Name", connection) -- registers + auto-disconnects old
|
|
221
|
+
Pulse.Conn.disconnect("Name")
|
|
222
|
+
Pulse.Conn.disconnectAll()
|
|
223
|
+
|
|
224
|
+
-- Cross-component reactive KV store
|
|
225
|
+
Pulse.Store.define("Key", defaultValue)
|
|
226
|
+
Pulse.Store.get("Key")
|
|
227
|
+
Pulse.Store.set("Key", value)
|
|
228
|
+
Pulse.Store.watch("Key", fn)
|
|
229
|
+
Pulse.Store.signal("Key") -- returns the raw Signal
|
|
230
|
+
|
|
231
|
+
-- Targeting / aiming
|
|
232
|
+
Pulse.Aim.inFOV(worldPos, pixelRadius) -- bool: is position inside FOV circle?
|
|
233
|
+
Pulse.Aim.lookAt(worldPos) -- snap camera to world position
|
|
234
|
+
Pulse.Aim.findNearest(list, {
|
|
235
|
+
maxDist = 500,
|
|
236
|
+
fovRadius = radius(),
|
|
237
|
+
filter = function(e) return not func.IsDead(e) end,
|
|
238
|
+
getRoot = function(e) return e:FindFirstChild("HumanoidRootPart") end,
|
|
239
|
+
origin = someVector3, -- defaults to local player HRP
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
-- Drawing / ESP
|
|
243
|
+
Pulse.Draw.highlight(instance, "Tag", {
|
|
244
|
+
fill = Color3.fromRGB(255,255,0), outline = Color3.fromRGB(255,0,0),
|
|
245
|
+
fillAlpha = 0.5, alwaysOnTop = true,
|
|
246
|
+
})
|
|
247
|
+
Pulse.Draw.removeHighlight(instance, "Tag")
|
|
248
|
+
local circle = Pulse.Draw.circle({ radius=300, color=Color3.new(1,1,1), thickness=2, alpha=0.8 })
|
|
249
|
+
circle.Position = Vector2.new(cx, cy)
|
|
250
|
+
Pulse.Draw.remove(circle)
|
|
251
|
+
|
|
252
|
+
-- Timed cache
|
|
253
|
+
local getTitans = Pulse.Cache.wrap(1.5, function()
|
|
254
|
+
return workspace.Titans.Alive:GetChildren()
|
|
255
|
+
end)
|
|
256
|
+
|
|
257
|
+
-- Save / restore instance properties
|
|
258
|
+
local r = Pulse.Restore.new()
|
|
259
|
+
r:save(part, "Size") -- store current value
|
|
260
|
+
r:one(part, "Size") -- restore one property
|
|
261
|
+
r:all() -- restore everything
|
|
262
|
+
r:has(part, "Size") -- bool
|
|
263
|
+
|
|
264
|
+
-- Entity lifecycle tracking
|
|
265
|
+
local tracker = Pulse.Track.new()
|
|
266
|
+
tracker:apply(entity, cleanupFn) -- track + register cleanup
|
|
267
|
+
tracker:remove(entity) -- remove + run cleanup
|
|
268
|
+
tracker:cleanup(isDeadFn) -- remove all where predicate is true
|
|
269
|
+
tracker:clear() -- remove everything
|
|
270
|
+
tracker:has(entity) -- bool
|
|
271
|
+
tracker:count()
|
|
272
|
+
tracker:each(fn)
|
|
273
|
+
|
|
274
|
+
-- Logging (dev-only — no-ops in prod; levels: trace < debug < info < warn < error)
|
|
275
|
+
Pulse.Log.trace("Tag", "msg") Pulse.Log.debug("Tag", "msg")
|
|
276
|
+
Pulse.Log.info("Tag", "msg") Pulse.Log.warn("Tag", "msg") Pulse.Log.error("Tag", "msg")
|
|
277
|
+
Pulse.Log.assert(cond, "Tag", "msg") -- logs ERROR if cond is false
|
|
278
|
+
Pulse.Log.throttle("Tag", 5, "debug", "msg") -- at most once per 5 s; safe in loops
|
|
279
|
+
Pulse.Log.watchSignal(signal, "Tag", "name") -- log every signal change
|
|
280
|
+
Pulse.Log.snapshot("Tag", "label", tbl) -- dump table as debug entry
|
|
281
|
+
Pulse.Log.configure({ level="debug", file="dev.log", tags={"Aimbot"} })
|
|
282
|
+
Pulse.Log.save("pulse_log.txt") -- write buffer to file
|
|
283
|
+
Pulse.Log.dump() -- return buffer as string
|
|
284
|
+
Pulse.Log.clear()
|
|
285
|
+
|
|
286
|
+
-- Live debug monitor (always available — use in Heartbeat loops to prove execution)
|
|
287
|
+
Pulse.Monitor.set("key", value) -- set a named live value
|
|
288
|
+
Pulse.Monitor.tick("key") -- increment counter (stops incrementing = loop died)
|
|
289
|
+
Pulse.Monitor.get("key") -- read one value
|
|
290
|
+
Pulse.Monitor.getAll() -- { key=value, ... }
|
|
291
|
+
|
|
292
|
+
-- Notifications (always available)
|
|
293
|
+
Pulse.Notify("Message") -- instant toast (3 s)
|
|
294
|
+
Pulse.Notify("Message", 5) -- custom duration
|
|
295
|
+
Pulse.Notify.onToggle(signal, "FeatureName") -- auto "on"/"off" toast on toggle
|
|
296
|
+
Pulse.Notify.onToggle(signal, "AutoFarm", {
|
|
297
|
+
on="AutoFarm started", off="AutoFarm stopped", duration=5,
|
|
298
|
+
}) -- returns unsubscribe fn
|
|
299
|
+
|
|
300
|
+
-- Hitbox expansion (game-agnostic BasePart size manager)
|
|
301
|
+
local hm = Pulse.Hitbox.new("tag")
|
|
302
|
+
hm:apply(part, 30) -- expand to 30×30×30, saves original on first call
|
|
303
|
+
hm:restore(part) -- restore to saved size
|
|
304
|
+
hm:restoreAll() -- restore all managed parts
|
|
305
|
+
hm:isExpanded(part) -- bool
|
|
306
|
+
|
|
307
|
+
-- Key simulation
|
|
308
|
+
Pulse.Input.simulateKey(Enum.KeyCode.T)
|
|
309
|
+
|
|
310
|
+
-- Executor capability checks
|
|
311
|
+
Pulse.Memory.supports("writefile") -- bool: UNC function exists
|
|
312
|
+
Pulse.Memory.testWritable(tbl, key) -- bool: field is actually writable
|
|
313
|
+
Pulse.Memory.requireFrom("ODMG", "Client", "Memory") -- safe Character child require
|
|
314
|
+
|
|
315
|
+
-- Enemy/ally resolver factory
|
|
316
|
+
local r = Pulse.Team.resolver({
|
|
317
|
+
isSelf = function(e) return e == _LocalPlayer end,
|
|
318
|
+
isValid = function(e) return e.Character ~= nil end,
|
|
319
|
+
isHostile = function(e) return func.IsEnemy(e) end,
|
|
320
|
+
exclude = { func.IsFriendly },
|
|
321
|
+
})
|
|
322
|
+
r:isEnemy(player) -- bool
|
|
323
|
+
r:isAlly(player) -- bool
|
|
324
|
+
r:filter(playerList) -- enemies only
|
|
325
|
+
r:partition(playerList) -- allies, enemies
|
|
326
|
+
|
|
327
|
+
-- Frame-time sampler (call Pulse.Perf.tick() in a Heartbeat to track perf)
|
|
328
|
+
Pulse.Perf.tick() -- sample current frame time
|
|
329
|
+
Pulse.Perf.avg() -- average frame time in seconds
|
|
330
|
+
Pulse.Perf.fps() -- estimated FPS
|
|
331
|
+
Pulse.Perf.setThreshold(50) -- warn when avg > 50 ms
|
|
332
|
+
|
|
333
|
+
-- Workspace navigation
|
|
334
|
+
Pulse.World.find("Folder", "SubFolder") -- nil if missing
|
|
335
|
+
Pulse.World.children("Folder", "SubFolder") -- {} on failure
|
|
336
|
+
Pulse.World.await(parent, "ChildName", timeout)
|
|
337
|
+
|
|
338
|
+
-- Vec helpers
|
|
339
|
+
Pulse.Vec.flatDir(from, to, fallback) -- XZ-plane normalized direction
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Globals available everywhere
|
|
345
|
+
|
|
346
|
+
```lua
|
|
347
|
+
_LocalPlayer -- game.Players.LocalPlayer
|
|
348
|
+
_PulseRS -- game:GetService("RunService")
|
|
349
|
+
_PulseUIS -- game:GetService("UserInputService")
|
|
350
|
+
_PulseGetChar() -- LocalPlayer.Character (nil-safe)
|
|
351
|
+
_PulseGetHRP() -- Character.HumanoidRootPart (nil-safe)
|
|
352
|
+
_PulseGetHumanoid() -- Character.Humanoid (nil-safe)
|
|
353
|
+
_PulseGetAlive() -- bool: health > 0
|
|
354
|
+
|
|
355
|
+
func.GetCachedPlayers() -- cached player list (1.5 s TTL)
|
|
356
|
+
func.GetCachedTitans() -- cached titan list (game-specific, if defined)
|
|
357
|
+
|
|
358
|
+
_Library -- WindUI library instance (ui_library = "windui" default)
|
|
359
|
+
|
|
360
|
+
Components.Name -- access any component by name
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Flat compilation order
|
|
366
|
+
|
|
367
|
+
1. `rb/pulse/runtime.lua` + `rb/pulse/helpers/*.lua` — framework (auto-injected)
|
|
368
|
+
2. `rb/adapters/windui.lua` — UI adapter (auto-injected; controlled by `ui_library` in layout.rblua, defaults to `"windui"`)
|
|
369
|
+
3. `src/misc/helpers/globals.lua` — your bootstrap (`local func = {}` etc.)
|
|
370
|
+
4. `src/misc/remotes.lua` — remote wrappers
|
|
371
|
+
5. All other `src/**/*.rblua|.lua` — alphabetical by path
|
|
372
|
+
6. `src/ui/layout.rblua` then `src/ui/pages/*.rblua` — UI wiring
|
|
373
|
+
7. Generated `_DEFAULTS_RUNNER` — applies all `default=` values after 0.5 s
|
|
374
|
+
|
|
375
|
+
**Key consequence:** `local` variables from earlier files **are** visible in later files as Lua upvalues. This is intentional — `func.GetCachedPlayers` defined in `globals.lua` is accessible everywhere.
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Game-load guard
|
|
380
|
+
|
|
381
|
+
For features that activate Roblox services that may not be ready when the script is injected early, defer activation with:
|
|
382
|
+
|
|
383
|
+
```lua
|
|
384
|
+
init {
|
|
385
|
+
task.spawn(function()
|
|
386
|
+
if not game:IsLoaded() then game.Loaded:Wait() end
|
|
387
|
+
-- safe to use RunService, workspace services, etc. here
|
|
388
|
+
RS:BindToRenderStep("__Key__", Enum.RenderPriority.Last.Value, function()
|
|
389
|
+
-- ...
|
|
390
|
+
end)
|
|
391
|
+
end)
|
|
392
|
+
|
|
393
|
+
-- cleanup bind OUTSIDE spawn so it always fires even if load hasn't completed
|
|
394
|
+
MyComponent:bind("_rs", { Disconnect = function()
|
|
395
|
+
RS:UnbindFromRenderStep("__Key__")
|
|
396
|
+
end })
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## Obfuscator config (Prometheus)
|
|
403
|
+
|
|
404
|
+
If `rb/prometheus_config.lua` exists it overrides the default `--preset`. Exclude steps that break the runtime:
|
|
405
|
+
|
|
406
|
+
| Step | Why to exclude |
|
|
407
|
+
|---|---|
|
|
408
|
+
| `Vmify` | Breaks Roblox member-access patterns at runtime |
|
|
409
|
+
| `AntiTamper` | Uses `debug` library — unavailable in exploit environments |
|
|
410
|
+
| `EncryptStrings` | Strings used as service/member names are corrupted → `X is not a valid member` errors |
|
|
411
|
+
|
|
412
|
+
Minimal safe set: `ConstantArray` (StringsOnly), `NumbersToExpressions`, `WrapInFunction`.
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## What NOT to do
|
|
417
|
+
|
|
418
|
+
- **Do not** use `require()` anywhere — flat compilation, no module system
|
|
419
|
+
- **Do not** assign `func.X = function()` inside a component's `init {}` — use `local function`
|
|
420
|
+
- **Do not** call `GetChildren()` in tight loops — use `func.GetCachedPlayers()` / `func.GetCachedTitans()`
|
|
421
|
+
- **Do not** put game-specific code in `rb/pulse/helpers/` — it is a game-agnostic framework library
|
|
422
|
+
- **Do not** use `Components.SomeComponent.x()` to reference your **own** component's signals — use `ComponentName.x()` directly
|
|
423
|
+
- **Do not** use `wait()` or `spawn()` — always use `task.wait()` / `task.spawn()` / `task.delay()`
|
|
424
|
+
- **Do not** nest `WaitForChild` chains inside loops or callbacks — cache at the top of `init {}`
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# .rb-deploy — GitHub deployment config for rb deploy
|
|
2
|
+
# Copy this file to .rb-deploy and fill in your details.
|
|
3
|
+
# .rb-deploy is gitignored — never commit it (it contains your token).
|
|
4
|
+
|
|
5
|
+
# GitHub Personal Access Token — needs 'repo' and 'contents' scope
|
|
6
|
+
# Create one at: https://github.com/settings/tokens
|
|
7
|
+
GITHUB_TOKEN=ghp_your_token_here
|
|
8
|
+
|
|
9
|
+
# The GitHub repo to push the obfuscated script to
|
|
10
|
+
# Create a separate empty public repo for this (e.g. "yourname/my-script-release")
|
|
11
|
+
GITHUB_REPO=yourname/my-script-release
|
|
12
|
+
|
|
13
|
+
# Filename in the repo (default is fine)
|
|
14
|
+
GITHUB_FILE=script.obf.lua
|
|
15
|
+
|
|
16
|
+
# Branch to push to
|
|
17
|
+
GITHUB_BRANCH=main
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
-- PlayerESP — example component. Customize or delete this file.
|
|
2
|
+
component {
|
|
3
|
+
signal enabled = false
|
|
4
|
+
|
|
5
|
+
init {
|
|
6
|
+
Pulse.Notify.onToggle(PlayerESP.enabled, "Player ESP")
|
|
7
|
+
|
|
8
|
+
local _CoreGui = game:GetService("CoreGui")
|
|
9
|
+
local _Players = game:GetService("Players")
|
|
10
|
+
local _highlights = {}
|
|
11
|
+
|
|
12
|
+
local function _addHighlight(player)
|
|
13
|
+
if not player.Character then return end
|
|
14
|
+
if _highlights[player] then return end
|
|
15
|
+
local hl = Instance.new("Highlight")
|
|
16
|
+
hl.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop
|
|
17
|
+
hl.FillColor = Color3.fromRGB(255, 60, 60)
|
|
18
|
+
hl.FillTransparency = 0.4
|
|
19
|
+
hl.OutlineColor = Color3.fromRGB(255, 60, 60)
|
|
20
|
+
hl.Adornee = player.Character
|
|
21
|
+
hl.Parent = _CoreGui
|
|
22
|
+
_highlights[player] = hl
|
|
23
|
+
Pulse.Log.trace("PlayerESP", "highlighted", { name = player.Name })
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
local function _removeHighlight(player)
|
|
27
|
+
if _highlights[player] then
|
|
28
|
+
_highlights[player]:Destroy()
|
|
29
|
+
_highlights[player] = nil
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
local function _clearAll()
|
|
34
|
+
for _, hl in pairs(_highlights) do hl:Destroy() end
|
|
35
|
+
_highlights = {}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
local _loop = Pulse.Loop.new(1.0, function()
|
|
39
|
+
for _, player in ipairs(func.GetCachedPlayers()) do
|
|
40
|
+
if player ~= _Players.LocalPlayer then
|
|
41
|
+
_addHighlight(player)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end)
|
|
45
|
+
|
|
46
|
+
local function espLoop(value)
|
|
47
|
+
if value then
|
|
48
|
+
_loop:start()
|
|
49
|
+
Pulse.Log.info("PlayerESP", "started")
|
|
50
|
+
else
|
|
51
|
+
_loop:stop()
|
|
52
|
+
_clearAll()
|
|
53
|
+
Pulse.Log.info("PlayerESP", "stopped")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
on enabled { espLoop(v) }
|
|
59
|
+
|
|
60
|
+
on CharacterAdded {
|
|
61
|
+
if not enabled then return end
|
|
62
|
+
_clearAll()
|
|
63
|
+
_loop:start()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
ui {
|
|
67
|
+
toggle "Player ESP" -> enabled tip="Highlight all players through walls"
|
|
68
|
+
}
|
|
69
|
+
}
|