1.4.x — Key system & premium tier
Released across v1.4.0 – v1.4.4.
Key system
Add a keySystem block to src/layout.ts to gate the entire UI behind a key:
keySystem: {
title: 'Key Required',
note: 'Get your free key from our Discord',
saveKey: true, // persist key to executor filesystem
getKeyUrl: 'https://discord.gg/example',
// Option A — static list (client-side):
keys: ['FREE_KEY_1', 'FREE_KEY_2'],
// Option B — server-side validator (more secure):
// validatorUrl: 'https://yoursite.com/validate?key=',
},
Without a keySystem block the script runs without any key prompt — nothing changes for existing scripts.
Premium tier
A second key layer on top of the free tier. Users with a premium key get access to additional groupboxes — no re-injection required.
premium: {
keys: ['PREMIUM_KEY_1'],
// OR: validatorUrl: 'https://yoursite.com/premium?key=',
getKeyUrl: 'https://yoursite.com/premium',
},
Mark groupboxes as premium in your page files:
groupbox('left', 'Aimbot', { icon: 'crosshair', mount: 'Aimbot', premium: true })
What users see: Each { premium: true } groupbox shows a locked-state UI — a key input, a Copy Link button, a Check Key button, and a status line. When the user enters a valid premium key, all premium groupboxes across the entire script unlock live via dynamic component mounting. No re-injection. No page reload.
Premium keys also grant basic key-system access automatically — one key for everything.
Signal engine fix
Fixed a silent infinite-recursion bug in the reactive signal engine.
Root cause: the _signal() helper overrode s.set using s:set(v) — which is Lua colon-call sugar for s.set(s, v). After the override, every s.set call would call itself recursively until stack overflow. WindUI's internal pcall caught the overflow silently, so toggle widgets appeared to fire (the log line appeared before the recursive call) but had no effect on the game.
Fix: capture the original method before overriding:
local _rawSet = s.set
s.set = function(_, v) _rawSet(s, v) end
s.toggle = function(_) _rawSet(s, not s:get()) end
This is the correct pattern for all signal method overrides.
IronBrew banner auto-stripped
The --[[ IronBrew 2 ... ]] comment block that Ironbrew2 prepends to obfuscated output is now automatically removed by the build pipeline. The final build/script.obf.lua starts cleanly with the re-execution guard, as expected.
Dev tab improvements
- Open Console button added to the Dev tab Console section — fires
StarterGui:SetCore("DevConsoleVisible", true)without needing to open the Roblox menu - Executor detection fixed for proxy-env executors — switched from
rawget(_G, "identifyexecutor")(which bypasses__indexmetamethods) topcall(function() return identifyexecutor() end), fixing the "Unknown" label on some executors - Removed Heartbeat Monitor section and auto-scan on inject (debugging tools that shipped accidentally in 1.3.0)
New rb init scaffold
rb init my-script now scaffolds:
my-script/
src/
layout.ts ← window config + commented keySystem/premium examples
pages/
1_Combat.ts ← Combat tab: 3 free groupboxes + 1 premium Aimbot groupbox
combat/
SpeedHack.ts ← free example component
FOVChanger.ts ← free example component
Aimbot.ts ← premium example component (clearly commented)
visuals/
PlayerESP.ts ← free example component
misc/
globals.lua
remotes.lua
tsconfig.json
CLAUDE.md / AGENTS.md / PULSE_DOCS.md
Changes from 1.3.0:
1_Home.tsrenamed to1_Combat.ts— "Home" is a reserved built-in tab name; user pages must not use "Home" or "Settings"Aimbot.tsadded — demonstrates premium component pattern withon.heartbeatat 60 fps throttlelayout.tstemplate now includesversion,description, anddiscordfields, plus fully-commentedkeySystemandpremiumexample blocks
Reserved page names
The framework creates "Home" and "Settings" tabs automatically. Do not name your pages "Home" or "Settings" — doing so creates a duplicate tab that may not behave correctly.
layout.ts new fields
export default {
title: 'MyScript',
version: '1.0.0', // shown in Home tab info card
description: 'A powerful script for MyScript.', // shown in Home tab
discord: '', // if set, shows "Join Discord" button in Home tab
// ...rest unchanged
} satisfies LayoutConfig