Skip to main content

Getting Started

VeSignal is a single-file Luau module. Install it, require it, and start connecting.


Installation

Get VeSignal from the Roblox Creator Store:

Get VeSignal on Creator Store

Drop VeSignal.lua into ReplicatedStorage (or any shared module location) and require it:

local Signal = require(ReplicatedStorage.VeSignal)

VeSignal requires the new Luau type solver for full generic type inference. Enable it in Studio under Beta Features → New Luau Solver.


Your First Signal

local Signal = require(ReplicatedStorage.VeSignal)

local onDamage = Signal.new() :: Signal.Signal<(victim: Player, amount: number) -> ()>

-- Connect a listener
local connection = onDamage:Connect(function(victim, amount)
print(victim.Name, "took", amount, "damage")
end)

-- Fire the signal
onDamage:Fire(player, 25)

-- Clean up when done
connection:Disconnect()

Typed Signals

Declare the signal's signature with a type cast. VeSignal's UDTF type functions propagate the signature to Fire, Wait, and all connect methods so your IDE catches type errors automatically:

-- Fire's signature is inferred as (self, victim: Player, amount: number) -> ()
onDamage:Fire(player, 25) -- ok
onDamage:Fire("bad", true) -- type error

Async Listeners

Use ConnectAsync for listeners that should run in their own thread and not block the firing coroutine:

onDamage:ConnectAsync(function(victim, amount)
-- Runs in a pooled thread — yielding here is safe
task.wait(0.5)
applyBloodEffect(victim)
end)

Priority

Listeners with higher priority numbers run first. Default is 0:

signal:Connect(earlyHandler, 10)   -- runs first
signal:Connect(normalHandler) -- priority 0
signal:Connect(lateHandler, -1) -- runs last

Combinators

React to multiple signals at once without boilerplate:

-- Fires whenever either signal fires
local either = Signal.any(playerSpawned, mapLoaded)

-- Fires once both have fired at least once
local both = Signal.all(playerSpawned, mapLoaded)
both:Once(function()
startGame()
end)

Quick Reference

I want to…Method
Connect a sync listenerConnect
Connect an async listenerConnectAsync
Connect with a conditionConnectIf
Connect onceOnce
Connect once with a deadlineOnceTimeout
Fire all listenersFire
Fire without blockingFireAsync
Yield until the signal firesWait
Combine signalsSignal.any / Signal.all
See practical examplesUse Cases