MOD DEVELOPER GUIDE

Build your own Void mods.

Mods are small text files that add things to Void — like an overlay with your stats over Roblox. This guide takes you from zero to your first working mod, no coding experience needed.

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.

1

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.)

2

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."
}
3

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() })
}
4

Keep it up to date

every 1000 runs again and again — every 1000 milliseconds, so once a second:

every 1000 {
  clock.text(time.clock())
}
5

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 + "!")
}
6

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!

The whole file — copy it if you want to start from here:
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.

BlockWhat 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 elseRuns 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:

EventWhen it runsGives you
on startThe mod is switched on (or Void starts)—
on stopThe mod is switched off or Void closes—
on roblox_startA Roblox window appears—
on roblox_exitRoblox closes—
on game_joinYou join a gamegame, placeId, location, serverType
on game_leaveYou 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.

Tip: names like 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

top-lefttop-centertop-right bottom-leftbottom-centerbottom-right

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.

MessageWhat it means
Line 7: "clok" doesn't existA typo, or the variable was never created with let.
Missing "}"A block was opened with { but never closed.
Can't add list and numberYou used + on things that don't go together.
The script ran too longA loop never ends — check your while condition.
This value is read-onlyYou tried to change a config value inside the mod.
Tip: sprinkle 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(…)