Skip to main content

Chrono

A scope-based task scheduler for Roblox. Schedule recurring tasks, fixed-rate ticks, one-shot delays, and per-frame callbacks — all tied to a Scope's lifecycle.

All tasks created through a Scope are automatically cleaned up when the Scope is destroyed, making chrono safe to use in component-based or OOP architectures without manual cleanup bookkeeping.

local chrono = require(path.to.chrono)

local scope = chrono.scope()

scope:tick(60, function(dt)
	player.position += player.velocity * dt
end)

scope:every(5, function()
	print("every 5 seconds")
end)

scope:after(10, function()
	scope:destroy() -- cleans up all tasks at once
end)

Functions

createScope

Chrono.createScope(
config{
timeScalenumber?,
onError((
errstring,
namestring
) → ())?
}?--

Optional configuration. timeScale sets the initial time multiplier (default: 1.0). onError is called when a task callback throws, receiving the error message and the task name.

) → Scope

Creates a new independent Scope. Each Scope maintains its own pause state, time scale, and elapsed time. Scopes do not interfere with each other.

profile

Chrono.profile() → {[string]{
namestring,
countnumber,
avgMsnumber,
maxMsnumber,
p99Msnumber,
totalMsnumber
}}

Returns profiling data for all tasks that have executed at least once since the last reset_profiler() call (or since the module was loaded).

Task names come from the name field in each task's config table. Tasks without a name are grouped under <anonymous>.

Times are computed over a rolling window of the last 128 samples per task.

local prof = chrono.profile()
for name, data in pairs(prof) do
	print(name, "avg:", data.avgMs, "p99:", data.p99Ms)
end

resetProfiler

Chrono.resetProfiler() → ()

Clears all profiler data accumulated since the last reset or module load.

pauseAll

Chrono.pauseAll() → ()

Pauses all active Scopes at once. Equivalent to calling scope:pause() on every Scope individually.

Useful for game-wide pause states such as cutscenes or menus.

resumeAll

Chrono.resumeAll() → ()

Resumes all active Scopes at once. Equivalent to calling scope:resume() on every Scope individually.

Show raw api
{
    "functions": [
        {
            "name": "createScope",
            "desc": "Creates a new independent Scope. Each Scope maintains its own pause state,\ntime scale, and elapsed time. Scopes do not interfere with each other.",
            "params": [
                {
                    "name": "config",
                    "desc": "Optional configuration. `timeScale` sets the initial time multiplier (default: `1.0`). `onError` is called when a task callback throws, receiving the error message and the task name.",
                    "lua_type": "{timeScale: number?, onError: ((err: string, name: string) -> ())?}?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Scope"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 777,
                "path": "src/Chrono.luau"
            }
        },
        {
            "name": "profile",
            "desc": "Returns profiling data for all tasks that have executed at least once since the\nlast `reset_profiler()` call (or since the module was loaded).\n\nTask names come from the `name` field in each task's config table. Tasks without\na name are grouped under `<anonymous>`.\n\nTimes are computed over a rolling window of the last 128 samples per task.\n\n```lua\nlocal prof = chrono.profile()\nfor name, data in pairs(prof) do\n\tprint(name, \"avg:\", data.avgMs, \"p99:\", data.p99Ms)\nend\n```",
            "params": [],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "{[string]: {name: string, count: number, avgMs: number, maxMs: number, p99Ms: number, totalMs: number}}"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 822,
                "path": "src/Chrono.luau"
            }
        },
        {
            "name": "resetProfiler",
            "desc": "Clears all profiler data accumulated since the last reset or module load.",
            "params": [],
            "returns": [],
            "function_type": "static",
            "source": {
                "line": 844,
                "path": "src/Chrono.luau"
            }
        },
        {
            "name": "pauseAll",
            "desc": "Pauses all active Scopes at once. Equivalent to calling `scope:pause()` on\nevery Scope individually.\n\nUseful for game-wide pause states such as cutscenes or menus.",
            "params": [],
            "returns": [],
            "function_type": "static",
            "source": {
                "line": 858,
                "path": "src/Chrono.luau"
            }
        },
        {
            "name": "resumeAll",
            "desc": "Resumes all active Scopes at once. Equivalent to calling `scope:resume()` on\nevery Scope individually.",
            "params": [],
            "returns": [],
            "function_type": "static",
            "source": {
                "line": 873,
                "path": "src/Chrono.luau"
            }
        }
    ],
    "properties": [],
    "types": [],
    "name": "Chrono",
    "desc": "A scope-based task scheduler for Roblox. Schedule recurring tasks, fixed-rate\nticks, one-shot delays, and per-frame callbacks — all tied to a `Scope`'s lifecycle.\n\nAll tasks created through a Scope are automatically cleaned up when the Scope\nis destroyed, making chrono safe to use in component-based or OOP architectures\nwithout manual cleanup bookkeeping.\n\n```lua\nlocal chrono = require(path.to.chrono)\n\nlocal scope = chrono.scope()\n\nscope:tick(60, function(dt)\n\tplayer.position += player.velocity * dt\nend)\n\nscope:every(5, function()\n\tprint(\"every 5 seconds\")\nend)\n\nscope:after(10, function()\n\tscope:destroy() -- cleans up all tasks at once\nend)\n```",
    "source": {
        "line": 767,
        "path": "src/Chrono.luau"
    }
}