atherhubather.hub
Back to Guides
SUNC
10 min read
May 11, 2026

What is SUNC?

SUNC — short for Strict Unified Naming Convention — is the community standard that defines what functions a Roblox executor is expected to expose to scripts, and the exact names and signatures they're expected to use. It's the strict sibling of UNC (Unified Naming Convention): same idea, tighter conformance bar. This article explains what it is, why it exists, what it covers, and how to use the documentation at docs.sunc.su when you're building a script that has to run across multiple executors.

Ather
Ather
Lead developer at Atherhub. Writes about Roblox internals, Luau, script engineering, and platform security.Last updated May 11, 2026

UNC, then SUNC

Before SUNC there was UNC — the Unified Naming Convention — which set out one canonical name per primitive (e.g. writefile, not write_file or WriteFile). UNC made multi-executor scripts possible, but it was lenient: an executor could pass UNC by having the functions present, even if their behaviour was subtly wrong.

SUNC tightens the bar. It uses the same names and the same surface area as UNC, but its conformance suite tests actual behaviour — correct return types, correct error cases, correct side effects, correct closure-type results. An executor with a high UNC score can still get a low SUNC score if its implementations cut corners. From a script author's point of view, SUNC is what you actually want: not just "the function exists," but "it works."

The documentation lives at docs.sunc.su and the test scripts run inside the executor itself. When you read "100% SUNC" in an executor's marketing, that's this score.

How the spec is organised

The functions in SUNC are grouped into libraries that mirror their purpose. Reading the table of contents in the docs, you see roughly this shape:

  • Cache library — invalidate, replace, iscached, clonefunction
  • Closures newcclosure, iscclosure, islclosure, checkcaller, clonefunction, hookfunction, hookmetamethod, loadstring
  • Crypt — base64 encode/decode, generatebytes, generatekey, encrypt, decrypt, hash
  • Debug — getconstants, getconstant, setconstant, getupvalues, getupvalue, setupvalue, getprotos, getinfo, getstack
  • Drawing — Drawing.new and all object types (Line, Text, Image, Circle, Square, Quad, Triangle)
  • Filesystem — readfile, writefile, appendfile, listfiles, isfile, isfolder, makefolder, delfolder, delfile, loadfile, dofile
  • Input — keypress, keyrelease, mouse1click, mousemoverel, etc.
  • Instance / metatable — getrawmetatable, setrawmetatable, getnamecallmethod, setnamecallmethod, getconnections, gethiddenproperty, sethiddenproperty, fireproximityprompt, getnilinstances, etc.
  • Reflection — getgenv, getrenv, getsenv, getreg, getloadedmodules, getrunningscripts, getscriptbytecode, getscriptclosure, getscripthash
  • Misc — request, getclipboard, setclipboard, identifyexecutor, messagebox, getfps, queue_on_teleport
  • WebSocket — WebSocket.connect with .Send / .OnMessage / .OnClose / .Close

We have dedicated articles digging into the bigger libraries (hooks, cache, drawing, debug, filesystem, crypt, websocket, instance utilities). The rest of this overview focuses on how the documentation is structured so you can navigate it on your own.

How an entry on docs.sunc.su looks

Every documented function follows the same template: signature, description, a list of parameters with types, the return value with its type, and a short worked example. Here is roughly what a typical page looks like, recreated:

luau
function hookfunction(target: (...any) -> ...any, hook: (...any) -> ...any): (...any) -> ...any
-- Replaces 'target' with 'hook'. Returns the original function so the
-- hook can delegate to it. Both target and hook must be Lua-callable.
Returns(...any) -> ...any
The original function value. Calling it dispatches to the un-hooked implementation, which is how most hooks delegate.
local original
original = hookfunction(print, function(...)
    return original("[hooked]", ...)
end)
print("hello")  --> [hooked] hello

Three things to know about the format: types are written in Luau-style notation ((string, number) -> boolean), example snippets are minimal but complete, and any executor-specific behaviour is called out in a "Notes" paragraph at the bottom — that's where you find the gotchas.

Reading compliance scores

The SUNC score executors advertise is a percentage of the test suite they pass. The suite covers correctness of return types, error cases, edge cases, and side effects. A score of 100% means every documented function exists with the correct signature and the correct behaviour. Anything less means there are gaps — and the test output will tell you exactly which ones.

luau
-- Run the SUNC test from inside the executor
loadstring(game:HttpGet("https://script.sunc.su/"))()

When you run that, the output prints a pass/fail line for each function. Read the failures to learn what your executor doesn't do — that information is more useful than the headline percentage.

A worked example: a SUNC-only script

Here is the kind of small utility that benefits directly from SUNC: a tiny "does this executor have what I need?" gate that scripts can run at startup. Every function it calls is named per the standard.

luau
local REQUIRED = {
    "hookfunction",
    "hookmetamethod",
    "newcclosure",
    "checkcaller",
    "getrawmetatable",
    "request",
    "writefile",
}

local missing = {}
for _, name in REQUIRED do
    if not getfenv()[name] then
        table.insert(missing, name)
    end
end

if #missing > 0 then
    warn("Missing SUNC functions: " .. table.concat(missing, ", "))
    return
end

print("Executor passes startup check.")

On any modern executor with a decent SUNC score this prints "passes". On an older or partial executor it tells you exactly which surface area is missing, so you know what to shim before the rest of your script runs.

When to read the docs vs. when to read the source

SUNC is a contract, not an implementation. Two executors that both score 100% can still behave differently in places the standard doesn't pin down — for example, the exact format of a few error messages, or whether request follows redirects by default. When the documented contract is enough, stop there. When you're writing something that needs executor-specific quirks (anti-detection that depends on fingerprintable behaviour, for instance), you'll need to read the executor's own docs or source instead.

Rule of thumb
If your script is going to ship across multiple executors, target SUNC. If it's exclusive to one, you can use that executor's extensions, but document the dependency.

Companion articles

The libraries above are big enough that each has its own deep-dive guide on this site. Recommended next reads:

Ather
Written by Ather

Ather is the lead developer behind Atherhub. He's been writing Luau and Roblox tooling for the better part of a decade, with a focus on the messy interface between game-script internals and the platforms that host them. Have feedback on this article? Drop it in the Discord.