Signals
Signals are the foundation of Pulse. Think of them like SolidJS createSignal — a value that notifies subscribers when it changes.
Creating a signal
const enabled = signal(false) // boolean signal, default false
const speed = signal(16) // number signal, default 16
const mode = signal('Normal') // string signal
Call signal() inside defineComponent. The value is reactive — anything that reads it can react to changes.
Reading a signal
Call it like a function:
enabled() // → false
speed() // → 16
Writing a signal
Use .set():
enabled.set(true)
speed.set(250)
Or .toggle() for booleans:
enabled.toggle() // false → true → false
Or .update() for a transform:
speed.update(v => v + 10)
Reacting to changes — on.signal
// Like SolidJS createEffect — runs immediately and whenever enabled changes
on.signal(enabled, (v) => {
if (v) startLoop()
else stopLoop()
})
You can watch multiple signals:
on.signal(fov, applyFov)
on.signal(enabled, applyFov)
Computed signals
// Derived value — auto-updates when enabled or speed change
const isActive = computed(() => enabled() && speed() > 0)
isActive() // → true/false
The when guard on event handlers
Any on.* handler accepts { when: signal } to gate it:
on.heartbeat({ when: enabled }, () => {
// skipped entirely when enabled() === false
const h = _PulseGetHumanoid()
if (h) h.WalkSpeed = speed()
})
This is the core Pulse pattern. Feature logic only runs while the feature is active.
Throttled handlers — every
on.heartbeat({ when: enabled, every: 0.1 }, () => {
// runs 10 times/sec instead of 60
})
on.heartbeat({ when: enabled, every: interval }, () => {
// interval is a signal — throttle adapts at runtime
})
Binding a signal to a widget
Widgets are declared with .bind(signal):
return [
toggle('Speed Hack').bind(enabled),
slider('Walk Speed', { min: 16, max: 250 }).bind(speed),
]
The binding is bidirectional:
- UI interaction → updates the signal
- Signal write → updates the widget's displayed value
Signals vs local variables
signal() | let / const | |
|---|---|---|
| Drives UI widget | ✓ | ✗ |
on.* handlers react to it | ✓ | ✗ |
| Accessible from other components | ✓ | ✗ |
| Private, internal bookkeeping | ✗ | ✓ |
Use a signal when it controls a UI widget, another component needs it, or you want code to react when it changes.
Use a local variable when it's internal bookkeeping — a cached reference, a counter, a lock state.
defineComponent('Aimbot', () => {
const enabled = signal(false) // drives UI, others react to this
const radius = signal(300) // drives slider, used by other components
let _lock: Model | null = null // internal, not reactive
let _lastFrame = 0 // internal counter
...
})
Watching from another component
Use .watch() to subscribe from outside the component:
// In another component's defineComponent:
Aimbot.enabled.watch((v) => {
if (v) showIndicator()
})
The subscription is automatically cleaned up when the watching component unmounts.