@rb-pulse/core 1.2.24 → 1.3.0
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/index.ts +296 -345
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -1,399 +1,350 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @pulse/core —
|
|
2
|
+
* @pulse/core — Global ambient declarations for Pulse framework TypeScript scripts.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Mental model:
|
|
5
|
+
* - SolidJS-style reactive signals: `signal(default)` returns a PulseSignal<T>.
|
|
6
|
+
* Call it to read, `.set()` to write, `.watch()` to subscribe — just like
|
|
7
|
+
* SolidJS `createSignal` but without the getter/setter tuple split.
|
|
8
|
+
* - Next.js-style file-based pages: place `src/pages/1_Home.ts`, `2_Combat.ts`…
|
|
9
|
+
* Each file calls `definePage(...)` at the top level — tab order is determined
|
|
10
|
+
* by the numeric filename prefix, just like Next.js routes.
|
|
11
|
+
* - Components are SolidJS-style setup functions: call `defineComponent(name, setup)`
|
|
12
|
+
* where `setup` declares signals, registers `on.*` handlers, and returns widgets.
|
|
13
|
+
* - All APIs are Lua globals — no imports needed. TypeScript sees them via this
|
|
14
|
+
* `declare global {}` block. TSTL will NOT emit any `require()` calls.
|
|
6
15
|
*
|
|
7
|
-
*
|
|
8
|
-
* ```typescript
|
|
9
|
-
* import { defineComponent, signal, on } from '@pulse/core'
|
|
10
|
-
* import { toggle, slider } from '@pulse/ui'
|
|
11
|
-
*
|
|
12
|
-
* export const KillAura = defineComponent(() => {
|
|
13
|
-
* const enabled = signal(false)
|
|
14
|
-
* const range = signal(50)
|
|
15
|
-
*
|
|
16
|
-
* on.heartbeat({ when: enabled, every: 0.1 }, dt => {
|
|
17
|
-
* // runs every 0.1 s while enabled === true
|
|
18
|
-
* })
|
|
19
|
-
*
|
|
20
|
-
* return [
|
|
21
|
-
* toggle('Kill Aura').bind(enabled),
|
|
22
|
-
* slider('Range', { min: 1, max: 500 }).bind(range),
|
|
23
|
-
* ]
|
|
24
|
-
* })
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
// ── Signal ─────────────────────────────────────────────────────────────────────
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Reactive state cell returned by `signal()`.
|
|
32
|
-
*
|
|
33
|
-
* Call it to read the current value; use `.set()` to write.
|
|
34
|
-
* Changes automatically propagate to UI widgets, event guards, and watchers.
|
|
35
|
-
*
|
|
36
|
-
* Compiles to: `Signal(initialValue)` in Lua.
|
|
37
|
-
*/
|
|
38
|
-
export interface Signal<T> {
|
|
39
|
-
/** Read the current value. Compiles to: `signalName()` */
|
|
40
|
-
(): T
|
|
41
|
-
/**
|
|
42
|
-
* Write a new value. Triggers UI, handler, and watcher updates.
|
|
43
|
-
* Compiles to: `signalName.set(value)`
|
|
44
|
-
*/
|
|
45
|
-
set(value: T): void
|
|
46
|
-
/**
|
|
47
|
-
* Toggle the signal value (boolean signals only).
|
|
48
|
-
* Equivalent to `signal.set(!signal())`.
|
|
49
|
-
* Compiles to: `signalName.toggle()`
|
|
50
|
-
*
|
|
51
|
-
* @example
|
|
52
|
-
* const enabled = signal(false)
|
|
53
|
-
* button('Toggle').onClick(() => enabled.toggle())
|
|
54
|
-
*/
|
|
55
|
-
toggle(this: Signal<boolean>): void
|
|
56
|
-
/**
|
|
57
|
-
* Subscribe to value changes. The callback fires immediately with the
|
|
58
|
-
* current value, then on every subsequent change.
|
|
59
|
-
* Returns an unsubscribe function.
|
|
60
|
-
* Compiles to: `signalName.watch(fn)`
|
|
61
|
-
*
|
|
62
|
-
* @example
|
|
63
|
-
* const unsubscribe = enabled.watch(v => {
|
|
64
|
-
* print('enabled changed to', v)
|
|
65
|
-
* })
|
|
66
|
-
* // later: unsubscribe()
|
|
67
|
-
*/
|
|
68
|
-
watch(fn: (value: T) => void): () => void
|
|
69
|
-
/**
|
|
70
|
-
* Mirror this signal's value into another signal on every change.
|
|
71
|
-
* Useful for propagating values across component boundaries.
|
|
72
|
-
* Compiles to: `signalName.mirror(target)`
|
|
73
|
-
*/
|
|
74
|
-
mirror(target: Signal<T>): void
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Derived signal — recomputes when any signal read inside `fn` changes.
|
|
79
|
-
* Read-only; no `.set()`.
|
|
80
|
-
*
|
|
81
|
-
* Compiles to: `Computed(fn)` in Lua.
|
|
82
|
-
*/
|
|
83
|
-
export interface Computed<T> {
|
|
84
|
-
(): T
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// ── Event options ──────────────────────────────────────────────────────────────
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Options for periodic event handlers (`on.heartbeat`, `on.renderStepped`, `on.stepped`).
|
|
91
|
-
* Both fields are optional — omit entirely to run every frame with no guard.
|
|
92
|
-
*/
|
|
93
|
-
export interface HandlerOpts {
|
|
94
|
-
/**
|
|
95
|
-
* Gate: skip the callback while this signal is `false`.
|
|
96
|
-
* The event connection stays alive but the callback is skipped.
|
|
97
|
-
* Compiles to: `when = signalName` in the event binding.
|
|
98
|
-
*/
|
|
99
|
-
when?: Signal<boolean>
|
|
100
|
-
/**
|
|
101
|
-
* Throttle: minimum seconds between callback invocations.
|
|
102
|
-
* Uses an internal accumulator — does not create extra connections.
|
|
103
|
-
* Accepts a number or a reactive `Signal<number>` for live adjustment.
|
|
104
|
-
* Compiles to: `every = value` in the event binding.
|
|
105
|
-
*
|
|
106
|
-
* @default 0 (every frame)
|
|
107
|
-
*/
|
|
108
|
-
every?: number | Signal<number>
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// ── Widget base ────────────────────────────────────────────────────────────────
|
|
112
|
-
|
|
113
|
-
/** Base interface shared by all widget definitions returned from `defineComponent`. */
|
|
114
|
-
export interface WidgetDef {
|
|
115
|
-
/**
|
|
116
|
-
* Bind this widget to a signal so their values stay in sync.
|
|
117
|
-
* The widget writes the signal on user interaction; the signal
|
|
118
|
-
* drives the widget when set programmatically.
|
|
119
|
-
*/
|
|
120
|
-
bind(signal: Signal<any>): this
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// ── Component ──────────────────────────────────────────────────────────────────
|
|
124
|
-
|
|
125
|
-
/** Setup function type for `defineComponent`. */
|
|
126
|
-
export type ComponentSetup = () => WidgetDef[]
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Opaque component handle returned by `defineComponent`.
|
|
130
|
-
* Pass it to `groupbox({ mount: MyComponent })` to embed its widgets.
|
|
131
|
-
*/
|
|
132
|
-
export interface Component<S extends ComponentSetup> {
|
|
133
|
-
readonly _type: 'component'
|
|
134
|
-
readonly _widgets: ReturnType<S>
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// ── Core API ───────────────────────────────────────────────────────────────────
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Define a Pulse component — the primary building block.
|
|
141
|
-
*
|
|
142
|
-
* The setup function runs once on initialisation.
|
|
143
|
-
* Declare signals, register event handlers with `on.*`, then return an array
|
|
144
|
-
* of widget definitions to mount into the component's groupbox.
|
|
145
|
-
* All `on.*` subscriptions are auto-disconnected when the component is destroyed.
|
|
146
|
-
*
|
|
147
|
-
* Compiles to a self-contained Lua IIFE with Signal/bind wiring.
|
|
148
|
-
*
|
|
149
|
-
* @param setup Called once at init. Returns UI widget array.
|
|
16
|
+
* Compiled to Lua via typescript-to-lua (TSTL): `rb build` handles this for you.
|
|
150
17
|
*
|
|
151
18
|
* @example
|
|
152
|
-
*
|
|
19
|
+
* // src/combat/SpeedHack.ts
|
|
20
|
+
* defineComponent('SpeedHack', () => {
|
|
153
21
|
* const enabled = signal(false)
|
|
154
22
|
* const speed = signal(16)
|
|
155
|
-
*
|
|
156
23
|
* on.heartbeat({ when: enabled }, () => {
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* on.respawn(() => {
|
|
161
|
-
* if (enabled()) applySpeed(speed())
|
|
24
|
+
* const h = _PulseGetHumanoid() as any
|
|
25
|
+
* if (h) h.WalkSpeed = speed()
|
|
162
26
|
* })
|
|
163
|
-
*
|
|
164
27
|
* return [
|
|
165
|
-
* toggle('Speed
|
|
166
|
-
* slider('Speed', { min:
|
|
28
|
+
* toggle('Speed Hack').bind(enabled),
|
|
29
|
+
* slider('Walk Speed', { min: 16, max: 250 }).bind(speed),
|
|
167
30
|
* ]
|
|
168
31
|
* })
|
|
169
32
|
*/
|
|
170
|
-
export declare function defineComponent<S extends ComponentSetup>(setup: S): Component<S>
|
|
171
33
|
|
|
172
|
-
|
|
173
|
-
* Create a reactive state cell with an initial value.
|
|
174
|
-
*
|
|
175
|
-
* Compiles to: `Signal(initialValue)` in Lua.
|
|
176
|
-
*
|
|
177
|
-
* @param initialValue The starting value.
|
|
178
|
-
*
|
|
179
|
-
* @example
|
|
180
|
-
* const enabled = signal(false) // Signal<boolean>
|
|
181
|
-
* const range = signal(50) // Signal<number>
|
|
182
|
-
* const mode = signal('Auto') // Signal<string>
|
|
183
|
-
*
|
|
184
|
-
* enabled() // read → false
|
|
185
|
-
* enabled.set(true) // write
|
|
186
|
-
* enabled.toggle() // flip boolean
|
|
187
|
-
* enabled.watch(v => print(v)) // subscribe
|
|
188
|
-
*/
|
|
189
|
-
export declare function signal<T>(initialValue: T): Signal<T>
|
|
34
|
+
declare global {
|
|
190
35
|
|
|
191
|
-
|
|
192
|
-
* Create a derived signal that recomputes automatically when its dependencies change.
|
|
193
|
-
*
|
|
194
|
-
* Compiles to: `Computed(fn)` in Lua.
|
|
195
|
-
*
|
|
196
|
-
* @param fn Pure function reading one or more signals. Must not have side effects.
|
|
197
|
-
*
|
|
198
|
-
* @example
|
|
199
|
-
* const fov = signal(90)
|
|
200
|
-
* const label = computed(() => `FOV: ${fov()}`)
|
|
201
|
-
*
|
|
202
|
-
* // Use in a toggle tooltip or paragraph widget
|
|
203
|
-
* paragraph('Current FOV', label())
|
|
204
|
-
*/
|
|
205
|
-
export declare function computed<T>(fn: () => T): Computed<T>
|
|
36
|
+
// ── Signal ────────────────────────────────────────────────────────────────────
|
|
206
37
|
|
|
207
|
-
// ── Event namespace ────────────────────────────────────────────────────────────
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Event subscription namespace.
|
|
211
|
-
* All connections are automatically cleaned up when the component is destroyed.
|
|
212
|
-
*
|
|
213
|
-
* @example
|
|
214
|
-
* on.heartbeat({ when: enabled, every: 0.1 }, dt => { ... })
|
|
215
|
-
* on.heartbeat(dt => updateDisplay(dt)) // no opts overload
|
|
216
|
-
* on.signal(range, v => applyRange(v)) // signal watcher
|
|
217
|
-
* on.inputBegan(input => handleKey(input))
|
|
218
|
-
* on.respawn(() => reapplyEffects())
|
|
219
|
-
* on.after(0.5, () => init()) // delayed one-shot
|
|
220
|
-
*/
|
|
221
|
-
export declare const on: {
|
|
222
38
|
/**
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
* Compiles to: `on Heartbeat { when = ..., every = ... }` in .rblua.
|
|
39
|
+
* Reactive state cell returned by `signal()`.
|
|
226
40
|
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
41
|
+
* Call it to read the current value. Changes propagate to UI widgets,
|
|
42
|
+
* event guards, and watchers automatically.
|
|
229
43
|
*
|
|
230
|
-
*
|
|
231
|
-
* // Throttled, gated
|
|
232
|
-
* on.heartbeat({ when: enabled, every: 0.1 }, dt => {
|
|
233
|
-
* doWork()
|
|
234
|
-
* })
|
|
235
|
-
*
|
|
236
|
-
* // Every frame, no guard
|
|
237
|
-
* on.heartbeat(dt => updateDisplay(dt))
|
|
44
|
+
* Like SolidJS `createSignal` but without the getter/setter tuple split.
|
|
238
45
|
*/
|
|
239
|
-
|
|
240
|
-
|
|
46
|
+
interface PulseSignal<T> {
|
|
47
|
+
/** Read the current value. */
|
|
48
|
+
(): T
|
|
49
|
+
/** Write a new value. Triggers UI, handler, and watcher updates. */
|
|
50
|
+
set(this: PulseSignal<T>, value: T): void
|
|
51
|
+
/**
|
|
52
|
+
* Toggle the signal value (boolean signals only).
|
|
53
|
+
* Equivalent to `signal.set(!signal())`.
|
|
54
|
+
*/
|
|
55
|
+
toggle(this: PulseSignal<boolean>): void
|
|
56
|
+
/**
|
|
57
|
+
* Subscribe to value changes. Returns an unsubscribe function.
|
|
58
|
+
* Fires immediately with the current value, then on every change.
|
|
59
|
+
*/
|
|
60
|
+
watch(this: PulseSignal<T>, fn: (value: T) => void): () => void
|
|
61
|
+
/**
|
|
62
|
+
* Apply a function to the current value and set the result.
|
|
63
|
+
* @example speed.update(v => v + 10)
|
|
64
|
+
*/
|
|
65
|
+
update(this: PulseSignal<T>, fn: (current: T) => T): void
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ── Event options ─────────────────────────────────────────────────────────────
|
|
241
69
|
|
|
242
70
|
/**
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* @example
|
|
247
|
-
* on.renderStepped({ when: espEnabled }, dt => drawBoxes(dt))
|
|
248
|
-
* on.renderStepped(dt => updateCamera(dt))
|
|
71
|
+
* Options for periodic event handlers (`on.heartbeat`, `on.renderStepped`, `on.stepped`).
|
|
72
|
+
* Both fields are optional — omit entirely to run every frame with no guard.
|
|
249
73
|
*/
|
|
250
|
-
|
|
251
|
-
|
|
74
|
+
interface HandlerOpts {
|
|
75
|
+
/**
|
|
76
|
+
* Gate: skip the callback while this signal is `false`.
|
|
77
|
+
* The event connection stays alive but the callback is skipped.
|
|
78
|
+
*/
|
|
79
|
+
when?: PulseSignal<boolean>
|
|
80
|
+
/**
|
|
81
|
+
* Throttle: minimum seconds between callback invocations.
|
|
82
|
+
* Accepts a number or a reactive `PulseSignal<number>` for live adjustment.
|
|
83
|
+
* @default 0 (every frame)
|
|
84
|
+
*/
|
|
85
|
+
every?: number | PulseSignal<number>
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ── Widget definitions ────────────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
interface ToggleDef {
|
|
91
|
+
bind(this: ToggleDef, sig: PulseSignal<boolean>): ToggleDef
|
|
92
|
+
withTip(this: ToggleDef, text: string): ToggleDef
|
|
93
|
+
withDefault(this: ToggleDef, v: boolean): ToggleDef
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface SliderDef {
|
|
97
|
+
bind(this: SliderDef, sig: PulseSignal<number>): SliderDef
|
|
98
|
+
withTip(this: SliderDef, text: string): SliderDef
|
|
99
|
+
withDefault(this: SliderDef, v: number): SliderDef
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
interface DropdownDef {
|
|
103
|
+
bind(this: DropdownDef, sig: PulseSignal<string>): DropdownDef
|
|
104
|
+
withTip(this: DropdownDef, text: string): DropdownDef
|
|
105
|
+
withDefault(this: DropdownDef, v: string): DropdownDef
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface ButtonDef {
|
|
109
|
+
onClick(this: ButtonDef, fn: () => void): ButtonDef
|
|
110
|
+
bind(this: ButtonDef): ButtonDef
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
type WidgetDef = ToggleDef | SliderDef | DropdownDef | ButtonDef | {
|
|
114
|
+
bind(this: any): any
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ── Component / Page / Layout ────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
/** Opaque handle returned by `defineComponent`. */
|
|
120
|
+
interface ComponentRef {
|
|
121
|
+
readonly _name: string
|
|
122
|
+
readonly _ui: WidgetDef[]
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface GroupboxDef {
|
|
126
|
+
readonly type: 'groupbox'
|
|
127
|
+
readonly side: 'left' | 'right'
|
|
128
|
+
readonly title: string
|
|
129
|
+
readonly icon: string
|
|
130
|
+
readonly mount?: string
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
interface PageDef {
|
|
134
|
+
readonly title: string
|
|
135
|
+
readonly icon: string
|
|
136
|
+
readonly layout: GroupboxDef[]
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
interface LayoutConfig {
|
|
140
|
+
title: string
|
|
141
|
+
author?: string
|
|
142
|
+
toggleKey?: string
|
|
143
|
+
size?: [number, number]
|
|
144
|
+
uiLibrary?: 'windui' | 'linoria'
|
|
145
|
+
theme?: string
|
|
146
|
+
icon?: string
|
|
147
|
+
folder?: string
|
|
148
|
+
acrylic?: boolean
|
|
149
|
+
transparency?: number
|
|
150
|
+
openButtonMobileOnly?: boolean
|
|
151
|
+
openButtonIcon?: string
|
|
152
|
+
themes?: Array<{ name: string; values: Record<string, string> }>
|
|
153
|
+
compatExclude?: string[]
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ── Core API — all are Lua globals, no require() ──────────────────────────────
|
|
252
157
|
|
|
253
158
|
/**
|
|
254
|
-
*
|
|
159
|
+
* SolidJS-style reactive state — see createSignal.
|
|
255
160
|
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*/
|
|
259
|
-
stepped(opts: HandlerOpts, fn: (time: number, dt: number) => void): void
|
|
260
|
-
stepped(fn: (time: number, dt: number) => void): void
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* UserInputService.InputBegan.
|
|
161
|
+
* Creates a reactive state cell with an initial value.
|
|
162
|
+
* Compiles to `Signal(initialValue)` in Lua.
|
|
264
163
|
*
|
|
265
164
|
* @example
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
165
|
+
* const enabled = signal(false) // PulseSignal<boolean>
|
|
166
|
+
* const speed = signal(16) // PulseSignal<number>
|
|
167
|
+
* enabled() // read
|
|
168
|
+
* enabled.set(true) // write
|
|
169
|
+
* enabled.toggle() // flip boolean
|
|
270
170
|
*/
|
|
271
|
-
|
|
171
|
+
function signal<T>(initialValue: T): PulseSignal<T>
|
|
272
172
|
|
|
273
173
|
/**
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
* @example
|
|
277
|
-
* on.inputEnded(input => {
|
|
278
|
-
* if (input.UserInputType === Enum.UserInputType.MouseButton1) release()
|
|
279
|
-
* })
|
|
174
|
+
* Create a derived value that recomputes when its dependencies change.
|
|
175
|
+
* Compiles to `Computed(fn)` in Lua.
|
|
280
176
|
*/
|
|
281
|
-
|
|
177
|
+
function computed<T>(fn: () => T): () => T
|
|
282
178
|
|
|
283
179
|
/**
|
|
284
|
-
*
|
|
285
|
-
* Use this to re-apply effects that attach to the character.
|
|
180
|
+
* SolidJS-style component setup function.
|
|
286
181
|
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
* })
|
|
291
|
-
*/
|
|
292
|
-
respawn(fn: () => void): void
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Player.CharacterAdded — fires when a new character model is added.
|
|
182
|
+
* The setup function runs once on init. Declare signals, register `on.*`
|
|
183
|
+
* handlers, then return an array of widget definitions. All connections are
|
|
184
|
+
* auto-disconnected when the component is destroyed.
|
|
296
185
|
*
|
|
297
186
|
* @example
|
|
298
|
-
*
|
|
299
|
-
* const
|
|
187
|
+
* defineComponent('SpeedHack', () => {
|
|
188
|
+
* const enabled = signal(false)
|
|
189
|
+
* on.heartbeat({ when: enabled }, () => { ... })
|
|
190
|
+
* return [toggle('Speed Hack').bind(enabled)]
|
|
300
191
|
* })
|
|
301
192
|
*/
|
|
302
|
-
|
|
193
|
+
function defineComponent(name: string, setup: () => WidgetDef[]): ComponentRef
|
|
303
194
|
|
|
304
195
|
/**
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
* on.characterRemoving(() => cleanup())
|
|
196
|
+
* Event subscription namespace.
|
|
197
|
+
* All connections are automatically cleaned up when the component is destroyed.
|
|
198
|
+
* Must be called inside a `defineComponent` setup function.
|
|
309
199
|
*/
|
|
310
|
-
|
|
200
|
+
const on: {
|
|
201
|
+
/**
|
|
202
|
+
* RunService.Heartbeat — fires every frame.
|
|
203
|
+
* Like SolidJS createEffect scoped to RunService.Heartbeat.
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* on.heartbeat({ when: enabled, every: 0.1 }, dt => { doWork() })
|
|
207
|
+
* on.heartbeat(dt => updateDisplay(dt))
|
|
208
|
+
*/
|
|
209
|
+
heartbeat(opts: HandlerOpts, fn: (dt: number) => void): void
|
|
210
|
+
heartbeat(fn: (dt: number) => void): void
|
|
211
|
+
|
|
212
|
+
/** RunService.RenderStepped — fires before every frame render (client only). */
|
|
213
|
+
renderStepped(opts: HandlerOpts, fn: (dt: number) => void): void
|
|
214
|
+
renderStepped(fn: (dt: number) => void): void
|
|
215
|
+
|
|
216
|
+
/** RunService.Stepped — fires at the physics step rate. */
|
|
217
|
+
stepped(opts: HandlerOpts, fn: (time: number, dt: number) => void): void
|
|
218
|
+
stepped(fn: (time: number, dt: number) => void): void
|
|
219
|
+
|
|
220
|
+
/** UserInputService.InputBegan. */
|
|
221
|
+
inputBegan(fn: (input: any, gameProcessed: boolean) => void): void
|
|
222
|
+
|
|
223
|
+
/** UserInputService.InputEnded. */
|
|
224
|
+
inputEnded(fn: (input: any, gameProcessed: boolean) => void): void
|
|
225
|
+
|
|
226
|
+
/** Fires when the player's character respawns. */
|
|
227
|
+
respawn(fn: () => void): void
|
|
228
|
+
|
|
229
|
+
/** Player.CharacterAdded — fires when a new character model is added. */
|
|
230
|
+
characterAdded(fn: (character: any) => void): void
|
|
231
|
+
|
|
232
|
+
/** Player.CharacterRemoving — fires just before the character is removed. */
|
|
233
|
+
characterRemoving(fn: (character: any) => void): void
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Subscribe to changes on a signal.
|
|
237
|
+
* Fires immediately with the current value, then on every change.
|
|
238
|
+
*/
|
|
239
|
+
signal<T>(sig: PulseSignal<T>, fn: (val: T) => void): void
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Run a one-shot callback after a delay (seconds).
|
|
243
|
+
* @example on.after(0.5, () => init())
|
|
244
|
+
*/
|
|
245
|
+
after(seconds: number, fn: () => void): void
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ── Widget factory globals ─────────────────────────────────────────────────────
|
|
249
|
+
|
|
250
|
+
/** Toggle widget — checkbox bound to a `PulseSignal<boolean>`. */
|
|
251
|
+
function toggle(label: string, opts?: { tip?: string; default?: boolean }): ToggleDef
|
|
252
|
+
|
|
253
|
+
/** Slider widget — numeric range input. */
|
|
254
|
+
function slider(label: string, opts?: {
|
|
255
|
+
min?: number; max?: number; step?: number; default?: number;
|
|
256
|
+
suffix?: string; tip?: string
|
|
257
|
+
}): SliderDef
|
|
258
|
+
|
|
259
|
+
/** Dropdown widget — selectable list of string options. */
|
|
260
|
+
function dropdown(label: string, opts?: {
|
|
261
|
+
options?: string[]; default?: string; tip?: string
|
|
262
|
+
}): DropdownDef
|
|
263
|
+
|
|
264
|
+
/** Multi-select dropdown widget. */
|
|
265
|
+
function multidropdown(label: string, opts?: {
|
|
266
|
+
options?: string[]; default?: string[]; tip?: string
|
|
267
|
+
}): DropdownDef
|
|
268
|
+
|
|
269
|
+
/** Button widget — triggers a callback when clicked. */
|
|
270
|
+
function button(label: string, fn: () => void, opts?: { tip?: string }): ButtonDef
|
|
271
|
+
function button(label: string, opts?: { tip?: string }): ButtonDef
|
|
272
|
+
|
|
273
|
+
/** Keybind widget — lets the user rebind a hotkey. */
|
|
274
|
+
function keybind(label: string, opts?: { key?: string; tip?: string }): WidgetDef
|
|
275
|
+
|
|
276
|
+
/** Label widget — static non-interactive text. */
|
|
277
|
+
function label(text: string): WidgetDef
|
|
278
|
+
|
|
279
|
+
/** Separator widget — horizontal divider line. */
|
|
280
|
+
function separator(): WidgetDef
|
|
311
281
|
|
|
312
282
|
/**
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
* @param sig The signal to watch.
|
|
319
|
-
* @param fn Called with the new value on every change.
|
|
320
|
-
*
|
|
321
|
-
* @example
|
|
322
|
-
* on.signal(enabled, v => {
|
|
323
|
-
* if (v) activateESP() else deactivateESP()
|
|
324
|
-
* })
|
|
325
|
-
*
|
|
326
|
-
* on.signal(range, v => updateAimRadius(v))
|
|
283
|
+
* Declare a groupbox column in a page.
|
|
284
|
+
* @param side 'left' or 'right' column
|
|
285
|
+
* @param title Groupbox header text
|
|
286
|
+
* @param opts icon, mount (component name string), widgets
|
|
327
287
|
*/
|
|
328
|
-
|
|
288
|
+
function groupbox(side: 'left' | 'right', title: string, opts?: {
|
|
289
|
+
icon?: string; mount?: string; widgets?: WidgetDef[]
|
|
290
|
+
}): GroupboxDef
|
|
329
291
|
|
|
330
292
|
/**
|
|
331
|
-
*
|
|
332
|
-
* Runs inside the component's init phase — useful for deferred setup.
|
|
333
|
-
* Compiles to: `task.delay(seconds, fn)` wrapped in component lifecycle.
|
|
293
|
+
* Next.js-style file-based page tab — place in src/pages/N_Name.ts.
|
|
334
294
|
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
295
|
+
* Each file calls `definePage` at the top level. Tab order is determined
|
|
296
|
+
* by the numeric prefix of the filename (1_Home.ts, 2_Combat.ts, …).
|
|
337
297
|
*
|
|
338
298
|
* @example
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
*
|
|
299
|
+
* // src/pages/1_Home.ts
|
|
300
|
+
* definePage('Home', { icon: 'house' }, () => [
|
|
301
|
+
* groupbox('left', 'Player', { icon: 'person', mount: 'SpeedHack' }),
|
|
302
|
+
* ])
|
|
343
303
|
*/
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
304
|
+
function definePage(
|
|
305
|
+
title: string,
|
|
306
|
+
opts: { icon?: string },
|
|
307
|
+
factory: () => GroupboxDef[],
|
|
308
|
+
): PageDef
|
|
309
|
+
|
|
310
|
+
// ── Roblox globals (minimal stubs) ────────────────────────────────────────────
|
|
311
|
+
|
|
312
|
+
const game: {
|
|
313
|
+
GetService(name: string): any
|
|
314
|
+
HttpGet(url: string): string
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const workspace: {
|
|
318
|
+
CurrentCamera: any
|
|
319
|
+
[key: string]: any
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const Enum: Record<string, Record<string, any>>
|
|
323
|
+
|
|
324
|
+
const Color3: {
|
|
325
|
+
new(r: number, g: number, b: number): any
|
|
326
|
+
fromRGB(r: number, g: number, b: number): any
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const Vector3: {
|
|
330
|
+
new(x: number, y: number, z: number): any
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const CFrame: {
|
|
334
|
+
new(x: number, y: number, z: number): any
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ── Pulse character helpers ───────────────────────────────────────────────────
|
|
338
|
+
|
|
339
|
+
/** Returns `LocalPlayer.Character` or nil. */
|
|
340
|
+
function _PulseGetChar(): any
|
|
341
|
+
/** Returns `HumanoidRootPart` from the character, or nil. */
|
|
342
|
+
function _PulseGetHRP(): any
|
|
343
|
+
/** Returns `Humanoid` from the character, or nil. */
|
|
344
|
+
function _PulseGetHumanoid(): any
|
|
345
|
+
/** Returns true if the local player's humanoid is alive. */
|
|
346
|
+
function _PulseGetAlive(): boolean
|
|
357
347
|
|
|
358
|
-
/** @see @pulse/roblox */
|
|
359
|
-
export interface Model {
|
|
360
|
-
WaitForChild(name: string, timeout?: number): Instance
|
|
361
|
-
FindFirstChild(name: string): Instance | undefined
|
|
362
|
-
FindFirstChildOfClass(className: string): Instance | undefined
|
|
363
|
-
GetChildren(): Instance[]
|
|
364
348
|
}
|
|
365
349
|
|
|
366
|
-
|
|
367
|
-
export interface Instance {
|
|
368
|
-
Name: string
|
|
369
|
-
Parent: Instance | undefined
|
|
370
|
-
Destroy(): void
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/** @see @pulse/roblox */
|
|
374
|
-
export interface BasePart extends Instance {
|
|
375
|
-
Position: Vector3
|
|
376
|
-
CFrame: CFrame
|
|
377
|
-
Size: Vector3
|
|
378
|
-
Anchored: boolean
|
|
379
|
-
CanCollide: boolean
|
|
380
|
-
Transparency: number
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/** @see @pulse/roblox */
|
|
384
|
-
export interface Vector3 {
|
|
385
|
-
X: number; Y: number; Z: number
|
|
386
|
-
Magnitude: number
|
|
387
|
-
Unit: Vector3
|
|
388
|
-
add(other: Vector3): Vector3
|
|
389
|
-
sub(other: Vector3): Vector3
|
|
390
|
-
mul(scalar: number): Vector3
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/** @see @pulse/roblox */
|
|
394
|
-
export interface CFrame {
|
|
395
|
-
Position: Vector3
|
|
396
|
-
LookVector: Vector3
|
|
397
|
-
RightVector: Vector3
|
|
398
|
-
UpVector: Vector3
|
|
399
|
-
}
|
|
350
|
+
export {}
|