Skip to main content

Signal

Minimal typed signal, built with closures so the kit stays strict without casts and without pulling a third dependency just to notify listeners.

Every event the kit exposes is one of these: Tutorial.StepChanged, Tutorial.Completed, TutorialServer.PlayerStepAdvanced and the rest.

const connection = tutorial.StepChanged:Connect(function(step, previousStep)
	print(step, previousStep)
end)

connection:Disconnect()

Handlers run on their own thread, matching how Roblox events behave: a listener that errors cannot take the tutorial flow down with it. It also means a handler cannot block the step that fired it, and that the order handlers run in is not guaranteed.

Types

Connection

interface Connection {
Connectedboolean--

False once disconnected

Disconnect(selfConnection) → ()--

Stop listening. Safe to call twice

}

Functions

create

constructor
Signal.create() → Signal<T...>

Creates an empty signal.

const stepReached: TutorialKit.Signal<number> = TutorialKit.Signal.create()

Connect

Signal:Connect(
handler(T...) → ()--

Runs on every fire

) → Connection

Listens until disconnected.

Inside an action, put the connection on the step Janitor so it dies with the step:

context.Janitor:add(tutorial.StepChanged:Connect(onStepChanged), "Disconnect")

Once

Signal:Once(
handler(T...) → ()--

Runs on the next fire only

) → Connection

Listens for a single fire, then disconnects itself.

Fire

Signal:Fire(
...T...--

Arguments passed to every handler

) → ()

Calls every handler, each on its own thread.

Handlers are iterated over a copy, so one may disconnect itself or others mid-fire without skipping anybody.

DisconnectAll

Signal:DisconnectAll() → ()

Drops every listener but leaves the signal usable.

Destroy

lifecycle
Signal:Destroy() → ()

Drops every listener. The kit calls this on its own signals from Tutorial:Destroy.

Show raw api
{
    "functions": [
        {
            "name": "Connect",
            "desc": "Listens until disconnected.\n\nInside an action, put the connection on the step Janitor so it dies with the step:\n\n```lua\ncontext.Janitor:add(tutorial.StepChanged:Connect(onStepChanged), \"Disconnect\")\n```",
            "params": [
                {
                    "name": "handler",
                    "desc": "Runs on every fire",
                    "lua_type": "(T...) -> ()"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Connection"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 49,
                "path": "src/Internal/Signal.luau"
            }
        },
        {
            "name": "Once",
            "desc": "Listens for a single fire, then disconnects itself.",
            "params": [
                {
                    "name": "handler",
                    "desc": "Runs on the next fire only",
                    "lua_type": "(T...) -> ()"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Connection"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 58,
                "path": "src/Internal/Signal.luau"
            }
        },
        {
            "name": "Fire",
            "desc": "Calls every handler, each on its own thread.\n\nHandlers are iterated over a copy, so one may disconnect itself or others mid-fire without\nskipping anybody.",
            "params": [
                {
                    "name": "...",
                    "desc": "Arguments passed to every handler",
                    "lua_type": "T..."
                }
            ],
            "returns": [],
            "function_type": "method",
            "source": {
                "line": 69,
                "path": "src/Internal/Signal.luau"
            }
        },
        {
            "name": "DisconnectAll",
            "desc": "Drops every listener but leaves the signal usable.",
            "params": [],
            "returns": [],
            "function_type": "method",
            "source": {
                "line": 76,
                "path": "src/Internal/Signal.luau"
            }
        },
        {
            "name": "Destroy",
            "desc": "Drops every listener. The kit calls this on its own signals from [Tutorial:Destroy].",
            "params": [],
            "returns": [],
            "function_type": "method",
            "tags": [
                "lifecycle"
            ],
            "source": {
                "line": 84,
                "path": "src/Internal/Signal.luau"
            }
        },
        {
            "name": "create",
            "desc": "Creates an empty signal.\n\n```lua\nconst stepReached: TutorialKit.Signal<number> = TutorialKit.Signal.create()\n```",
            "params": [],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Signal<T...>"
                }
            ],
            "function_type": "static",
            "tags": [
                "constructor"
            ],
            "source": {
                "line": 106,
                "path": "src/Internal/Signal.luau"
            }
        }
    ],
    "properties": [],
    "types": [
        {
            "name": "Connection",
            "desc": "",
            "fields": [
                {
                    "name": "Connected",
                    "lua_type": "boolean",
                    "desc": "False once disconnected"
                },
                {
                    "name": "Disconnect",
                    "lua_type": "(self: Connection) -> ()",
                    "desc": "Stop listening. Safe to call twice"
                }
            ],
            "source": {
                "line": 30,
                "path": "src/Internal/Signal.luau"
            }
        }
    ],
    "name": "Signal",
    "desc": "Minimal typed signal, built with closures so the kit stays strict without casts and without\npulling a third dependency just to notify listeners.\n\nEvery event the kit exposes is one of these: [Tutorial.StepChanged], [Tutorial.Completed],\n[TutorialServer.PlayerStepAdvanced] and the rest.\n\n```lua\nconst connection = tutorial.StepChanged:Connect(function(step, previousStep)\n\tprint(step, previousStep)\nend)\n\nconnection:Disconnect()\n```\n\nHandlers run on their own thread, matching how Roblox events behave: a listener that errors\ncannot take the tutorial flow down with it. It also means a handler cannot block the step that\nfired it, and that the order handlers run in is not guaranteed.",
    "source": {
        "line": 23,
        "path": "src/Internal/Signal.luau"
    }
}