Options
Options are the controls your module exposes in the menu — toggles, sliders,
dropdowns, text fields, color pickers. You declare them in
phase 1, and each declaration returns
a live Option handle you read and observe from your listeners.
defineModule({ name: "Example", category: ModuleCategory.Client }, (options) => {
const enabled = options.boolean("Particles", true);
const count = options.number("Count", 8, { min: 1, max: 64, step: 1, displayResolution: 0 });
const mode = options.enum("Mode", ["Spin", "Pulse", "Wave"] as const, "Spin");
const color = options.color("Tint", [255, 0, 0, 255]);
return (ctx) => {
ctx.on("tick", () => {
if (!enabled.value) return;
render(count.value, mode.value, color.value);
});
};
});
Declaring options — ModuleOptions
The options object passed to build has one method per kind:
| Method | Returns | Description |
|---|---|---|
boolean(name, def?) | Option<boolean> | A toggle. def defaults to false. |
number(name, def, props) | Option<number> | A slider; props is NumberOptionProps. |
string(name, def?) | Option<string> | A free-text field. def defaults to "". |
enum(name, values, def?) | Option<T> | A single choice over a fixed list of strings. def defaults to values[0]. |
color(name, def) | Option<Color> | An RGBA color picker. |
NumberOptionProps
interface NumberOptionProps {
min: number;
max: number;
step?: number;
displayResolution: number; // decimal places shown in the UI
}
Color
type Color = [r: number, g: number, b: number, a: number]; // each channel 0-255
Enums
Pass as const on the values array so the option's type narrows to the literal
union:
const mode = options.enum("Mode", ["Spin", "Pulse", "Wave"] as const, "Spin");
// mode.value : "Spin" | "Pulse" | "Wave"
Reading & observing — Option<T>
Every declaration returns an Option<T>. Because options are declared once and
shared across sessions, you can close over the handle in any listener.
| Member | Type | Description |
|---|---|---|
value | T | The current value. Read it, or set it to change the option as if edited in the UI. |
name | string | Display name. |
defaultValue | T | The value reset() restores. |
subscribe(listener, notifyFirst?) | () => void | Observe changes; returns an unsubscribe fn. Pass notifyFirst: true to fire once immediately. |
reset() | void | Restore the default value. |
isDefault() | boolean | Whether the current value is the default. |
get type | string | The option kind, e.g. "boolean", "number". |
Reading
Read option.value inside a listener — it always reflects the current menu
state:
ctx.on("tick", () => {
if (speed.value > 0) applySpeed(speed.value);
});
Writing
Setting option.value applies the change and notifies subscribers, exactly as
if the user moved the slider:
ctx.onEnable(() => { speed.value = 1.5; });
Subscribing
To react the moment an option changes (rather than polling each tick):
return (ctx) => {
const unsub = color.subscribe(() => rebuildPalette(color.value), true);
ctx.onDisable(unsub);
};
Tip — subscriptions vs.
ctx.on.option.subscribeis not tied to the module's enabled state — it fires whenever the value changes. If you only want to react while enabled, unsubscribe inonDisable(as above), or just readoption.valueinside actx.onlistener.