@rb-pulse/core 1.3.0 → 1.3.1
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.d.ts +65 -0
- package/package.json +7 -7
- package/types/components.d.ts +162 -0
- package/types/events.d.ts +110 -0
- package/types/globals.d.ts +36 -0
- package/types/runtime.d.ts +99 -0
- package/types/signals.d.ts +77 -0
- package/types/widgets.d.ts +208 -0
- package/index.ts +0 -350
package/index.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rb-pulse/core — TypeScript declarations for the Pulse Roblox scripting framework.
|
|
3
|
+
*
|
|
4
|
+
* Add `"types": ["@rb-pulse/core"]` to your tsconfig `compilerOptions` and every
|
|
5
|
+
* Pulse global (`signal`, `defineComponent`, `on.*`, widget factories, `Pulse`, …)
|
|
6
|
+
* plus the full Roblox API (`game`, `workspace`, `task`, all instance types, …)
|
|
7
|
+
* become available in every `.ts` file without any imports.
|
|
8
|
+
*
|
|
9
|
+
* Package layout:
|
|
10
|
+
* types/signals.d.ts — PulseSignal<T>, signal(), computed()
|
|
11
|
+
* types/events.d.ts — HandlerOpts, on.* subscriptions
|
|
12
|
+
* types/widgets.d.ts — widget interfaces + factory functions
|
|
13
|
+
* types/components.d.ts — defineComponent, definePage, groupbox, LayoutConfig
|
|
14
|
+
* types/runtime.d.ts — Pulse namespace, _PulseGet* character helpers
|
|
15
|
+
*
|
|
16
|
+
* Roblox API types are provided by @rbxts/types (auto-included — no extra config needed).
|
|
17
|
+
*
|
|
18
|
+
* @example tsconfig.json
|
|
19
|
+
* {
|
|
20
|
+
* "compilerOptions": {
|
|
21
|
+
* "strict": true,
|
|
22
|
+
* "noEmit": true,
|
|
23
|
+
* "skipLibCheck": true,
|
|
24
|
+
* "target": "ESNext",
|
|
25
|
+
* "moduleResolution": "bundler",
|
|
26
|
+
* "types": ["@rb-pulse/core"]
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
// Pulse framework globals
|
|
32
|
+
/// <reference path="./types/globals.d.ts" />
|
|
33
|
+
/// <reference path="./types/signals.d.ts" />
|
|
34
|
+
/// <reference path="./types/events.d.ts" />
|
|
35
|
+
/// <reference path="./types/widgets.d.ts" />
|
|
36
|
+
/// <reference path="./types/components.d.ts" />
|
|
37
|
+
/// <reference path="./types/runtime.d.ts" />
|
|
38
|
+
|
|
39
|
+
// ── Named re-exports ───────────────────────────────────────────────────────────
|
|
40
|
+
// Globals are already available without imports (via declare global above).
|
|
41
|
+
// These re-exports let you use explicit `import type` when you want visible types
|
|
42
|
+
// in function signatures, generics, or cross-file type sharing.
|
|
43
|
+
//
|
|
44
|
+
// @example
|
|
45
|
+
// import type { PulseSignal, WidgetDef, LayoutConfig } from '@rb-pulse/core'
|
|
46
|
+
|
|
47
|
+
export type { PulseSignal } from './types/signals'
|
|
48
|
+
export type { HandlerOpts } from './types/events'
|
|
49
|
+
export type {
|
|
50
|
+
ToggleDef,
|
|
51
|
+
SliderDef,
|
|
52
|
+
DropdownDef,
|
|
53
|
+
MultiDropdownDef,
|
|
54
|
+
ButtonDef,
|
|
55
|
+
KeybindDef,
|
|
56
|
+
LabelDef,
|
|
57
|
+
SeparatorDef,
|
|
58
|
+
WidgetDef,
|
|
59
|
+
} from './types/widgets'
|
|
60
|
+
export type {
|
|
61
|
+
ComponentRef,
|
|
62
|
+
GroupboxDef,
|
|
63
|
+
PageDef,
|
|
64
|
+
LayoutConfig,
|
|
65
|
+
} from './types/components'
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rb-pulse/core",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "Pulse framework —
|
|
5
|
-
"
|
|
6
|
-
"types": "./index.ts",
|
|
3
|
+
"version": "1.3.1",
|
|
4
|
+
"description": "Pulse framework — TypeScript type declarations for components, signals, widgets, and the Roblox API",
|
|
5
|
+
"types": "./index.d.ts",
|
|
7
6
|
"files": [
|
|
8
|
-
"index.ts",
|
|
9
|
-
"
|
|
7
|
+
"index.d.ts",
|
|
8
|
+
"types/"
|
|
10
9
|
],
|
|
11
10
|
"keywords": [
|
|
12
11
|
"roblox",
|
|
13
12
|
"pulse",
|
|
14
13
|
"lua",
|
|
15
|
-
"typescript-to-lua"
|
|
14
|
+
"typescript-to-lua",
|
|
15
|
+
"types"
|
|
16
16
|
],
|
|
17
17
|
"license": "MIT"
|
|
18
18
|
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component system, page layout, and window configuration.
|
|
3
|
+
*
|
|
4
|
+
* - `defineComponent` — SolidJS-style reactive component setup
|
|
5
|
+
* - `definePage` — Next.js-style file-based page tabs
|
|
6
|
+
* - `groupbox` — column layout declaration inside a page
|
|
7
|
+
* - `LayoutConfig` — export default from `src/layout.ts`
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/// <reference path="./widgets.d.ts" />
|
|
11
|
+
|
|
12
|
+
declare global {
|
|
13
|
+
|
|
14
|
+
// ── Component ──────────────────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Opaque handle returned by `defineComponent`.
|
|
18
|
+
* Pass to `groupbox({ mount: 'ComponentName' })` to render its widgets.
|
|
19
|
+
*/
|
|
20
|
+
interface ComponentRef {
|
|
21
|
+
readonly _name: string
|
|
22
|
+
readonly _ui: WidgetDef[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Register a reactive component.
|
|
27
|
+
*
|
|
28
|
+
* The `setup` function runs once on init. Declare signals, register `on.*`
|
|
29
|
+
* event handlers, then return an array of widget definitions. All event
|
|
30
|
+
* connections are auto-disconnected when the script re-executes or the
|
|
31
|
+
* component is destroyed (re-execution guard handles this automatically).
|
|
32
|
+
*
|
|
33
|
+
* Components mirror SolidJS function components: pure setup, reactive state,
|
|
34
|
+
* declarative UI return.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* defineComponent('SpeedHack', (): WidgetDef[] => {
|
|
38
|
+
* const enabled = signal<boolean>(false)
|
|
39
|
+
* const speed = signal<number>(16)
|
|
40
|
+
*
|
|
41
|
+
* on.heartbeat({ when: enabled }, (): void => {
|
|
42
|
+
* const h = _PulseGetHumanoid() as any
|
|
43
|
+
* if (h) h.WalkSpeed = speed()
|
|
44
|
+
* })
|
|
45
|
+
*
|
|
46
|
+
* return [
|
|
47
|
+
* toggle('Speed Hack').bind(enabled),
|
|
48
|
+
* slider('Walk Speed', { min: 16, max: 250 }).bind(speed),
|
|
49
|
+
* ]
|
|
50
|
+
* })
|
|
51
|
+
*/
|
|
52
|
+
function defineComponent(name: string, setup: () => WidgetDef[]): ComponentRef
|
|
53
|
+
|
|
54
|
+
// ── Page layout ────────────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Groupbox column inside a page layout.
|
|
58
|
+
* Use `mount` to attach a named component's widgets, or `widgets` for inline widgets.
|
|
59
|
+
*/
|
|
60
|
+
interface GroupboxDef {
|
|
61
|
+
readonly type: 'groupbox'
|
|
62
|
+
readonly side: 'left' | 'right'
|
|
63
|
+
readonly title: string
|
|
64
|
+
readonly icon: string
|
|
65
|
+
readonly mount?: string
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Page tab descriptor returned by `definePage`. */
|
|
69
|
+
interface PageDef {
|
|
70
|
+
readonly title: string
|
|
71
|
+
readonly icon: string
|
|
72
|
+
readonly layout: GroupboxDef[]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Declare a groupbox column inside a `definePage` factory.
|
|
77
|
+
*
|
|
78
|
+
* @param side Column position — `'left'` or `'right'`
|
|
79
|
+
* @param title Header text of the groupbox
|
|
80
|
+
* @param opts `icon` for a lucide icon name; `mount` to attach a component by name;
|
|
81
|
+
* `widgets` for inline widget declarations without a component
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* groupbox('left', 'Player', { icon: 'person', mount: 'SpeedHack' })
|
|
85
|
+
* groupbox('right', 'Visuals', { icon: 'eye', mount: 'PlayerESP' })
|
|
86
|
+
*/
|
|
87
|
+
function groupbox(side: 'left' | 'right', title: string, opts?: {
|
|
88
|
+
icon?: string
|
|
89
|
+
mount?: string
|
|
90
|
+
widgets?: WidgetDef[]
|
|
91
|
+
}): GroupboxDef
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Declare a page tab. Place in `src/pages/N_Name.ts`.
|
|
95
|
+
*
|
|
96
|
+
* Tab order follows the numeric filename prefix: `1_Home.ts`, `2_Combat.ts`, …
|
|
97
|
+
* This mirrors the Next.js file-based routing convention.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* // src/pages/1_Home.ts
|
|
101
|
+
* definePage('Home', { icon: 'house' }, () => [
|
|
102
|
+
* groupbox('left', 'Player', { mount: 'SpeedHack' }),
|
|
103
|
+
* groupbox('right', 'Visuals', { mount: 'PlayerESP' }),
|
|
104
|
+
* ])
|
|
105
|
+
*/
|
|
106
|
+
function definePage(
|
|
107
|
+
title: string,
|
|
108
|
+
opts: { icon?: string },
|
|
109
|
+
factory: () => GroupboxDef[],
|
|
110
|
+
): PageDef
|
|
111
|
+
|
|
112
|
+
// ── Layout configuration ───────────────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Window/layout configuration — export as `default` from `src/layout.ts`.
|
|
116
|
+
* Drives the UI window title, size, theme, and UI library selection.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* // src/layout.ts
|
|
120
|
+
* export default {
|
|
121
|
+
* title: 'My Script',
|
|
122
|
+
* author: 'YourName',
|
|
123
|
+
* uiLibrary: 'windui',
|
|
124
|
+
* size: [850, 560],
|
|
125
|
+
* theme: 'Indigo',
|
|
126
|
+
* folder: 'MyHub',
|
|
127
|
+
* } satisfies LayoutConfig
|
|
128
|
+
*/
|
|
129
|
+
interface LayoutConfig {
|
|
130
|
+
/** Window title displayed in the UI header. */
|
|
131
|
+
title: string
|
|
132
|
+
/** Author subtitle shown below the title. */
|
|
133
|
+
author?: string
|
|
134
|
+
/** Key to toggle the UI open/closed. @default 'RightControl' */
|
|
135
|
+
toggleKey?: string
|
|
136
|
+
/** Window dimensions `[width, height]` in pixels. @default [950, 600] */
|
|
137
|
+
size?: [number, number]
|
|
138
|
+
/** UI library to use. Currently only `'windui'` is supported. */
|
|
139
|
+
uiLibrary?: 'windui'
|
|
140
|
+
/** Theme name (library-specific, e.g. `'Indigo'`, `'Dark'`). */
|
|
141
|
+
theme?: string
|
|
142
|
+
/** Lucide icon name or asset URL for the window icon. */
|
|
143
|
+
icon?: string
|
|
144
|
+
/** Config save folder name (inside executor workspace). */
|
|
145
|
+
folder?: string
|
|
146
|
+
/** Enable acrylic/frosted glass background effect. */
|
|
147
|
+
acrylic?: boolean
|
|
148
|
+
/** Background transparency `[0, 1]`. */
|
|
149
|
+
transparency?: number
|
|
150
|
+
/** Show the open button only on mobile. */
|
|
151
|
+
openButtonMobileOnly?: boolean
|
|
152
|
+
/** Icon for the mobile open button. */
|
|
153
|
+
openButtonIcon?: string
|
|
154
|
+
/** Custom theme overrides. */
|
|
155
|
+
themes?: Array<{ name: string; values: Record<string, string> }>
|
|
156
|
+
/** File paths to exclude from the compat build. */
|
|
157
|
+
compatExclude?: string[]
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export type { ComponentRef, GroupboxDef, PageDef, LayoutConfig }
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event subscription system — RunService, UserInputService, and signal watchers.
|
|
3
|
+
* All connections are automatically cleaned up when the enclosing component is destroyed.
|
|
4
|
+
* Must be called inside a `defineComponent` setup function.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Reference signal types so HandlerOpts can reference PulseSignal<T>
|
|
8
|
+
/// <reference path="./signals.d.ts" />
|
|
9
|
+
|
|
10
|
+
declare global {
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Options for periodic event handlers.
|
|
14
|
+
* Both fields are optional — omit entirely to run every frame with no guard.
|
|
15
|
+
*/
|
|
16
|
+
interface HandlerOpts {
|
|
17
|
+
/**
|
|
18
|
+
* Gate signal — while `false` the callback is skipped each frame.
|
|
19
|
+
* The connection stays alive; toggling to `true` resumes immediately.
|
|
20
|
+
*
|
|
21
|
+
* @example on.heartbeat({ when: enabled }, dt => doWork())
|
|
22
|
+
*/
|
|
23
|
+
when?: PulseSignal<boolean>
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Throttle — minimum seconds between callback invocations.
|
|
27
|
+
* Pass a `PulseSignal<number>` for live adjustment at runtime.
|
|
28
|
+
* @default 0 (every frame)
|
|
29
|
+
*/
|
|
30
|
+
every?: number | PulseSignal<number>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Event subscription namespace.
|
|
35
|
+
*
|
|
36
|
+
* All connections registered via `on.*` are scoped to the current component
|
|
37
|
+
* and auto-disconnected when the script re-executes or the component is destroyed.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* defineComponent('SpeedHack', (): WidgetDef[] => {
|
|
41
|
+
* const enabled = signal<boolean>(false)
|
|
42
|
+
*
|
|
43
|
+
* on.heartbeat({ when: enabled }, dt => applySpeed())
|
|
44
|
+
* on.respawn(() => resetSpeed())
|
|
45
|
+
* on.signal(enabled, v => console.log('enabled:', v))
|
|
46
|
+
*
|
|
47
|
+
* return [toggle('Speed Hack').bind(enabled)]
|
|
48
|
+
* })
|
|
49
|
+
*/
|
|
50
|
+
const on: {
|
|
51
|
+
/**
|
|
52
|
+
* RunService.Heartbeat — fires every physics frame (~60 fps).
|
|
53
|
+
* Equivalent to SolidJS `createEffect` scoped to the RunService.Heartbeat event.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* on.heartbeat({ when: enabled, every: 0.1 }, dt => doWork())
|
|
57
|
+
* on.heartbeat(dt => updateDisplay(dt))
|
|
58
|
+
*/
|
|
59
|
+
heartbeat(opts: HandlerOpts, fn: (dt: number) => void): void
|
|
60
|
+
heartbeat(fn: (dt: number) => void): void
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* RunService.RenderStepped — fires before every render frame (client-only).
|
|
64
|
+
* Use for camera/visual updates that must sync with rendering.
|
|
65
|
+
*/
|
|
66
|
+
renderStepped(opts: HandlerOpts, fn: (dt: number) => void): void
|
|
67
|
+
renderStepped(fn: (dt: number) => void): void
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* RunService.Stepped — fires at the physics step rate.
|
|
71
|
+
* Provides both elapsed time and delta time.
|
|
72
|
+
*/
|
|
73
|
+
stepped(opts: HandlerOpts, fn: (time: number, dt: number) => void): void
|
|
74
|
+
stepped(fn: (time: number, dt: number) => void): void
|
|
75
|
+
|
|
76
|
+
/** UserInputService.InputBegan — fires when any input starts. */
|
|
77
|
+
inputBegan(fn: (input: any, gameProcessed: boolean) => void): void
|
|
78
|
+
|
|
79
|
+
/** UserInputService.InputEnded — fires when any input ends. */
|
|
80
|
+
inputEnded(fn: (input: any, gameProcessed: boolean) => void): void
|
|
81
|
+
|
|
82
|
+
/** Fires each time the local player's character model is added to the world. */
|
|
83
|
+
respawn(fn: () => void): void
|
|
84
|
+
|
|
85
|
+
/** Player.CharacterAdded — fires when a new character model appears. */
|
|
86
|
+
characterAdded(fn: (character: any) => void): void
|
|
87
|
+
|
|
88
|
+
/** Player.CharacterRemoving — fires just before the character is removed. */
|
|
89
|
+
characterRemoving(fn: (character: any) => void): void
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Subscribe to a `PulseSignal` inside a component.
|
|
93
|
+
* Fires immediately with the current value, then on every change.
|
|
94
|
+
* The subscription is auto-cleaned with the component.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* on.signal(speed, v => applySpeed(v))
|
|
98
|
+
*/
|
|
99
|
+
signal<T>(sig: PulseSignal<T>, fn: (val: T) => void): void
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* One-shot callback after a delay in seconds.
|
|
103
|
+
* @example on.after(0.5, () => init())
|
|
104
|
+
*/
|
|
105
|
+
after(seconds: number, fn: () => void): void
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export type { HandlerOpts }
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Roblox Lua globals not declared by @rbxts/types.
|
|
3
|
+
*
|
|
4
|
+
* roblox-ts accesses the workspace via `game.Workspace`, but in standard Roblox
|
|
5
|
+
* Lua (and executor environments) it is also available as the `workspace` global.
|
|
6
|
+
* We declare it here so TypeScript recognises it in Pulse scripts.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
declare global {
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Alias for `game:GetService("Workspace")`.
|
|
13
|
+
* Provides access to the current place's Workspace service.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const cam = workspace.CurrentCamera
|
|
17
|
+
* cam.FieldOfView = 90
|
|
18
|
+
*/
|
|
19
|
+
const workspace: Workspace
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The shared Lua global table.
|
|
23
|
+
* Used internally by the compiler to propagate runtime globals across
|
|
24
|
+
* sandboxed `loadstring` environments in executor contexts.
|
|
25
|
+
*/
|
|
26
|
+
const _G: Record<string, unknown>
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Print to the output console (Roblox Studio / executor output).
|
|
30
|
+
* Accepts any number of values, separated by tabs in the output.
|
|
31
|
+
*/
|
|
32
|
+
function print(...args: unknown[]): void
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse runtime globals — the `Pulse` namespace and character helper functions.
|
|
3
|
+
* These are set up automatically by the CDN bundle before your code runs.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
declare global {
|
|
7
|
+
|
|
8
|
+
// ── Pulse runtime namespace ────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The Pulse runtime namespace.
|
|
12
|
+
* Populated by the CDN bundle and extended by the adapter (Wind UI).
|
|
13
|
+
*
|
|
14
|
+
* `Pulse.UI` is available after the Wind UI adapter initialises the window.
|
|
15
|
+
* `Pulse.Log` and `Pulse.TestMode` are always available.
|
|
16
|
+
*/
|
|
17
|
+
const Pulse: {
|
|
18
|
+
/**
|
|
19
|
+
* Dynamic element builder — populated by the Wind UI adapter.
|
|
20
|
+
* Use this for advanced manual UI construction beyond the standard widget set.
|
|
21
|
+
*/
|
|
22
|
+
UI: {
|
|
23
|
+
/** Get the mounted groupbox container for a component reference. */
|
|
24
|
+
gb(component: ComponentRef): any
|
|
25
|
+
/** Add a rich paragraph (title + description) to a container. */
|
|
26
|
+
paragraph(
|
|
27
|
+
container: any,
|
|
28
|
+
title: string,
|
|
29
|
+
desc: string,
|
|
30
|
+
): { set(title?: string, desc?: string): void }
|
|
31
|
+
/** Add a button to a container. */
|
|
32
|
+
button(container: any, label: string, desc: string, fn: () => void): any
|
|
33
|
+
/** Add a toggle to a container. */
|
|
34
|
+
toggle(
|
|
35
|
+
container: any,
|
|
36
|
+
id: string,
|
|
37
|
+
label: string,
|
|
38
|
+
desc: string,
|
|
39
|
+
defaultVal: boolean,
|
|
40
|
+
fn: (v: boolean) => void,
|
|
41
|
+
): any
|
|
42
|
+
/** Add a slider to a container. */
|
|
43
|
+
slider(
|
|
44
|
+
container: any,
|
|
45
|
+
id: string,
|
|
46
|
+
label: string,
|
|
47
|
+
min: number,
|
|
48
|
+
max: number,
|
|
49
|
+
defaultVal: number,
|
|
50
|
+
fn: (v: number) => void,
|
|
51
|
+
): any
|
|
52
|
+
/** Add a dropdown to a container. */
|
|
53
|
+
dropdown(
|
|
54
|
+
container: any,
|
|
55
|
+
id: string,
|
|
56
|
+
label: string,
|
|
57
|
+
options: string[],
|
|
58
|
+
defaultVal: string | undefined,
|
|
59
|
+
multi: boolean,
|
|
60
|
+
fn: (v: string | string[]) => void,
|
|
61
|
+
): any
|
|
62
|
+
/** Add a collapsible section group to a container. */
|
|
63
|
+
section(container: any, title: string, icon?: string): any
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Structured logging helpers. */
|
|
67
|
+
Log: {
|
|
68
|
+
info(tag: string, msg: string, data?: Record<string, unknown>): void
|
|
69
|
+
warn(tag: string, msg: string, data?: Record<string, unknown>): void
|
|
70
|
+
error(tag: string, msg: string, data?: Record<string, unknown>): void
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Automated test-mode helpers (used by the test harness). */
|
|
74
|
+
TestMode: {
|
|
75
|
+
isActive(): boolean
|
|
76
|
+
isTarget(id: string): boolean
|
|
77
|
+
getTargets(): string[]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ── Character helper functions ─────────────────────────────────────────────────
|
|
82
|
+
// Safe wrappers around LocalPlayer.Character — all return undefined if the
|
|
83
|
+
// character or the specific instance is not present.
|
|
84
|
+
|
|
85
|
+
/** Returns `LocalPlayer.Character` or `undefined`. */
|
|
86
|
+
function _PulseGetChar(): Instance | undefined
|
|
87
|
+
|
|
88
|
+
/** Returns `HumanoidRootPart` from the local character, or `undefined`. */
|
|
89
|
+
function _PulseGetHRP(): BasePart | undefined
|
|
90
|
+
|
|
91
|
+
/** Returns `Humanoid` from the local character, or `undefined`. */
|
|
92
|
+
function _PulseGetHumanoid(): Humanoid | undefined
|
|
93
|
+
|
|
94
|
+
/** Returns `true` while the local humanoid's health is above zero. */
|
|
95
|
+
function _PulseGetAlive(): boolean
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export {}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactive signal primitives — SolidJS-style state atoms.
|
|
3
|
+
* No imports needed: these are Lua globals available in every Pulse script.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
declare global {
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Reactive state cell returned by `signal<T>()`.
|
|
10
|
+
*
|
|
11
|
+
* Call it (no args) to read the current value. Calling `.set()` pushes a new
|
|
12
|
+
* value and propagates it to every bound UI widget, `on.*` guard, and watcher.
|
|
13
|
+
*
|
|
14
|
+
* Mirrors SolidJS `createSignal` but as a single callable object instead of a
|
|
15
|
+
* getter/setter tuple.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* const enabled = signal<boolean>(false)
|
|
19
|
+
* const speed = signal<number>(16)
|
|
20
|
+
*
|
|
21
|
+
* enabled() // → false (read)
|
|
22
|
+
* enabled.set(true) // write, triggers watchers
|
|
23
|
+
* enabled.toggle() // flip boolean in-place
|
|
24
|
+
* speed.update(v => v + 1)
|
|
25
|
+
*/
|
|
26
|
+
interface PulseSignal<T> {
|
|
27
|
+
/** Read the current value. */
|
|
28
|
+
(): T
|
|
29
|
+
|
|
30
|
+
/** Write a new value. No-op if the value hasn't changed. */
|
|
31
|
+
set(this: PulseSignal<T>, value: T): void
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Toggle a boolean signal in-place (`sig.set(!sig())`).
|
|
35
|
+
* Type-constrained to `PulseSignal<boolean>`.
|
|
36
|
+
*/
|
|
37
|
+
toggle(this: PulseSignal<boolean>): void
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Subscribe to value changes.
|
|
41
|
+
* Fires immediately with the current value, then on every subsequent change.
|
|
42
|
+
* @returns Unsubscribe function — call to stop the subscription.
|
|
43
|
+
*/
|
|
44
|
+
watch(this: PulseSignal<T>, fn: (value: T) => void): () => void
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Apply a transform and write the result.
|
|
48
|
+
* @example speed.update(v => v + 10)
|
|
49
|
+
*/
|
|
50
|
+
update(this: PulseSignal<T>, fn: (current: T) => T): void
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Create a reactive state cell with an initial value.
|
|
55
|
+
* Always use an explicit generic so TypeScript infers the correct type.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* const enabled = signal<boolean>(false)
|
|
59
|
+
* const speed = signal<number>(16)
|
|
60
|
+
* const mode = signal<string>('Low')
|
|
61
|
+
* const targets = signal<string[]>([])
|
|
62
|
+
*/
|
|
63
|
+
function signal<T>(initialValue: T): PulseSignal<T>
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create a read-only derived value that recomputes lazily when its dependencies
|
|
67
|
+
* change. The result is cached until invalidated.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* const displaySpeed = computed(() => `Speed: ${speed()}x`)
|
|
71
|
+
* label(displaySpeed())
|
|
72
|
+
*/
|
|
73
|
+
function computed<T>(fn: () => T): () => T
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type { PulseSignal }
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget definitions and factory functions.
|
|
3
|
+
* Every factory returns a builder that you chain to configure and optionally bind to a signal.
|
|
4
|
+
* Return an array of widget defs from `defineComponent` to render them into the UI.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/// <reference path="./signals.d.ts" />
|
|
8
|
+
|
|
9
|
+
declare global {
|
|
10
|
+
|
|
11
|
+
// ── Widget interfaces ──────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Toggle (checkbox) bound to a `PulseSignal<boolean>`.
|
|
15
|
+
* @example toggle('Speed Hack').bind(enabled)
|
|
16
|
+
*/
|
|
17
|
+
interface ToggleDef {
|
|
18
|
+
/** Two-way bind to a boolean signal — UI changes update the signal, signal changes update UI. */
|
|
19
|
+
bind(this: ToggleDef, sig: PulseSignal<boolean>): ToggleDef
|
|
20
|
+
/** Tooltip text shown on hover. */
|
|
21
|
+
withTip(this: ToggleDef, text: string): ToggleDef
|
|
22
|
+
/** Persisted default value loaded from config on startup. */
|
|
23
|
+
withDefault(this: ToggleDef, v: boolean): ToggleDef
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Slider (range input) bound to a `PulseSignal<number>`.
|
|
28
|
+
* @example slider('Walk Speed', { min: 16, max: 250 }).bind(speed)
|
|
29
|
+
*/
|
|
30
|
+
interface SliderDef {
|
|
31
|
+
/** Two-way bind to a numeric signal. */
|
|
32
|
+
bind(this: SliderDef, sig: PulseSignal<number>): SliderDef
|
|
33
|
+
/** Tooltip text shown on hover. */
|
|
34
|
+
withTip(this: SliderDef, text: string): SliderDef
|
|
35
|
+
/** Persisted default value loaded from config on startup. */
|
|
36
|
+
withDefault(this: SliderDef, v: number): SliderDef
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Dropdown (single-select) bound to a `PulseSignal<string>`.
|
|
41
|
+
* @example dropdown('Mode', { options: ['Low', 'High'] }).bind(mode)
|
|
42
|
+
*/
|
|
43
|
+
interface DropdownDef {
|
|
44
|
+
/** Two-way bind to a string signal. */
|
|
45
|
+
bind(this: DropdownDef, sig: PulseSignal<string>): DropdownDef
|
|
46
|
+
/** Tooltip text shown on hover. */
|
|
47
|
+
withTip(this: DropdownDef, text: string): DropdownDef
|
|
48
|
+
/** Persisted default selected option. */
|
|
49
|
+
withDefault(this: DropdownDef, v: string): DropdownDef
|
|
50
|
+
/** Replace the option list at runtime (e.g. after fetching players). */
|
|
51
|
+
withOptions(this: DropdownDef, opts: string[]): DropdownDef
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Multi-select dropdown bound to a `PulseSignal<string[]>`.
|
|
56
|
+
* @example multidropdown('Targets', { options: ['Player', 'NPC'] }).bind(targets)
|
|
57
|
+
*/
|
|
58
|
+
interface MultiDropdownDef {
|
|
59
|
+
/** Two-way bind to a string-array signal. */
|
|
60
|
+
bind(this: MultiDropdownDef, sig: PulseSignal<string[]>): MultiDropdownDef
|
|
61
|
+
/** Tooltip text shown on hover. */
|
|
62
|
+
withTip(this: MultiDropdownDef, text: string): MultiDropdownDef
|
|
63
|
+
/** Persisted default selections. */
|
|
64
|
+
withDefault(this: MultiDropdownDef, v: string[]): MultiDropdownDef
|
|
65
|
+
/** Replace the option list at runtime. */
|
|
66
|
+
withOptions(this: MultiDropdownDef, opts: string[]): MultiDropdownDef
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Button — triggers a callback when clicked.
|
|
71
|
+
* @example button('Reset', () => speed.set(16))
|
|
72
|
+
*/
|
|
73
|
+
interface ButtonDef {
|
|
74
|
+
/** Register the click handler. Can be chained. */
|
|
75
|
+
onClick(this: ButtonDef, fn: () => void): ButtonDef
|
|
76
|
+
/** Satisfies `WidgetDef` — returns self. */
|
|
77
|
+
bind(this: ButtonDef): ButtonDef
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Keybind — shows the current key and lets the user rebind it at runtime.
|
|
82
|
+
* @example keybind('Toggle UI', { key: 'RightControl' })
|
|
83
|
+
*/
|
|
84
|
+
interface KeybindDef {
|
|
85
|
+
/** Two-way bind to a string signal tracking the current key name. */
|
|
86
|
+
bind(this: KeybindDef, sig: PulseSignal<string>): KeybindDef
|
|
87
|
+
/** Set the default key name (e.g. `'RightControl'`, `'F'`). */
|
|
88
|
+
withDefault(this: KeybindDef, key: string): KeybindDef
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Static text label — non-interactive, just displays text.
|
|
93
|
+
* @example label('v1.3.1 — by YourName')
|
|
94
|
+
*/
|
|
95
|
+
interface LabelDef {
|
|
96
|
+
/** Update the displayed text at runtime. */
|
|
97
|
+
setText(this: LabelDef, text: string): void
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Horizontal divider line between widget groups. */
|
|
101
|
+
interface SeparatorDef {
|
|
102
|
+
readonly _type: 'separator'
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Union of all renderable widget types.
|
|
107
|
+
* Use as the return type of the `defineComponent` setup function.
|
|
108
|
+
*/
|
|
109
|
+
type WidgetDef =
|
|
110
|
+
| ToggleDef
|
|
111
|
+
| SliderDef
|
|
112
|
+
| DropdownDef
|
|
113
|
+
| MultiDropdownDef
|
|
114
|
+
| ButtonDef
|
|
115
|
+
| KeybindDef
|
|
116
|
+
| LabelDef
|
|
117
|
+
| SeparatorDef
|
|
118
|
+
|
|
119
|
+
// ── Widget factory functions ───────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Create a toggle (checkbox) widget.
|
|
123
|
+
* Chain `.bind(signal)` to connect it to reactive state.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* toggle('Speed Hack').bind(enabled)
|
|
127
|
+
* toggle('Debug', { tip: 'Verbose logging', default: false }).bind(debug)
|
|
128
|
+
*/
|
|
129
|
+
function toggle(label: string, opts?: { tip?: string; default?: boolean }): ToggleDef
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Create a numeric slider widget.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* slider('Walk Speed', { min: 16, max: 250 }).bind(speed)
|
|
136
|
+
* slider('FOV', { min: 1, max: 120, suffix: '°', default: 70 }).bind(fov)
|
|
137
|
+
*/
|
|
138
|
+
function slider(label: string, opts?: {
|
|
139
|
+
min?: number
|
|
140
|
+
max?: number
|
|
141
|
+
step?: number
|
|
142
|
+
default?: number
|
|
143
|
+
suffix?: string
|
|
144
|
+
tip?: string
|
|
145
|
+
}): SliderDef
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Create a single-select dropdown widget.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* dropdown('Mode', { options: ['Silent', 'Normal', 'Loud'] }).bind(mode)
|
|
152
|
+
*/
|
|
153
|
+
function dropdown(label: string, opts?: {
|
|
154
|
+
options?: string[]
|
|
155
|
+
default?: string
|
|
156
|
+
tip?: string
|
|
157
|
+
}): DropdownDef
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Create a multi-select dropdown widget.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* multidropdown('Bypass', { options: ['AntiCheat', 'Logger'] }).bind(bypass)
|
|
164
|
+
*/
|
|
165
|
+
function multidropdown(label: string, opts?: {
|
|
166
|
+
options?: string[]
|
|
167
|
+
default?: string[]
|
|
168
|
+
tip?: string
|
|
169
|
+
}): MultiDropdownDef
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Create a button widget.
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* button('Reset Speed', () => speed.set(16))
|
|
176
|
+
* button('Open Menu').onClick(() => openMenu())
|
|
177
|
+
*/
|
|
178
|
+
function button(label: string, fn: () => void, opts?: { tip?: string }): ButtonDef
|
|
179
|
+
function button(label: string, opts?: { tip?: string }): ButtonDef
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Create a user-rebindable keybind widget.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* keybind('Toggle', { key: 'RightControl' })
|
|
186
|
+
*/
|
|
187
|
+
function keybind(label: string, opts?: { key?: string; tip?: string }): KeybindDef
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Create a static text label widget.
|
|
191
|
+
*
|
|
192
|
+
* @example label('v1.3.1')
|
|
193
|
+
*/
|
|
194
|
+
function label(text: string): LabelDef
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Insert a horizontal separator line between widgets.
|
|
198
|
+
*
|
|
199
|
+
* @example separator()
|
|
200
|
+
*/
|
|
201
|
+
function separator(): SeparatorDef
|
|
202
|
+
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export type {
|
|
206
|
+
ToggleDef, SliderDef, DropdownDef, MultiDropdownDef,
|
|
207
|
+
ButtonDef, KeybindDef, LabelDef, SeparatorDef, WidgetDef,
|
|
208
|
+
}
|
package/index.ts
DELETED
|
@@ -1,350 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @pulse/core — Global ambient declarations for Pulse framework TypeScript scripts.
|
|
3
|
-
*
|
|
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.
|
|
15
|
-
*
|
|
16
|
-
* Compiled to Lua via typescript-to-lua (TSTL): `rb build` handles this for you.
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* // src/combat/SpeedHack.ts
|
|
20
|
-
* defineComponent('SpeedHack', () => {
|
|
21
|
-
* const enabled = signal(false)
|
|
22
|
-
* const speed = signal(16)
|
|
23
|
-
* on.heartbeat({ when: enabled }, () => {
|
|
24
|
-
* const h = _PulseGetHumanoid() as any
|
|
25
|
-
* if (h) h.WalkSpeed = speed()
|
|
26
|
-
* })
|
|
27
|
-
* return [
|
|
28
|
-
* toggle('Speed Hack').bind(enabled),
|
|
29
|
-
* slider('Walk Speed', { min: 16, max: 250 }).bind(speed),
|
|
30
|
-
* ]
|
|
31
|
-
* })
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
declare global {
|
|
35
|
-
|
|
36
|
-
// ── Signal ────────────────────────────────────────────────────────────────────
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Reactive state cell returned by `signal()`.
|
|
40
|
-
*
|
|
41
|
-
* Call it to read the current value. Changes propagate to UI widgets,
|
|
42
|
-
* event guards, and watchers automatically.
|
|
43
|
-
*
|
|
44
|
-
* Like SolidJS `createSignal` but without the getter/setter tuple split.
|
|
45
|
-
*/
|
|
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 ─────────────────────────────────────────────────────────────
|
|
69
|
-
|
|
70
|
-
/**
|
|
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.
|
|
73
|
-
*/
|
|
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() ──────────────────────────────
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* SolidJS-style reactive state — see createSignal.
|
|
160
|
-
*
|
|
161
|
-
* Creates a reactive state cell with an initial value.
|
|
162
|
-
* Compiles to `Signal(initialValue)` in Lua.
|
|
163
|
-
*
|
|
164
|
-
* @example
|
|
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
|
|
170
|
-
*/
|
|
171
|
-
function signal<T>(initialValue: T): PulseSignal<T>
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Create a derived value that recomputes when its dependencies change.
|
|
175
|
-
* Compiles to `Computed(fn)` in Lua.
|
|
176
|
-
*/
|
|
177
|
-
function computed<T>(fn: () => T): () => T
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* SolidJS-style component setup function.
|
|
181
|
-
*
|
|
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.
|
|
185
|
-
*
|
|
186
|
-
* @example
|
|
187
|
-
* defineComponent('SpeedHack', () => {
|
|
188
|
-
* const enabled = signal(false)
|
|
189
|
-
* on.heartbeat({ when: enabled }, () => { ... })
|
|
190
|
-
* return [toggle('Speed Hack').bind(enabled)]
|
|
191
|
-
* })
|
|
192
|
-
*/
|
|
193
|
-
function defineComponent(name: string, setup: () => WidgetDef[]): ComponentRef
|
|
194
|
-
|
|
195
|
-
/**
|
|
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.
|
|
199
|
-
*/
|
|
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
|
|
281
|
-
|
|
282
|
-
/**
|
|
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
|
|
287
|
-
*/
|
|
288
|
-
function groupbox(side: 'left' | 'right', title: string, opts?: {
|
|
289
|
-
icon?: string; mount?: string; widgets?: WidgetDef[]
|
|
290
|
-
}): GroupboxDef
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Next.js-style file-based page tab — place in src/pages/N_Name.ts.
|
|
294
|
-
*
|
|
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, …).
|
|
297
|
-
*
|
|
298
|
-
* @example
|
|
299
|
-
* // src/pages/1_Home.ts
|
|
300
|
-
* definePage('Home', { icon: 'house' }, () => [
|
|
301
|
-
* groupbox('left', 'Player', { icon: 'person', mount: 'SpeedHack' }),
|
|
302
|
-
* ])
|
|
303
|
-
*/
|
|
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
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
export {}
|