What is a mod?
A mod is one text file ending in .vb. It's written in VoidScript — Void's own little language. Void reads the file and runs it while Void is open. There's nothing to compile and nothing to install except the file itself.
Plain text
Write it in Notepad, VS Code or any editor. Save it as something.vb.
Reacts to things
Run code when you join a game, when Roblox starts, or every second.
Has settings
Users change colours, sizes and switches on the Mods page — no code needed.
Your first mod in 5 minutes
We'll build a small mod that shows the time in the corner of Roblox and says hi when you join a game.
Create the file
Make a new text file and call it hello.vb. (In Windows, turn on View → File name extensions so it doesn't secretly become hello.vb.txt.)
Give it a name
Every mod starts with a mod block. This is what people see in the marketplace:
mod {
name: "Hello Clock"
version: "1.0.0"
author: "your name"
description: "Shows the time and says hi when you join."
}
Show something over Roblox
Add this below. on start runs once when the mod is switched on. It creates a small label in the bottom-left corner:
let clock = null
on start {
clock = overlay.label({ at: "bottom-left", text: time.clock() })
}
Keep it up to date
every 1000 runs again and again — every 1000 milliseconds, so once a second:
every 1000 {
clock.text(time.clock())
}
React to a game
on game_join runs whenever you join a game, and you get the game's name for free in game:
on game_join {
void.notify("Have fun in " + game + "!")
}
Try it
Open Void → Mods and drag your file onto the window (or click From file). It's switched on right away. Start Roblox — the clock appears bottom-left. Done!
mod {
name: "Hello Clock"
version: "1.0.0"
author: "your name"
description: "Shows the time and says hi when you join."
}
let clock = null
on start {
clock = overlay.label({ at: "bottom-left", text: time.clock() })
}
every 1000 {
clock.text(time.clock())
}
on game_join {
void.notify("Have fun in " + game + "!")
}
How a mod is built
A mod file is made of a few kinds of blocks. Only mod is required; everything else is optional and can appear in any order.
| Block | What it's for |
|---|---|
mod { … } | Name, version, author, description, tags. Shown in the marketplace and on the Mods page. |
config { … } | Settings with their default values. Void turns them into switches, number boxes and colour pickers. More below. |
on name { … } | Code that runs when something happens — e.g. on start, on game_join. |
every ms { … } | Code that runs again and again, every ms milliseconds (50 or more). |
| everything else | Runs once when the mod starts. Use it for variables (let) and functions (func). |
Language basics
VoidScript is small on purpose. If you've seen JavaScript or Lua before, it'll feel familiar. If not — here's everything, one piece at a time.
Variables
A variable is a named box for a value. Create it once with let, then change it without let.
let deaths = 0 // a number let name = "Void" // text — "double" or 'single' quotes let ready = true // true or false let nothing = null // "no value" deaths = deaths + 1 // change it deaths += 1 // the same, shorter (also -= *= /=)
Text
Use + to glue text together — numbers are turned into text automatically.
let cpu = 42
let line = "CPU " + cpu + "%" // "CPU 42%"
line.upper() // "CPU 42%" in capitals
"hello".contains("ell") // true
Decisions
if cpu > 90 {
void.notify("Your PC is working hard!")
} else if cpu > 60 {
// something in between
} else {
// all good
}
// short version: condition ? if-true : if-false
let label = ping == null ? "—" : ping + " ms"
Combine conditions with and, or and not. Compare with == != < > <= >=.
Lists & loops
let games = ["Adopt Me", "Brookhaven"]
games.push("Bloxburg") // add to the end
games.length // 3
games[0] // "Adopt Me" — counting starts at 0
for g in games {
print(g)
}
for i in 5 { // i = 0, 1, 2, 3, 4
print(i)
}
let n = 0
while n < 3 {
n += 1
}
Objects
An object groups named values together:
let player = { name: "skulli", level: 12 }
player.level += 1
print(player.name) // "skulli"
Functions
A function is a reusable piece of code. Give it inputs, get a result back with return.
func colorFor(value) {
if value > 90 { return "#ef4444" } // red
if value > 70 { return "#f59e0b" } // orange
return null // default colour
}
let c = colorFor(stats.cpu())
Comments
Anything after // or # on a line is ignored — use it to explain your code. /* … */ works across several lines.
Events & timers
Mods don't run top to bottom and stop — they wait for things to happen. These are the events you can use:
| Event | When it runs | Gives you |
|---|---|---|
on start | The mod is switched on (or Void starts) | — |
on stop | The mod is switched off or Void closes | — |
on roblox_start | A Roblox window appears | — |
on roblox_exit | Roblox closes | — |
on game_join | You join a game | game, placeId, location, serverType |
on game_leave | You leave a game | — |
Timers: every 1000 { … } runs every second. You can use a setting too: every config.refresh { … }. The smallest value is 50.
Settings (config)
Put anything users should be able to change in a config block. Void builds the settings panel on the Mods page for you — the type of the default value decides the control:
config {
showPing: true // true/false → on/off switch
refresh: 1000 // number → number box
opacity: 0.3 // number → number box (decimals)
color: "#a855f7" // "#rrggbb" → colour picker
title: "My stats" // other text → text box
}
Read them anywhere with config.name, e.g. if config.showPing { … }. Settings are read-only inside the mod — when a user changes one, Void restarts the mod with the new value.
showPing are shown as "Show Ping" in the settings panel automatically.Drawing over Roblox
Overlays sit on top of the Roblox window. They only show while Roblox is the active window, and clicks go straight through to the game. There are two kinds:
Bars — a row of values
let bar = overlay.bar({
from: "top-center", // where the bar starts
to: "top-right", // where it ends (same edge: top or bottom)
color: "#a855f7", // accent colour
opacity: 0.3, // background: 0.3 = 70 % see-through
offset: 10 // distance from the edge in px (optional)
})
bar.set("cpu", "CPU", "42%") // key, label, value
bar.set("ping", "PING", "180 ms", "#ef4444") // optional colour for the value
bar.remove("cpu")
Use the same key again to update a value — it stays in its place.
Labels — a single badge
let tag = overlay.label({ at: "bottom-left", text: "Void", size: 14 })
tag.text("new text")
tag.color("#22c55e")
Positions
Overlays sit 10 px from the edge by default; change it with offset. Both bars and labels also have .hide(), .show() and .destroy().
Everything mods can use
stats — your PC
stats.cpu() | CPU load in % |
stats.ram() | RAM in use in % — also stats.ramUsedGb() and stats.ramTotalGb() |
stats.gpu() | Roblox's GPU load in %, or null while Roblox isn't running |
stats.ping() | Ping to the Roblox server in ms, or null if the server doesn't answer pings |
stats.playtime() | Seconds since you joined the current game |
stats.fps() | Always null — Roblox doesn't share its FPS with other programs |
roblox — the game
roblox.running() / roblox.focused() | Is Roblox open / is it the active window? |
roblox.inGame() | Are you in a game right now? |
roblox.game() / roblox.placeId() | Name and place ID of the current game |
roblox.location() / roblox.serverType() | Server location ("Frankfurt, DE") and type ("Public", "Private", "Reserved") |
void, storage, helpers
void.notify("text") | Shows a message in Void |
storage.set("best", 42) / storage.get("best", 0) | Remember values between runs (the 2nd value of get is the default) |
print(…) | Writes to the mod's log (handy while testing) |
round(x, digits) floor ceil abs min max clamp(x, lo, hi) | Maths |
random() / random(1, 6) | Random number (0–1) or whole number in a range |
text(x) number(x) type(x) len(x) keys(obj) | Convert and inspect values |
time.clock() / time.now() | "14:05" / milliseconds since 1970 |
Example: Void Stats, explained
A shortened version of the Void Stats mod from the marketplace, with what each part does.
config {
opacity: 0.3
color: "#a855f7"
refresh: 1000
showPing: true
showCpu: true
}
let bar = null // the overlay bar, made in "on start"
func colorFor(value, warn, bad) { // orange when high, red when very high
if value == null { return null }
if value >= bad { return "#ef4444" }
if value >= warn { return "#f59e0b" }
return null
}
func update() {
if config.showPing {
let ping = stats.ping()
bar.set("ping", "PING", ping == null ? "—" : ping + " ms", colorFor(ping, 120, 220))
}
if config.showCpu {
let cpu = stats.cpu()
bar.set("cpu", "CPU", cpu + "%", colorFor(cpu, 75, 92))
}
}
on start { // create the bar once…
bar = overlay.bar({ from: "top-center", to: "top-right", color: config.color, opacity: config.opacity })
update()
}
every config.refresh { // …and refresh the values every second
update()
}
Errors & testing
If something's wrong, Void switches the mod off and shows the problem with the line number on the Mods page. Fix the file and drop it onto Void again — it replaces the old version.
| Message | What it means |
|---|---|
Line 7: "clok" doesn't exist | A typo, or the variable was never created with let. |
Missing "}" | A block was opened with { but never closed. |
Can't add list and number | You used + on things that don't go together. |
The script ran too long | A loop never ends — check your while condition. |
This value is read-only | You tried to change a config value inside the mod. |
print("got here", value) into your code — the last lines show up on the Mods page when you open the mod's settings (⚙).Publishing
Happy with your mod? Send the .vb file to the Void team. Once it's added to the marketplace, everyone can install it with one click.
To ship an update, raise the version in your mod block (e.g. "1.0.0" → "1.1.0"). Everyone who installed it sees an Update button.
Cheat sheet
mod { name: "…" version: "1.0.0" author: "…" description: "…" }
config { setting: default }
let x = 1 x += 1 func f(a, b) { return a + b }
if a and not b { } else if c { } else { }
for item in list { } for i in 10 { } while cond { } break continue
cond ? yes : no
on start { } on stop { } on game_join { } on game_leave { }
on roblox_start { } on roblox_exit { } every 1000 { }
overlay.bar({ from, to, color, opacity, offset }) .set(key, label, value, color)
overlay.label({ at, text, color, opacity, size }) .text(t) .color(c)
stats.cpu() stats.ram() stats.gpu() stats.ping() stats.playtime()
roblox.game() roblox.inGame() roblox.location()
void.notify(t) storage.get(k, default) storage.set(k, v) print(…)
