Quick Start
Install rb, scaffold a project, build, inject.
1. Install rb
You need Node.js 18+ and pnpm. If you don't have them yet, see Environment Setup.
pnpm add -g pulse-rb
Open a new terminal after it finishes. Verify:
rb --help
2. Scaffold a project
rb init my-script
cd my-script
This creates a TypeScript-first project:
my-script/
src/
layout.ts ← window title, size, theme, toggle key, optional key/premium system
pages/
1_Combat.ts ← Combat tab with 3 free + 1 premium groupbox
combat/
SpeedHack.ts ← free example component
FOVChanger.ts ← free example component
Aimbot.ts ← premium example component
visuals/
PlayerESP.ts ← free example component
misc/
globals.lua ← shared helpers, compiled first
remotes.lua ← remote wrappers
build/ ← compiled output goes here
tsconfig.json ← TypeScript config (TSTL-compatible)
:::note Reserved page names The framework creates Home and Settings tabs automatically. Never name your own pages "Home" or "Settings" — use names like "Combat", "Visuals", "Misc" instead. :::
3. Configure your window
Open src/layout.ts:
export default {
title: 'MyScript',
version: '1.0.0',
description: 'A powerful script for MyScript.',
discord: '', // 'https://discord.gg/...' shows a Join Discord button
toggleKey: 'RightControl',
size: [850, 560] as [number, number],
uiLibrary: 'windui' as 'windui' | 'linoria',
theme: 'Indigo',
icon: 'code-2',
folder: 'MyScript',
acrylic: true,
transparency: 0.8,
} satisfies LayoutConfig
Change title, toggleKey, and uiLibrary to match your script.
The template also includes commented-out keySystem and premium blocks — uncomment them to add a key gate or premium tier. See the v1.4.4 changelog for details.
4. Write a component
Open src/combat/SpeedHack.ts:
// Like SolidJS — signals are reactive values, on.* hooks are reactive effects
defineComponent('SpeedHack', () => {
const enabled = signal(false)
const speed = signal(16)
on.heartbeat({ when: enabled }, () => {
const h = _PulseGetHumanoid()
if (h) h.WalkSpeed = speed()
})
on.respawn(() => {
const h = _PulseGetHumanoid()
if (h) h.WalkSpeed = enabled() ? speed() : 16
})
return [
toggle('Speed Hack').bind(enabled),
slider('Walk Speed', { min: 16, max: 250 }).bind(speed),
]
})
All Pulse APIs (signal, defineComponent, on, toggle, slider, etc.) are ambient globals — no imports needed.
5. Lay out a tab
Open src/pages/1_Combat.ts:
// Like Next.js pages — filename order = tab order
definePage('Combat', { icon: 'swords' }, () => [
groupbox('left', 'Player', { icon: 'person', mount: 'SpeedHack' }),
groupbox('left', 'Player', { icon: 'person', mount: 'FOVChanger' }),
groupbox('right', 'Visuals', { icon: 'eye', mount: 'PlayerESP' }),
groupbox('right', 'Aimbot', { icon: 'crosshair', mount: 'Aimbot', premium: true }),
])
The premium: true groupbox shows a locked key-entry UI until the user enters a valid premium key.
6. Build
rb build
Output: build/script.lua — two CDN loadstrings at the top, then your compiled code. Inject this.
For a quick build without obfuscation:
rb build --no-obfuscate
7. What the output looks like
-- re-execution guard
if _G.__AOT_R_DESTROY then pcall(_G.__AOT_R_DESTROY) end
-- Pulse v1.4.4 — runtime and adapter from CDN (not inlined)
local _P=loadstring(game:HttpGet("https://cdn.pulse-rb.dev/v1.4.4/bundle.lua"))()
local _A=loadstring(game:HttpGet("https://cdn.pulse-rb.dev/v1.4.4/adapters/windui.lua"))()
-- your compiled TypeScript below
defineComponent("SpeedHack", function() ... end)
definePage("Combat", ..., function() ... end)
The runtime is never inlined — the build stays small regardless of how many helpers are in the framework.
Daily workflow
rb watch ← auto-rebuild every time you save a file
rb build ← one-off build
rb copy ← build + copy obfuscated output to clipboard
rb lint ← find dead signals and broken references
rb save "msg" ← git commit shortcut
Next step
Write your first full feature → Your First Feature
Or learn how signals work → Signals