[
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\n## Guidelines\n* Adding a new function can be done by copying TEMPLATE.md, renaming it, and editing it as needed.\n* You may provide edits of existing functions, just edit and submit it.\n* When possible, organise files in their respective category folders.\n* When writing the function signature, please make sure it is **valid typed Luau syntax**. Documentation for typed luau can be found [here](https://luau-lang.org/typecheck#union-types).\n* When referencing arguments of a function in the description, please use `` in order to make `it look nice like so`.\n* Please confirm a function has not already been added to the API before you submit it.\n\n* Functions must be named appropriately, if you are contributing one - the following criteria applies for the naming:\n  * No brand names should be visible in your documentation.\n    * This also includes function alias' - UNC aims to be a vanilla naming convention, not a branded one\n   * The function name must be **descriptive of what the function does**.\n   * Aliases for shortening function names without good reason are *not* allowed. For example, `hookfunc` is not a alias supported by UNC. Function names should be written out in full.\n  \n* The description must be coherent, if the function is basic enough to not warrant one - you may put \"N/A\" in the description.\n* Functions don't always require an alias, you may just also put N/A in that field.\n\n## Submitting your edits and/or additions\nThis can be done through [github pull requests](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests). Clone the repository, make your changes, then submit a pull request. The pull request will be reviewed by several members of the UNC before it is merged.\n"
  },
  {
    "path": "README.md",
    "content": "# Unified Naming Convention\naka UNC, is an organization between executor developers to provide a unified scripting API for our scripters.\n\n## UNC Has Retired 👋\n\nWho would've thought a globally documented API would be **such a hit**? We sure did! UNC was a great concept and it's lifespan proved it, focusing on building an excellent API for scripters allowed for those scripters to create great scripts, making our software just that more usable.\n\nTwo years ago, UNC helped to resolve the issue of poorly named functions. Today, it's founders at ([Script-Ware](https://script-ware.com/)) have stopped engineering script execution software for Roblox where these functions are used.\n\nYou are welcome to keep using UNC as a benchmark for software, but it will eventually grow out of date with newer features. We're sorry! We hope one day we'll make it up to you.\n\n---\n~~**Please go to our official website for better styled information: https://scriptunc.org/**~~\n\nThis website has since been removed, you can find all of the same information below.\n\n## Why?\nOver the years scripting has gotten more and more complex to support multiple executors. This is because of the many unique naming conventions various executors use.\n\nConsider the following scenario. You want to know if a function belongs to the executor or not. In order for this code to be cross compatiable with all executors code like this is needed:\n```lua\nlocal is_executor_closure = is_syn_closure or is_fluxus_closure or is_sentinel_closure or is_krnl_closure or is_proto_closure or is_calamari_closure or is_electron_closure or is_elysian_closure\n```\nThis is reality for scripters who want cross compatibilty in their scripts. Scripters shouldn't have to do such laborous work just to attain cross compatability. The UNC seeks to solve this problem using naming conventions everyone agrees upon and follows.\n\nOne variant of a script should naturally work on all script executors which have their environment properly fitted to the UNC. \n\n## How?\nThe UNC provides standards for naming conventions as well as API functionality. The standard is written in markdown on this GitHub. Edits or additions are done through pull requests. Edits and additions are manually approved by the UNC council and discussed by everyone.\n\n## Supporting UNC\nAs a product owner, your support of UNC by following the API will result in a far smoother experience for scripters, as they are able to work on scripts that they can confidently say will work on **most** products. Once you have implemented UNC's API, you can display so by adding the badge to your website, thread or application.\n\nYou can find the badge here: ~~https://scriptunc.org/badge~~\n(This badge has since been removed from our website)\n\nThis will notify people of your alliance in providing scripters with an easier method of engineering scripts that your consumers can enjoy.\n\nNOTICE: If you, as a product owner, do not have all of these functions but yet support the ones you do - you then support UNC! You are more than able to display the badge on your website.\n\n## Checking your environment\n\nYou can run the UNC environment checking script to see how well your executor environment supports the UNC standard. Find the script [here.](UNCCheckEnv.lua) The script determines what is missing, and writes the results to file under workspace.\n\n## Contributing\nGo [here](CONTRIBUTING.md) for a guide on contributing.\n"
  },
  {
    "path": "TEMPLATE.md",
    "content": "## FunctionName\n\n`⏰ Yields` `🌎 Global` `🪲 Inconsistent` `🔎 Needs Investigation` `📌 Custom Tag`\n\n```lua\nfunction FunctionName(param: string): ()\n```\n\nDescribe the function in a neat and concise manner.\n\nMay include multiple lines, paragraphs, or info cards.\n\n> ### 🔎 Notes, tips, info\n> Additional information or URLs.\n\n> ### ⚠️ Warnings, risks\n> Exercise caution.\n\n> ### ⛔ Danger!\n> Avoid making this mistake.\n\n> ### 🪲 Bugs, issues\n> Document known issues.\n\n### Parameters\n\n * `param` - The parameter description.\n\n### Aliases\n\n * `functionAlias`\n * `badAlias` - Optional justification.\n\n### Example\n\nA description of the example that follows.\n\n```lua\nprint(FunctionName()) --> (void)\n```"
  },
  {
    "path": "UNCCheckEnv.lua",
    "content": "local passes, fails, undefined = 0, 0, 0\r\nlocal running = 0\r\n\r\nlocal function getGlobal(path)\r\n\tlocal value = getfenv(0)\r\n\r\n\twhile value ~= nil and path ~= \"\" do\r\n\t\tlocal name, nextValue = string.match(path, \"^([^.]+)%.?(.*)$\")\r\n\t\tvalue = value[name]\r\n\t\tpath = nextValue\r\n\tend\r\n\r\n\treturn value\r\nend\r\n\r\nlocal function test(name, aliases, callback)\r\n\trunning += 1\r\n\r\n\ttask.spawn(function()\r\n\t\tif not callback then\r\n\t\t\tprint(\"⏺️ \" .. name)\r\n\t\telseif not getGlobal(name) then\r\n\t\t\tfails += 1\r\n\t\t\twarn(\"⛔ \" .. name)\r\n\t\telse\r\n\t\t\tlocal success, message = pcall(callback)\r\n\t\r\n\t\t\tif success then\r\n\t\t\t\tpasses += 1\r\n\t\t\t\tprint(\"✅ \" .. name .. (message and \" • \" .. message or \"\"))\r\n\t\t\telse\r\n\t\t\t\tfails += 1\r\n\t\t\t\twarn(\"⛔ \" .. name .. \" failed: \" .. message)\r\n\t\t\tend\r\n\t\tend\r\n\t\r\n\t\tlocal undefinedAliases = {}\r\n\t\r\n\t\tfor _, alias in ipairs(aliases) do\r\n\t\t\tif getGlobal(alias) == nil then\r\n\t\t\t\ttable.insert(undefinedAliases, alias)\r\n\t\t\tend\r\n\t\tend\r\n\t\r\n\t\tif #undefinedAliases > 0 then\r\n\t\t\tundefined += 1\r\n\t\t\twarn(\"⚠️ \" .. table.concat(undefinedAliases, \", \"))\r\n\t\tend\r\n\r\n\t\trunning -= 1\r\n\tend)\r\nend\r\n\r\n-- Header and summary\r\n\r\nprint(\"\\n\")\r\n\r\nprint(\"UNC Environment Check\")\r\nprint(\"✅ - Pass, ⛔ - Fail, ⏺️ - No test, ⚠️ - Missing aliases\\n\")\r\n\r\ntask.defer(function()\r\n\trepeat task.wait() until running == 0\r\n\r\n\tlocal rate = math.round(passes / (passes + fails) * 100)\r\n\tlocal outOf = passes .. \" out of \" .. (passes + fails)\r\n\r\n\tprint(\"\\n\")\r\n\r\n\tprint(\"UNC Summary\")\r\n\tprint(\"✅ Tested with a \" .. rate .. \"% success rate (\" .. outOf .. \")\")\r\n\tprint(\"⛔ \" .. fails .. \" tests failed\")\r\n\tprint(\"⚠️ \" .. undefined .. \" globals are missing aliases\")\r\nend)\r\n\r\n-- Cache\r\n\r\ntest(\"cache.invalidate\", {}, function()\r\n\tlocal container = Instance.new(\"Folder\")\r\n\tlocal part = Instance.new(\"Part\", container)\r\n\tcache.invalidate(container:FindFirstChild(\"Part\"))\r\n\tassert(part ~= container:FindFirstChild(\"Part\"), \"Reference `part` could not be invalidated\")\r\nend)\r\n\r\ntest(\"cache.iscached\", {}, function()\r\n\tlocal part = Instance.new(\"Part\")\r\n\tassert(cache.iscached(part), \"Part should be cached\")\r\n\tcache.invalidate(part)\r\n\tassert(not cache.iscached(part), \"Part should not be cached\")\r\nend)\r\n\r\ntest(\"cache.replace\", {}, function()\r\n\tlocal part = Instance.new(\"Part\")\r\n\tlocal fire = Instance.new(\"Fire\")\r\n\tcache.replace(part, fire)\r\n\tassert(part ~= fire, \"Part was not replaced with Fire\")\r\nend)\r\n\r\ntest(\"cloneref\", {}, function()\r\n\tlocal part = Instance.new(\"Part\")\r\n\tlocal clone = cloneref(part)\r\n\tassert(part ~= clone, \"Clone should not be equal to original\")\r\n\tclone.Name = \"Test\"\r\n\tassert(part.Name == \"Test\", \"Clone should have updated the original\")\r\nend)\r\n\r\ntest(\"compareinstances\", {}, function()\r\n\tlocal part = Instance.new(\"Part\")\r\n\tlocal clone = cloneref(part)\r\n\tassert(part ~= clone, \"Clone should not be equal to original\")\r\n\tassert(compareinstances(part, clone), \"Clone should be equal to original when using compareinstances()\")\r\nend)\r\n\r\n-- Closures\r\n\r\nlocal function shallowEqual(t1, t2)\r\n\tif t1 == t2 then\r\n\t\treturn true\r\n\tend\r\n\r\n\tlocal UNIQUE_TYPES = {\r\n\t\t[\"function\"] = true,\r\n\t\t[\"table\"] = true,\r\n\t\t[\"userdata\"] = true,\r\n\t\t[\"thread\"] = true,\r\n\t}\r\n\r\n\tfor k, v in pairs(t1) do\r\n\t\tif UNIQUE_TYPES[type(v)] then\r\n\t\t\tif type(t2[k]) ~= type(v) then\r\n\t\t\t\treturn false\r\n\t\t\tend\r\n\t\telseif t2[k] ~= v then\r\n\t\t\treturn false\r\n\t\tend\r\n\tend\r\n\r\n\tfor k, v in pairs(t2) do\r\n\t\tif UNIQUE_TYPES[type(v)] then\r\n\t\t\tif type(t2[k]) ~= type(v) then\r\n\t\t\t\treturn false\r\n\t\t\tend\r\n\t\telseif t1[k] ~= v then\r\n\t\t\treturn false\r\n\t\tend\r\n\tend\r\n\r\n\treturn true\r\nend\r\n\r\ntest(\"checkcaller\", {}, function()\r\n\tassert(checkcaller(), \"Main scope should return true\")\r\nend)\r\n\r\ntest(\"clonefunction\", {}, function()\r\n\tlocal function test()\r\n\t\treturn \"success\"\r\n\tend\r\n\tlocal copy = clonefunction(test)\r\n\tassert(test() == copy(), \"The clone should return the same value as the original\")\r\n\tassert(test ~= copy, \"The clone should not be equal to the original\")\r\nend)\r\n\r\ntest(\"getcallingscript\", {})\r\n\r\ntest(\"getscriptclosure\", {\"getscriptfunction\"}, function()\r\n\tlocal module = game:GetService(\"CoreGui\").RobloxGui.Modules.Common.Constants\r\n\tlocal constants = getrenv().require(module)\r\n\tlocal generated = getscriptclosure(module)()\r\n\tassert(constants ~= generated, \"Generated module should not match the original\")\r\n\tassert(shallowEqual(constants, generated), \"Generated constant table should be shallow equal to the original\")\r\nend)\r\n\r\ntest(\"hookfunction\", {\"replaceclosure\"}, function()\r\n\tlocal function test()\r\n\t\treturn true\r\n\tend\r\n\tlocal ref = hookfunction(test, function()\r\n\t\treturn false\r\n\tend)\r\n\tassert(test() == false, \"Function should return false\")\r\n\tassert(ref() == true, \"Original function should return true\")\r\n\tassert(test ~= ref, \"Original function should not be same as the reference\")\r\nend)\r\n\r\ntest(\"iscclosure\", {}, function()\r\n\tassert(iscclosure(print) == true, \"Function 'print' should be a C closure\")\r\n\tassert(iscclosure(function() end) == false, \"Executor function should not be a C closure\")\r\nend)\r\n\r\ntest(\"islclosure\", {}, function()\r\n\tassert(islclosure(print) == false, \"Function 'print' should not be a Lua closure\")\r\n\tassert(islclosure(function() end) == true, \"Executor function should be a Lua closure\")\r\nend)\r\n\r\ntest(\"isexecutorclosure\", {\"checkclosure\", \"isourclosure\"}, function()\r\n\tassert(isexecutorclosure(isexecutorclosure) == true, \"Did not return true for an executor global\")\r\n\tassert(isexecutorclosure(newcclosure(function() end)) == true, \"Did not return true for an executor C closure\")\r\n\tassert(isexecutorclosure(function() end) == true, \"Did not return true for an executor Luau closure\")\r\n\tassert(isexecutorclosure(print) == false, \"Did not return false for a Roblox global\")\r\nend)\r\n\r\ntest(\"loadstring\", {}, function()\r\n\tlocal animate = game:GetService(\"Players\").LocalPlayer.Character.Animate\r\n\tlocal bytecode = getscriptbytecode(animate)\r\n\tlocal func = loadstring(bytecode)\r\n\tassert(type(func) ~= \"function\", \"Luau bytecode should not be loadable!\")\r\n\tassert(assert(loadstring(\"return ... + 1\"))(1) == 2, \"Failed to do simple math\")\r\n\tassert(type(select(2, loadstring(\"f\"))) == \"string\", \"Loadstring did not return anything for a compiler error\")\r\nend)\r\n\r\ntest(\"newcclosure\", {}, function()\r\n\tlocal function test()\r\n\t\treturn true\r\n\tend\r\n\tlocal testC = newcclosure(test)\r\n\tassert(test() == testC(), \"New C closure should return the same value as the original\")\r\n\tassert(test ~= testC, \"New C closure should not be same as the original\")\r\n\tassert(iscclosure(testC), \"New C closure should be a C closure\")\r\nend)\r\n\r\n-- Console\r\n\r\ntest(\"rconsoleclear\", {\"consoleclear\"})\r\n\r\ntest(\"rconsolecreate\", {\"consolecreate\"})\r\n\r\ntest(\"rconsoledestroy\", {\"consoledestroy\"})\r\n\r\ntest(\"rconsoleinput\", {\"consoleinput\"})\r\n\r\ntest(\"rconsoleprint\", {\"consoleprint\"})\r\n\r\ntest(\"rconsolesettitle\", {\"rconsolename\", \"consolesettitle\"})\r\n\r\n-- Crypt\r\n\r\ntest(\"crypt.base64encode\", {\"crypt.base64.encode\", \"crypt.base64_encode\", \"base64.encode\", \"base64_encode\"}, function()\r\n\tassert(crypt.base64encode(\"test\") == \"dGVzdA==\", \"Base64 encoding failed\")\r\nend)\r\n\r\ntest(\"crypt.base64decode\", {\"crypt.base64.decode\", \"crypt.base64_decode\", \"base64.decode\", \"base64_decode\"}, function()\r\n\tassert(crypt.base64decode(\"dGVzdA==\") == \"test\", \"Base64 decoding failed\")\r\nend)\r\n\r\ntest(\"crypt.encrypt\", {}, function()\r\n\tlocal key = crypt.generatekey()\r\n\tlocal encrypted, iv = crypt.encrypt(\"test\", key, nil, \"CBC\")\r\n\tassert(iv, \"crypt.encrypt should return an IV\")\r\n\tlocal decrypted = crypt.decrypt(encrypted, key, iv, \"CBC\")\r\n\tassert(decrypted == \"test\", \"Failed to decrypt raw string from encrypted data\")\r\nend)\r\n\r\ntest(\"crypt.decrypt\", {}, function()\r\n\tlocal key, iv = crypt.generatekey(), crypt.generatekey()\r\n\tlocal encrypted = crypt.encrypt(\"test\", key, iv, \"CBC\")\r\n\tlocal decrypted = crypt.decrypt(encrypted, key, iv, \"CBC\")\r\n\tassert(decrypted == \"test\", \"Failed to decrypt raw string from encrypted data\")\r\nend)\r\n\r\ntest(\"crypt.generatebytes\", {}, function()\r\n\tlocal size = math.random(10, 100)\r\n\tlocal bytes = crypt.generatebytes(size)\r\n\tassert(#crypt.base64decode(bytes) == size, \"The decoded result should be \" .. size .. \" bytes long (got \" .. #crypt.base64decode(bytes) .. \" decoded, \" .. #bytes .. \" raw)\")\r\nend)\r\n\r\ntest(\"crypt.generatekey\", {}, function()\r\n\tlocal key = crypt.generatekey()\r\n\tassert(#crypt.base64decode(key) == 32, \"Generated key should be 32 bytes long when decoded\")\r\nend)\r\n\r\ntest(\"crypt.hash\", {}, function()\r\n\tlocal algorithms = {'sha1', 'sha384', 'sha512', 'md5', 'sha256', 'sha3-224', 'sha3-256', 'sha3-512'}\r\n\tfor _, algorithm in ipairs(algorithms) do\r\n\t\tlocal hash = crypt.hash(\"test\", algorithm)\r\n\t\tassert(hash, \"crypt.hash on algorithm '\" .. algorithm .. \"' should return a hash\")\r\n\tend\r\nend)\r\n\r\n--- Debug\r\n\r\ntest(\"debug.getconstant\", {}, function()\r\n\tlocal function test()\r\n\t\tprint(\"Hello, world!\")\r\n\tend\r\n\tassert(debug.getconstant(test, 1) == \"print\", \"First constant must be print\")\r\n\tassert(debug.getconstant(test, 2) == nil, \"Second constant must be nil\")\r\n\tassert(debug.getconstant(test, 3) == \"Hello, world!\", \"Third constant must be 'Hello, world!'\")\r\nend)\r\n\r\ntest(\"debug.getconstants\", {}, function()\r\n\tlocal function test()\r\n\t\tlocal num = 5000 .. 50000\r\n\t\tprint(\"Hello, world!\", num, warn)\r\n\tend\r\n\tlocal constants = debug.getconstants(test)\r\n\tassert(constants[1] == 50000, \"First constant must be 50000\")\r\n\tassert(constants[2] == \"print\", \"Second constant must be print\")\r\n\tassert(constants[3] == nil, \"Third constant must be nil\")\r\n\tassert(constants[4] == \"Hello, world!\", \"Fourth constant must be 'Hello, world!'\")\r\n\tassert(constants[5] == \"warn\", \"Fifth constant must be warn\")\r\nend)\r\n\r\ntest(\"debug.getinfo\", {}, function()\r\n\tlocal types = {\r\n\t\tsource = \"string\",\r\n\t\tshort_src = \"string\",\r\n\t\tfunc = \"function\",\r\n\t\twhat = \"string\",\r\n\t\tcurrentline = \"number\",\r\n\t\tname = \"string\",\r\n\t\tnups = \"number\",\r\n\t\tnumparams = \"number\",\r\n\t\tis_vararg = \"number\",\r\n\t}\r\n\tlocal function test(...)\r\n\t\tprint(...)\r\n\tend\r\n\tlocal info = debug.getinfo(test)\r\n\tfor k, v in pairs(types) do\r\n\t\tassert(info[k] ~= nil, \"Did not return a table with a '\" .. k .. \"' field\")\r\n\t\tassert(type(info[k]) == v, \"Did not return a table with \" .. k .. \" as a \" .. v .. \" (got \" .. type(info[k]) .. \")\")\r\n\tend\r\nend)\r\n\r\ntest(\"debug.getproto\", {}, function()\r\n\tlocal function test()\r\n\t\tlocal function proto()\r\n\t\t\treturn true\r\n\t\tend\r\n\tend\r\n\tlocal proto = debug.getproto(test, 1, true)[1]\r\n\tlocal realproto = debug.getproto(test, 1)\r\n\tassert(proto, \"Failed to get the inner function\")\r\n\tassert(proto() == true, \"The inner function did not return anything\")\r\n\tif not realproto() then\r\n\t\treturn \"Proto return values are disabled on this executor\"\r\n\tend\r\nend)\r\n\r\ntest(\"debug.getprotos\", {}, function()\r\n\tlocal function test()\r\n\t\tlocal function _1()\r\n\t\t\treturn true\r\n\t\tend\r\n\t\tlocal function _2()\r\n\t\t\treturn true\r\n\t\tend\r\n\t\tlocal function _3()\r\n\t\t\treturn true\r\n\t\tend\r\n\tend\r\n\tfor i in ipairs(debug.getprotos(test)) do\r\n\t\tlocal proto = debug.getproto(test, i, true)[1]\r\n\t\tlocal realproto = debug.getproto(test, i)\r\n\t\tassert(proto(), \"Failed to get inner function \" .. i)\r\n\t\tif not realproto() then\r\n\t\t\treturn \"Proto return values are disabled on this executor\"\r\n\t\tend\r\n\tend\r\nend)\r\n\r\ntest(\"debug.getstack\", {}, function()\r\n\tlocal _ = \"a\" .. \"b\"\r\n\tassert(debug.getstack(1, 1) == \"ab\", \"The first item in the stack should be 'ab'\")\r\n\tassert(debug.getstack(1)[1] == \"ab\", \"The first item in the stack table should be 'ab'\")\r\nend)\r\n\r\ntest(\"debug.getupvalue\", {}, function()\r\n\tlocal upvalue = function() end\r\n\tlocal function test()\r\n\t\tprint(upvalue)\r\n\tend\r\n\tassert(debug.getupvalue(test, 1) == upvalue, \"Unexpected value returned from debug.getupvalue\")\r\nend)\r\n\r\ntest(\"debug.getupvalues\", {}, function()\r\n\tlocal upvalue = function() end\r\n\tlocal function test()\r\n\t\tprint(upvalue)\r\n\tend\r\n\tlocal upvalues = debug.getupvalues(test)\r\n\tassert(upvalues[1] == upvalue, \"Unexpected value returned from debug.getupvalues\")\r\nend)\r\n\r\ntest(\"debug.setconstant\", {}, function()\r\n\tlocal function test()\r\n\t\treturn \"fail\"\r\n\tend\r\n\tdebug.setconstant(test, 1, \"success\")\r\n\tassert(test() == \"success\", \"debug.setconstant did not set the first constant\")\r\nend)\r\n\r\ntest(\"debug.setstack\", {}, function()\r\n\tlocal function test()\r\n\t\treturn \"fail\", debug.setstack(1, 1, \"success\")\r\n\tend\r\n\tassert(test() == \"success\", \"debug.setstack did not set the first stack item\")\r\nend)\r\n\r\ntest(\"debug.setupvalue\", {}, function()\r\n\tlocal function upvalue()\r\n\t\treturn \"fail\"\r\n\tend\r\n\tlocal function test()\r\n\t\treturn upvalue()\r\n\tend\r\n\tdebug.setupvalue(test, 1, function()\r\n\t\treturn \"success\"\r\n\tend)\r\n\tassert(test() == \"success\", \"debug.setupvalue did not set the first upvalue\")\r\nend)\r\n\r\n-- Filesystem\r\n\r\nif isfolder and makefolder and delfolder then\r\n\tif isfolder(\".tests\") then\r\n\t\tdelfolder(\".tests\")\r\n\tend\r\n\tmakefolder(\".tests\")\r\nend\r\n\r\ntest(\"readfile\", {}, function()\r\n\twritefile(\".tests/readfile.txt\", \"success\")\r\n\tassert(readfile(\".tests/readfile.txt\") == \"success\", \"Did not return the contents of the file\")\r\nend)\r\n\r\ntest(\"listfiles\", {}, function()\r\n\tmakefolder(\".tests/listfiles\")\r\n\twritefile(\".tests/listfiles/test_1.txt\", \"success\")\r\n\twritefile(\".tests/listfiles/test_2.txt\", \"success\")\r\n\tlocal files = listfiles(\".tests/listfiles\")\r\n\tassert(#files == 2, \"Did not return the correct number of files\")\r\n\tassert(isfile(files[1]), \"Did not return a file path\")\r\n\tassert(readfile(files[1]) == \"success\", \"Did not return the correct files\")\r\n\tmakefolder(\".tests/listfiles_2\")\r\n\tmakefolder(\".tests/listfiles_2/test_1\")\r\n\tmakefolder(\".tests/listfiles_2/test_2\")\r\n\tlocal folders = listfiles(\".tests/listfiles_2\")\r\n\tassert(#folders == 2, \"Did not return the correct number of folders\")\r\n\tassert(isfolder(folders[1]), \"Did not return a folder path\")\r\nend)\r\n\r\ntest(\"writefile\", {}, function()\r\n\twritefile(\".tests/writefile.txt\", \"success\")\r\n\tassert(readfile(\".tests/writefile.txt\") == \"success\", \"Did not write the file\")\r\n\tlocal requiresFileExt = pcall(function()\r\n\t\twritefile(\".tests/writefile\", \"success\")\r\n\t\tassert(isfile(\".tests/writefile.txt\"))\r\n\tend)\r\n\tif not requiresFileExt then\r\n\t\treturn \"This executor requires a file extension in writefile\"\r\n\tend\r\nend)\r\n\r\ntest(\"makefolder\", {}, function()\r\n\tmakefolder(\".tests/makefolder\")\r\n\tassert(isfolder(\".tests/makefolder\"), \"Did not create the folder\")\r\nend)\r\n\r\ntest(\"appendfile\", {}, function()\r\n\twritefile(\".tests/appendfile.txt\", \"su\")\r\n\tappendfile(\".tests/appendfile.txt\", \"cce\")\r\n\tappendfile(\".tests/appendfile.txt\", \"ss\")\r\n\tassert(readfile(\".tests/appendfile.txt\") == \"success\", \"Did not append the file\")\r\nend)\r\n\r\ntest(\"isfile\", {}, function()\r\n\twritefile(\".tests/isfile.txt\", \"success\")\r\n\tassert(isfile(\".tests/isfile.txt\") == true, \"Did not return true for a file\")\r\n\tassert(isfile(\".tests\") == false, \"Did not return false for a folder\")\r\n\tassert(isfile(\".tests/doesnotexist.exe\") == false, \"Did not return false for a nonexistent path (got \" .. tostring(isfile(\".tests/doesnotexist.exe\")) .. \")\")\r\nend)\r\n\r\ntest(\"isfolder\", {}, function()\r\n\tassert(isfolder(\".tests\") == true, \"Did not return false for a folder\")\r\n\tassert(isfolder(\".tests/doesnotexist.exe\") == false, \"Did not return false for a nonexistent path (got \" .. tostring(isfolder(\".tests/doesnotexist.exe\")) .. \")\")\r\nend)\r\n\r\ntest(\"delfolder\", {}, function()\r\n\tmakefolder(\".tests/delfolder\")\r\n\tdelfolder(\".tests/delfolder\")\r\n\tassert(isfolder(\".tests/delfolder\") == false, \"Failed to delete folder (isfolder = \" .. tostring(isfolder(\".tests/delfolder\")) .. \")\")\r\nend)\r\n\r\ntest(\"delfile\", {}, function()\r\n\twritefile(\".tests/delfile.txt\", \"Hello, world!\")\r\n\tdelfile(\".tests/delfile.txt\")\r\n\tassert(isfile(\".tests/delfile.txt\") == false, \"Failed to delete file (isfile = \" .. tostring(isfile(\".tests/delfile.txt\")) .. \")\")\r\nend)\r\n\r\ntest(\"loadfile\", {}, function()\r\n\twritefile(\".tests/loadfile.txt\", \"return ... + 1\")\r\n\tassert(assert(loadfile(\".tests/loadfile.txt\"))(1) == 2, \"Failed to load a file with arguments\")\r\n\twritefile(\".tests/loadfile.txt\", \"f\")\r\n\tlocal callback, err = loadfile(\".tests/loadfile.txt\")\r\n\tassert(err and not callback, \"Did not return an error message for a compiler error\")\r\nend)\r\n\r\ntest(\"dofile\", {})\r\n\r\n-- Input\r\n\r\ntest(\"isrbxactive\", {\"isgameactive\"}, function()\r\n\tassert(type(isrbxactive()) == \"boolean\", \"Did not return a boolean value\")\r\nend)\r\n\r\ntest(\"mouse1click\", {})\r\n\r\ntest(\"mouse1press\", {})\r\n\r\ntest(\"mouse1release\", {})\r\n\r\ntest(\"mouse2click\", {})\r\n\r\ntest(\"mouse2press\", {})\r\n\r\ntest(\"mouse2release\", {})\r\n\r\ntest(\"mousemoveabs\", {})\r\n\r\ntest(\"mousemoverel\", {})\r\n\r\ntest(\"mousescroll\", {})\r\n\r\n-- Instances\r\n\r\ntest(\"fireclickdetector\", {}, function()\r\n\tlocal detector = Instance.new(\"ClickDetector\")\r\n\tfireclickdetector(detector, 50, \"MouseHoverEnter\")\r\nend)\r\n\r\ntest(\"getcallbackvalue\", {}, function()\r\n\tlocal bindable = Instance.new(\"BindableFunction\")\r\n\tlocal function test()\r\n\tend\r\n\tbindable.OnInvoke = test\r\n\tassert(getcallbackvalue(bindable, \"OnInvoke\") == test, \"Did not return the correct value\")\r\nend)\r\n\r\ntest(\"getconnections\", {}, function()\r\n\tlocal types = {\r\n\t\tEnabled = \"boolean\",\r\n\t\tForeignState = \"boolean\",\r\n\t\tLuaConnection = \"boolean\",\r\n\t\tFunction = \"function\",\r\n\t\tThread = \"thread\",\r\n\t\tFire = \"function\",\r\n\t\tDefer = \"function\",\r\n\t\tDisconnect = \"function\",\r\n\t\tDisable = \"function\",\r\n\t\tEnable = \"function\",\r\n\t}\r\n\tlocal bindable = Instance.new(\"BindableEvent\")\r\n\tbindable.Event:Connect(function() end)\r\n\tlocal connection = getconnections(bindable.Event)[1]\r\n\tfor k, v in pairs(types) do\r\n\t\tassert(connection[k] ~= nil, \"Did not return a table with a '\" .. k .. \"' field\")\r\n\t\tassert(type(connection[k]) == v, \"Did not return a table with \" .. k .. \" as a \" .. v .. \" (got \" .. type(connection[k]) .. \")\")\r\n\tend\r\nend)\r\n\r\ntest(\"getcustomasset\", {}, function()\r\n\twritefile(\".tests/getcustomasset.txt\", \"success\")\r\n\tlocal contentId = getcustomasset(\".tests/getcustomasset.txt\")\r\n\tassert(type(contentId) == \"string\", \"Did not return a string\")\r\n\tassert(#contentId > 0, \"Returned an empty string\")\r\n\tassert(string.match(contentId, \"rbxasset://\") == \"rbxasset://\", \"Did not return an rbxasset url\")\r\nend)\r\n\r\ntest(\"gethiddenproperty\", {}, function()\r\n\tlocal fire = Instance.new(\"Fire\")\r\n\tlocal property, isHidden = gethiddenproperty(fire, \"size_xml\")\r\n\tassert(property == 5, \"Did not return the correct value\")\r\n\tassert(isHidden == true, \"Did not return whether the property was hidden\")\r\nend)\r\n\r\ntest(\"sethiddenproperty\", {}, function()\r\n\tlocal fire = Instance.new(\"Fire\")\r\n\tlocal hidden = sethiddenproperty(fire, \"size_xml\", 10)\r\n\tassert(hidden, \"Did not return true for the hidden property\")\r\n\tassert(gethiddenproperty(fire, \"size_xml\") == 10, \"Did not set the hidden property\")\r\nend)\r\n\r\ntest(\"gethui\", {}, function()\r\n\tassert(typeof(gethui()) == \"Instance\", \"Did not return an Instance\")\r\nend)\r\n\r\ntest(\"getinstances\", {}, function()\r\n\tassert(getinstances()[1]:IsA(\"Instance\"), \"The first value is not an Instance\")\r\nend)\r\n\r\ntest(\"getnilinstances\", {}, function()\r\n\tassert(getnilinstances()[1]:IsA(\"Instance\"), \"The first value is not an Instance\")\r\n\tassert(getnilinstances()[1].Parent == nil, \"The first value is not parented to nil\")\r\nend)\r\n\r\ntest(\"isscriptable\", {}, function()\r\n\tlocal fire = Instance.new(\"Fire\")\r\n\tassert(isscriptable(fire, \"size_xml\") == false, \"Did not return false for a non-scriptable property (size_xml)\")\r\n\tassert(isscriptable(fire, \"Size\") == true, \"Did not return true for a scriptable property (Size)\")\r\nend)\r\n\r\ntest(\"setscriptable\", {}, function()\r\n\tlocal fire = Instance.new(\"Fire\")\r\n\tlocal wasScriptable = setscriptable(fire, \"size_xml\", true)\r\n\tassert(wasScriptable == false, \"Did not return false for a non-scriptable property (size_xml)\")\r\n\tassert(isscriptable(fire, \"size_xml\") == true, \"Did not set the scriptable property\")\r\n\tfire = Instance.new(\"Fire\")\r\n\tassert(isscriptable(fire, \"size_xml\") == false, \"⚠️⚠️ setscriptable persists between unique instances ⚠️⚠️\")\r\nend)\r\n\r\ntest(\"setrbxclipboard\", {})\r\n\r\n-- Metatable\r\n\r\ntest(\"getrawmetatable\", {}, function()\r\n\tlocal metatable = { __metatable = \"Locked!\" }\r\n\tlocal object = setmetatable({}, metatable)\r\n\tassert(getrawmetatable(object) == metatable, \"Did not return the metatable\")\r\nend)\r\n\r\ntest(\"hookmetamethod\", {}, function()\r\n\tlocal object = setmetatable({}, { __index = newcclosure(function() return false end), __metatable = \"Locked!\" })\r\n\tlocal ref = hookmetamethod(object, \"__index\", function() return true end)\r\n\tassert(object.test == true, \"Failed to hook a metamethod and change the return value\")\r\n\tassert(ref() == false, \"Did not return the original function\")\r\nend)\r\n\r\ntest(\"getnamecallmethod\", {}, function()\r\n\tlocal method\r\n\tlocal ref\r\n\tref = hookmetamethod(game, \"__namecall\", function(...)\r\n\t\tif not method then\r\n\t\t\tmethod = getnamecallmethod()\r\n\t\tend\r\n\t\treturn ref(...)\r\n\tend)\r\n\tgame:GetService(\"Lighting\")\r\n\tassert(method == \"GetService\", \"Did not get the correct method (GetService)\")\r\nend)\r\n\r\ntest(\"isreadonly\", {}, function()\r\n\tlocal object = {}\r\n\ttable.freeze(object)\r\n\tassert(isreadonly(object), \"Did not return true for a read-only table\")\r\nend)\r\n\r\ntest(\"setrawmetatable\", {}, function()\r\n\tlocal object = setmetatable({}, { __index = function() return false end, __metatable = \"Locked!\" })\r\n\tlocal objectReturned = setrawmetatable(object, { __index = function() return true end })\r\n\tassert(object, \"Did not return the original object\")\r\n\tassert(object.test == true, \"Failed to change the metatable\")\r\n\tif objectReturned then\r\n\t\treturn objectReturned == object and \"Returned the original object\" or \"Did not return the original object\"\r\n\tend\r\nend)\r\n\r\ntest(\"setreadonly\", {}, function()\r\n\tlocal object = { success = false }\r\n\ttable.freeze(object)\r\n\tsetreadonly(object, false)\r\n\tobject.success = true\r\n\tassert(object.success, \"Did not allow the table to be modified\")\r\nend)\r\n\r\n-- Miscellaneous\r\n\r\ntest(\"identifyexecutor\", {\"getexecutorname\"}, function()\r\n\tlocal name, version = identifyexecutor()\r\n\tassert(type(name) == \"string\", \"Did not return a string for the name\")\r\n\treturn type(version) == \"string\" and \"Returns version as a string\" or \"Does not return version\"\r\nend)\r\n\r\ntest(\"lz4compress\", {}, function()\r\n\tlocal raw = \"Hello, world!\"\r\n\tlocal compressed = lz4compress(raw)\r\n\tassert(type(compressed) == \"string\", \"Compression did not return a string\")\r\n\tassert(lz4decompress(compressed, #raw) == raw, \"Decompression did not return the original string\")\r\nend)\r\n\r\ntest(\"lz4decompress\", {}, function()\r\n\tlocal raw = \"Hello, world!\"\r\n\tlocal compressed = lz4compress(raw)\r\n\tassert(type(compressed) == \"string\", \"Compression did not return a string\")\r\n\tassert(lz4decompress(compressed, #raw) == raw, \"Decompression did not return the original string\")\r\nend)\r\n\r\ntest(\"messagebox\", {})\r\n\r\ntest(\"queue_on_teleport\", {\"queueonteleport\"})\r\n\r\ntest(\"request\", {\"http.request\", \"http_request\"}, function()\r\n\tlocal response = request({\r\n\t\tUrl = \"https://httpbin.org/user-agent\",\r\n\t\tMethod = \"GET\",\r\n\t})\r\n\tassert(type(response) == \"table\", \"Response must be a table\")\r\n\tassert(response.StatusCode == 200, \"Did not return a 200 status code\")\r\n\tlocal data = game:GetService(\"HttpService\"):JSONDecode(response.Body)\r\n\tassert(type(data) == \"table\" and type(data[\"user-agent\"]) == \"string\", \"Did not return a table with a user-agent key\")\r\n\treturn \"User-Agent: \" .. data[\"user-agent\"]\r\nend)\r\n\r\ntest(\"setclipboard\", {\"toclipboard\"})\r\n\r\ntest(\"setfpscap\", {}, function()\r\n\tlocal renderStepped = game:GetService(\"RunService\").RenderStepped\r\n\tlocal function step()\r\n\t\trenderStepped:Wait()\r\n\t\tlocal sum = 0\r\n\t\tfor _ = 1, 5 do\r\n\t\t\tsum += 1 / renderStepped:Wait()\r\n\t\tend\r\n\t\treturn math.round(sum / 5)\r\n\tend\r\n\tsetfpscap(60)\r\n\tlocal step60 = step()\r\n\tsetfpscap(0)\r\n\tlocal step0 = step()\r\n\treturn step60 .. \"fps @60 • \" .. step0 .. \"fps @0\"\r\nend)\r\n\r\n-- Scripts\r\n\r\ntest(\"getgc\", {}, function()\r\n\tlocal gc = getgc()\r\n\tassert(type(gc) == \"table\", \"Did not return a table\")\r\n\tassert(#gc > 0, \"Did not return a table with any values\")\r\nend)\r\n\r\ntest(\"getgenv\", {}, function()\r\n\tgetgenv().__TEST_GLOBAL = true\r\n\tassert(__TEST_GLOBAL, \"Failed to set a global variable\")\r\n\tgetgenv().__TEST_GLOBAL = nil\r\nend)\r\n\r\ntest(\"getloadedmodules\", {}, function()\r\n\tlocal modules = getloadedmodules()\r\n\tassert(type(modules) == \"table\", \"Did not return a table\")\r\n\tassert(#modules > 0, \"Did not return a table with any values\")\r\n\tassert(typeof(modules[1]) == \"Instance\", \"First value is not an Instance\")\r\n\tassert(modules[1]:IsA(\"ModuleScript\"), \"First value is not a ModuleScript\")\r\nend)\r\n\r\ntest(\"getrenv\", {}, function()\r\n\tassert(_G ~= getrenv()._G, \"The variable _G in the executor is identical to _G in the game\")\r\nend)\r\n\r\ntest(\"getrunningscripts\", {}, function()\r\n\tlocal scripts = getrunningscripts()\r\n\tassert(type(scripts) == \"table\", \"Did not return a table\")\r\n\tassert(#scripts > 0, \"Did not return a table with any values\")\r\n\tassert(typeof(scripts[1]) == \"Instance\", \"First value is not an Instance\")\r\n\tassert(scripts[1]:IsA(\"ModuleScript\") or scripts[1]:IsA(\"LocalScript\"), \"First value is not a ModuleScript or LocalScript\")\r\nend)\r\n\r\ntest(\"getscriptbytecode\", {\"dumpstring\"}, function()\r\n\tlocal animate = game:GetService(\"Players\").LocalPlayer.Character.Animate\r\n\tlocal bytecode = getscriptbytecode(animate)\r\n\tassert(type(bytecode) == \"string\", \"Did not return a string for Character.Animate (a \" .. animate.ClassName .. \")\")\r\nend)\r\n\r\ntest(\"getscripthash\", {}, function()\r\n\tlocal animate = game:GetService(\"Players\").LocalPlayer.Character.Animate:Clone()\r\n\tlocal hash = getscripthash(animate)\r\n\tlocal source = animate.Source\r\n\tanimate.Source = \"print('Hello, world!')\"\r\n\ttask.defer(function()\r\n\t\tanimate.Source = source\r\n\tend)\r\n\tlocal newHash = getscripthash(animate)\r\n\tassert(hash ~= newHash, \"Did not return a different hash for a modified script\")\r\n\tassert(newHash == getscripthash(animate), \"Did not return the same hash for a script with the same source\")\r\nend)\r\n\r\ntest(\"getscripts\", {}, function()\r\n\tlocal scripts = getscripts()\r\n\tassert(type(scripts) == \"table\", \"Did not return a table\")\r\n\tassert(#scripts > 0, \"Did not return a table with any values\")\r\n\tassert(typeof(scripts[1]) == \"Instance\", \"First value is not an Instance\")\r\n\tassert(scripts[1]:IsA(\"ModuleScript\") or scripts[1]:IsA(\"LocalScript\"), \"First value is not a ModuleScript or LocalScript\")\r\nend)\r\n\r\ntest(\"getsenv\", {}, function()\r\n\tlocal animate = game:GetService(\"Players\").LocalPlayer.Character.Animate\r\n\tlocal env = getsenv(animate)\r\n\tassert(type(env) == \"table\", \"Did not return a table for Character.Animate (a \" .. animate.ClassName .. \")\")\r\n\tassert(env.script == animate, \"The script global is not identical to Character.Animate\")\r\nend)\r\n\r\ntest(\"getthreadidentity\", {\"getidentity\", \"getthreadcontext\"}, function()\r\n\tassert(type(getthreadidentity()) == \"number\", \"Did not return a number\")\r\nend)\r\n\r\ntest(\"setthreadidentity\", {\"setidentity\", \"setthreadcontext\"}, function()\r\n\tsetthreadidentity(3)\r\n\tassert(getthreadidentity() == 3, \"Did not set the thread identity\")\r\nend)\r\n\r\n-- Drawing\r\n\r\ntest(\"Drawing\", {})\r\n\r\ntest(\"Drawing.new\", {}, function()\r\n\tlocal drawing = Drawing.new(\"Square\")\r\n\tdrawing.Visible = false\r\n\tlocal canDestroy = pcall(function()\r\n\t\tdrawing:Destroy()\r\n\tend)\r\n\tassert(canDestroy, \"Drawing:Destroy() should not throw an error\")\r\nend)\r\n\r\ntest(\"Drawing.Fonts\", {}, function()\r\n\tassert(Drawing.Fonts.UI == 0, \"Did not return the correct id for UI\")\r\n\tassert(Drawing.Fonts.System == 1, \"Did not return the correct id for System\")\r\n\tassert(Drawing.Fonts.Plex == 2, \"Did not return the correct id for Plex\")\r\n\tassert(Drawing.Fonts.Monospace == 3, \"Did not return the correct id for Monospace\")\r\nend)\r\n\r\ntest(\"isrenderobj\", {}, function()\r\n\tlocal drawing = Drawing.new(\"Image\")\r\n\tdrawing.Visible = true\r\n\tassert(isrenderobj(drawing) == true, \"Did not return true for an Image\")\r\n\tassert(isrenderobj(newproxy()) == false, \"Did not return false for a blank table\")\r\nend)\r\n\r\ntest(\"getrenderproperty\", {}, function()\r\n\tlocal drawing = Drawing.new(\"Image\")\r\n\tdrawing.Visible = true\r\n\tassert(type(getrenderproperty(drawing, \"Visible\")) == \"boolean\", \"Did not return a boolean value for Image.Visible\")\r\n\tlocal success, result = pcall(function()\r\n\t\treturn getrenderproperty(drawing, \"Color\")\r\n\tend)\r\n\tif not success or not result then\r\n\t\treturn \"Image.Color is not supported\"\r\n\tend\r\nend)\r\n\r\ntest(\"setrenderproperty\", {}, function()\r\n\tlocal drawing = Drawing.new(\"Square\")\r\n\tdrawing.Visible = true\r\n\tsetrenderproperty(drawing, \"Visible\", false)\r\n\tassert(drawing.Visible == false, \"Did not set the value for Square.Visible\")\r\nend)\r\n\r\ntest(\"cleardrawcache\", {}, function()\r\n\tcleardrawcache()\r\nend)\r\n\r\n-- WebSocket\r\n\r\ntest(\"WebSocket\", {})\r\n\r\ntest(\"WebSocket.connect\", {}, function()\r\n\tlocal types = {\r\n\t\tSend = \"function\",\r\n\t\tClose = \"function\",\r\n\t\tOnMessage = {\"table\", \"userdata\"},\r\n\t\tOnClose = {\"table\", \"userdata\"},\r\n\t}\r\n\tlocal ws = WebSocket.connect(\"ws://echo.websocket.events\")\r\n\tassert(type(ws) == \"table\" or type(ws) == \"userdata\", \"Did not return a table or userdata\")\r\n\tfor k, v in pairs(types) do\r\n\t\tif type(v) == \"table\" then\r\n\t\t\tassert(table.find(v, type(ws[k])), \"Did not return a \" .. table.concat(v, \", \") .. \" for \" .. k .. \" (a \" .. type(ws[k]) .. \")\")\r\n\t\telse\r\n\t\t\tassert(type(ws[k]) == v, \"Did not return a \" .. v .. \" for \" .. k .. \" (a \" .. type(ws[k]) .. \")\")\r\n\t\tend\r\n\tend\r\n\tws:Close()\r\nend)\r\n"
  },
  {
    "path": "api/Drawing.md",
    "content": "# Drawing\n\nThe **Drawing** class provides an interface for drawing shapes and text above the game window.\n\n---\n\n## Drawing.new\n\n`🏛️ Constructor`\n\n```lua\nfunction Drawing.new(type: string): Drawing\n```\n\nCreate a new drawing object of the specified type.\n\nThe possible types are 'Line', 'Text', 'Image', 'Circle', 'Square', 'Quad', and 'Triangle'.\n\n### Parameters\n\n * `type` - The type of drawing object to create.\n\n### Example\n\n```lua\nlocal circle = Drawing.new(\"Circle\")\ncircle.Radius = 50\ncircle.Color = Color3.fromRGB(255, 0, 0)\ncircle.Filled = true\ncircle.NumSides = 32\ncircle.Position = Vector2.new(300, 300)\ncircle.Transparency = 0.7\ncircle.Visible = true\n\ntask.wait(1)\ncircle:Destroy()\n```\n\n---\n\n## Drawing.Fonts\n\n`⭕ Static` `🔒 Read-only`\n\n```lua\nDrawing.Fonts: {\n\tUI: 0,\n\tSystem: 1,\n\tPlex: 2,\n\tMonospace: 3,\n}\n```\n\nA table containing the available font names. The style of each font varies depending on the executor.\n\n### Fonts\n\n<details>\n<summary>Show font table</summary>\n\n> | Executor | Fonts |\n> | --------- | ----- |\n> | Script-Ware | ![Script-Ware Fonts](../images/fonts-sw.png) |\n> | Krnl | ![Krnl Fonts](../images/fonts-krnl.png) |\n</details>\n\n### Example\n\n```lua\nfor name, font in pairs(Drawing.Fonts) do\n\tlocal text = Drawing.new(\"Text\")\n\ttext.Text = \"The quick brown fox (\" .. name .. \")\"\n\ttext.Font = font\n\ttext.Size = 48\n\ttext.Position = Vector2.new(150, 100 + font * 50)\n\ttext.Visible = true\n\ttask.delay(2, function ()\n\t\ttext:Destroy()\n\tend)\nend\n```\n\n---\n\n## Drawing\n\n`🖥️ Class`\n\n```lua\ndrawing = Drawing.new(type)\n```\n\n### BaseDrawing\n\nThe base class of which all drawing objects inherit. Cannot be instantiated.\n\n| Property | Type | Description |\n| -------- | ---- | ----------- |\n| `Visible` | boolean | Whether the drawing is visible. Defaults to `false` on some executors. |\n| `ZIndex` | number | Determines the order in which a Drawing renders relative to other drawings. |\n| `Transparency` | number | The opacity of the drawing (1 is opaque, 0 is transparent). |\n| `Color` | Color3 | The color of the drawing. |\n| `Destroy(): ()` | function | Destroys the drawing. |\n\n### Line\n\nRenders a line starting at `From` and ending at `To`.\n\n| Property | Type | Description |\n| -------- | ---- | ----------- |\n| `From` | Vector2 | The starting point of the line. |\n| `To` | Vector2 | The ending point of the line. |\n| `Thickness` | number | The thickness of the line. |\n\n### Text\n\nRenders text at `Position`.\n\n| Property | Type | Description |\n| -------- | ---- | ----------- |\n| `Text` | string | The text to render. |\n| `TextBounds` | 🔒 Vector2 | The size of the text. Cannot be set. |\n| `Font` | Drawing.Font | The font to use. |\n| `Size` | number | The size of the text. |\n| `Position` | Vector2 | The position of the text. |\n| `Center` | boolean | Whether the text should be centered horizontally. |\n| `Outline` | boolean | Whether the text should be outlined. |\n| `OutlineColor` | Color3 | The color of the outline. |\n\n### Image\n\nDraws the image data to the screen. `Data` *must* be the raw image data.\n\n| Property | Type | Description |\n| -------- | ---- | ----------- |\n| `Data` | string | The raw image data. |\n| `Size` | Vector2 | The size of the image. |\n| `Position` | Vector2 | The position of the image. |\n| `Rounding` | number | The rounding of the image. |\n\n### Circle\n\nDraws a circle that is centered at `Position`.\n\nThis is not a perfect circle! The greater the value for `NumSides`, the more accurate the circle will be.\n\n| Property | Type | Description |\n| -------- | ---- | ----------- |\n| `NumSides` | number | The number of sides of the circle. |\n| `Radius` | number | The radius of the circle. |\n| `Position` | Vector2 | The position of the center of the circle. |\n| `Thickness` | number | If `Filled` is false, specifies the thickness of the outline. |\n| `Filled` | boolean | Whether the circle should be filled. |\n\n### Square\n\nDraws a rectangle starting at `Position` and ending at `Position` + `Size`.\n\n| Property | Type | Description |\n| -------- | ---- | ----------- |\n| `Size` | Vector2 | The size of the square. |\n| `Position` | Vector2 | The position of the top-left corner of the square. |\n| `Thickness` | number | If `Filled` is false, specifies the thickness of the outline. |\n| `Filled` | boolean | Whether the square should be filled. |\n\n### Quad\n\nDraws a four-sided figure connecting to each of the four points.\n\n| Property | Type | Description |\n| -------- | ---- | ----------- |\n| `PointA` | Vector2 | The first point. |\n| `PointB` | Vector2 | The second point. |\n| `PointC` | Vector2 | The third point. |\n| `PointD` | Vector2 | The fourth point. |\n| `Thickness` | number | If `Filled` is false, specifies the thickness of the outline. |\n| `Filled` | boolean | Whether the quad should be filled. |\n\n### Triangle\n\nDraws a triangle connecting to each of the three points.\n\n| Property | Type | Description |\n| -------- | ---- | ----------- |\n| `PointA` | Vector2 | The first point. |\n| `PointB` | Vector2 | The second point. |\n| `PointC` | Vector2 | The third point. |\n| `Thickness` | number | If `Filled` is false, specifies the thickness of the outline. |\n| `Filled` | boolean | Whether the triangle should be filled. |\n\n---\n\n## cleardrawcache\n\n`🌎 Global`\n\n```lua\nfunction cleardrawcache(): ()\n```\n\nDestroys every drawing object in the cache. Invalidates references to the drawing objects.\n\n### Example\n\n```lua\nfor i = 1, 10 do\n\tlocal circle = Drawing.new(\"Circle\")\n\tcircle.Radius = 50\n\tcircle.Color = Color3.fromRGB(255, 0, 0)\n\tcircle.Filled = true\n\tcircle.NumSides = 32\n\tcircle.Position = Vector2.new(math.random(300, 1200), math.random(300, 1200))\n\tcircle.Transparency = 0.7\n\tcircle.Visible = true\nend\n\ntask.wait(1)\ncleardrawcache()\n```\n\n---\n\n## getrenderproperty\n\n`🌎 Global`\n\n```lua\nfunction getrenderproperty(drawing: Drawing, property: string): any\n```\n\nGets the value of a property of a drawing. Functionally identical to `drawing[property]`.\n\n### Parameters\n\n * `drawing` - The drawing to get the property of.\n * `property` - The property to get.\n\n### Example\n\n```lua\nlocal circle = Drawing.new(\"Circle\")\ngetrenderproperty(circle, \"Color\")\n```\n\n---\n\n## isrenderobj\n\n`🌎 Global`\n\n```lua\nfunction isrenderobj(object: any): boolean\n```\n\nReturns whether the given object is a valid Drawing.\n\n### Parameters\n\n * `object` - Any object.\n\n### Example\n\n```lua\nprint(isrenderobj(Drawing.new(\"Circle\"))) --> true\nprint(isrenderobj({})) --> false\n```\n\n---\n\n## setrenderproperty\n\n`🌎 Global`\n\n```lua\nfunction setrenderproperty(drawing: Drawing, property: string, value: any): ()\n```\n\nSets the value of a property of a drawing. Functionally identical to `drawing[property] = value`.\n\n### Parameters\n\n * `drawing` - The drawing to set the property of.\n * `property` - The property to set.\n * `value` - The value to set the property to.\n\n### Example\n\n```lua\nlocal circle = Drawing.new(\"Circle\")\nsetrenderproperty(circle, \"Color\", Color3.fromRGB(255, 0, 0))\n```"
  },
  {
    "path": "api/WebSocket.md",
    "content": "# WebSocket\n\nThe **WebSocket** class provides a simple interface for sending and receiving data over a WebSocket connection.\n\n---\n\n## WebSocket.connect\n\n`🏛️ Constructor`\n\n```lua\nfunction WebSocket.connect(url: string): WebSocket\n```\n\nEstablishes a WebSocket connection to the specified URL.\n\n### Parameters\n\n * `url` - The URL to connect to.\n\n### Example\n\n```lua\nlocal ws = WebSocket.connect(\"ws://localhost:8080\")\n\nws.OnMessage:Connect(function(message)\n\tprint(message)\nend)\n\nws.OnClose:Connect(function()\n\tprint(\"Closed\")\nend)\n\nws:Send(\"Hello, World!\")\n```\n\n---\n\n## WebSocket\n\n`🖥️ Class`\n\n```lua\nws = WebSocket.connect(url)\n```\n\n### Methods\n\n| Method | Description |\n| ------ | ----------- |\n| `Send(message: string): ()` | Sends a message over the WebSocket connection. |\n| `Close(): ()` | Closes the WebSocket connection. |\n\n### Events\n\n| Event | Description |\n| ----- | ----------- |\n| `OnMessage(message: string): ()` | Fired when a message is received over the WebSocket connection. |\n| `OnClose(): ()` | Fired when the WebSocket connection is closed. |\n"
  },
  {
    "path": "api/cache.md",
    "content": "# Cache\n\nThe **cache** library provides methods for modifying the internal Instance cache.\n\nNote that some of the methods are only available as global functions. They will be tagged with `🌎 Global`.\n\n---\n\n## cache.invalidate\n\n```lua\nfunction invalidate(object: Instance): ()\n```\n\nDeletes `object` from the Instance cache. Effectively invalidates `object` as a reference to the underlying Instance.\n\n### Parameters\n\n * `object` - The object to invalidate.\n\n### Example\n\n```lua\nlocal Lighting = game:GetService(\"Lighting\")\ncache.invalidate(game:GetService(\"Lighting\"))\nprint(Lighting, Lighting == game:GetService(\"Lighting\")) --> Lighting, false\n```\n\n---\n\n## cache.iscached\n\n```lua\nfunction iscached(object: Instance): boolean\n```\n\nChecks whether `object` exists in the Instance cache.\n\n### Parameters\n\n * `object` - The object to find.\n\n### Example\n\n```lua\nlocal Lighting = game:GetService(\"Lighting\")\ncache.invalidate(Lighting)\nprint(cache.iscached(Lighting)) --> false\n```\n\n---\n\n## cache.replace\n\n```lua\nfunction replace(object: Instance, newObject: Instance): ()\n```\n\nReplaces `object` in the Instance cache with `newObject`.\n\n### Parameters\n\n * `object` - The object to replace.\n * `newObject` - The new object to replace `object` with.\n\n### Example\n\n```lua\nlocal Lighting = game:GetService(\"Lighting\")\nlocal Players = game:GetService(\"Players\")\n\ncache.replace(Lighting, Players)\n\nprint(Lighting) --> Players\n```\n\n---\n\n## cloneref\n\n`🌎 Global`\n\n```lua\nfunction cloneref(object: Instance): Instance\n```\n\nReturns a copy of the Instance reference to `object`. This is useful for managing an Instance without directly referencing it.\n\n### Parameters\n\n * `object` - The Instance to clone.\n\n### Example\n\n```lua\nlocal Lighting = game:GetService(\"Lighting\")\nlocal LightingClone = cloneref(Lighting)\n\nprint(Lighting == LightingClone) --> false\n```\n\n---\n\n## compareinstances\n\n`🌎 Global`\n\n```lua\nfunction compareinstances(a: Instance, b: Instance): boolean\n```\n\nReturns whether objects `a` and `b` both reference the same Instance.\n\n### Parameters\n\n * `a` - The first Instance to compare.\n * `b` - The second Instance to compare.\n\n### Example\n\n```lua\nlocal Lighting = game:GetService(\"Lighting\")\nlocal LightingClone = cloneref(Lighting)\n\nprint(Lighting == LightingClone) --> false\nprint(compareinstances(Lighting, LightingClone)) --> true\n```"
  },
  {
    "path": "api/closures.md",
    "content": "# Closures\n\nThe **closure** functions are used to create, identify, and interact with Luau closures.\n\n---\n\n## checkcaller\n\n```lua\nfunction checkcaller(): boolean\n```\n\nReturns whether the function currently running was called by the executor.\n\nThis is useful for metamethod hooks that behave differently when called by the game.\n\n### Example\n\nPrevent the executor from invoking `__namecall` with the global `game` object:\n\n```lua\nlocal refs = {}\n\nrefs.__namecall = hookmetamethod(game, \"__namecall\", function(...)\n\tlocal self = ...\n\tlocal isRunningOnExecutor = checkcaller()\n\n\tif isRunningOnExecutor then\n\t\t-- The executor invoked the __namecall method, so this will not affect the\n\t\t-- scripts in the game.\n\t\tif self == game then\n\t\t\terror(\"No __namecall on game allowed\")\n\t\tend\n\tend\n\n\treturn refs.__namecall(...)\nend)\n\ngame:Destroy() --> Error \"No __namecall on game allowed\"\n```\n\n---\n\n## clonefunction\n\n```lua\nclonefunction<T>(func: T): T\n```\n\nGenerates a new closure based on the bytecode of function `func`.\n\n### Parameters\n\n * `func` - The function to recreate.\n\n### Example\n\n```lua\nlocal function foo()\n\tprint(\"Hello, world!\")\nend\n\nlocal bar = clonefunction(foo)\n\nfoo() --> Hello, world!\nbar() --> Hello, world!\nprint(foo == bar) --> false\n```\n\n---\n\n## getcallingscript\n\n```lua\nfunction getcallingscript(): BaseScript\n```\n\nReturns the script responsible for the currently running function.\n\n### Example\n\nPrevent scripts in PlayerGui from invoking the `__namecall` hook:\n\n```lua\nlocal refs = {}\nlocal bannedScripts = game:GetService(\"Players\").LocalPlayer.PlayerGui\n\nrefs.__namecall = hookmetamethod(game, \"__namecall\", function(...)\n\tlocal caller = getcallingscript()\n\n\t-- Use '.' notation to call the IsDescendantOf method without invoking\n\t-- __namecall and causing a recursive loop.\n\tlocal isBanned = caller.IsDescendantOf(caller, bannedScripts)\n\n\tif isBanned then\n\t\terror(\"Not allowed to invoke __namecall\")\n\tend\n\n\treturn refs.__namecall(...)\nend)\n```\n\n---\n\n## hookfunction\n\n```lua\nfunction hookfunction<T>(func: T, hook: function): T\n```\n\nReplaces `func` with `hook` internally, where `hook` will be invoked in place of `func` when called.\n\nReturns a new function that can be used to access the original definition of `func`.\n\n> ### ⚠️ Warning\n> If `func` is a Luau function (`islclosure(func) --> true`), the upvalue count of `hook` must be less than or equal to that of `func`.\\\n> Read more about upvalues on [Lua visibility rules](http://www.lua.org/manual/5.1/manual.html#2.6).\n\n### Parameters\n\n * `func` - The function to hook.\n * `hook` - The function to redirect calls to.\n\n### Aliases\n\n * `replaceclosure`\n\n### Example\n\n```lua\nlocal function foo()\n\tprint(\"Hello, world!\")\nend\n\nlocal fooRef = hookfunction(foo, function(...)\n\tprint(\"Hooked!\")\nend)\n\nfoo() --> Hooked!\nfooRef() --> Hello, world!\n```\n\n---\n\n## iscclosure\n\n```lua\nfunction iscclosure(func: function): boolean\n```\n\nReturns whether or not `func` is a closure whose source is written in C.\n\n### Parameters\n\n * `func` - The function to check.\n\n### Example\n\n```lua\nprint(iscclosure(print)) --> true\nprint(iscclosure(function() end)) --> false\n```\n\n---\n\n## islclosure\n\n```lua\nfunction islclosure(func: function): boolean\n```\n\nReturns whether or not `func` is a closure whose source is written in Luau.\n\n### Parameters\n\n * `func` - The function to check.\n\n### Example\n\n```lua\nprint(islclosure(print)) --> false\nprint(islclosure(function() end)) --> true\n```\n\n---\n\n## isexecutorclosure\n\n```lua\nfunction isexecutorclosure(func: function): boolean\n```\n\nReturns whether or not `func` was created by the executor.\n\n### Parameters\n\n * `func` - The function to check.\n\n### Aliases\n\n * `checkclosure`\n * `isourclosure`\n\n### Example\n\n```lua\nprint(isexecutorclosure(isexecutorclosure)) --> true\nprint(isexecutorclosure(function() end)) --> true\nprint(isexecutorclosure(print)) --> false\n```\n\n---\n\n## loadstring\n\n```lua\nfunction loadstring(source: string, chunkname: string?): (function?, string?)\n```\n\nGenerates a chunk from the given source code. The environment of the returned function is the global environment.\n\nIf there are no compilation errors, the chunk is returned by itself; otherwise, it returns `nil` plus the error message.\n\n`chunkname` is used as the chunk name for error messages and debug information. When absent, it defaults to a **random string**.\n\n> ### ⛔ Danger\n> Vanilla Lua allows `source` to contain Lua bytecode, but it is a security vulnerability.\\\n> This is a feature that should not be implemented.\n\n### Parameters\n\n * `source` - The source code to compile.\n * `chunkname` - Optional name of the chunk.\n\n### Example\n\n```lua\nlocal func, err = loadstring(\"print('Hello, world!')\")\nassert(func, err)() --> Hello, world!\n\nlocal func, err = loadstring(\"print('Hello\")\nassert(func, err)() --> Errors \"Malformed string\"\n```\n\n---\n\n## newcclosure\n\n```lua\nfunction newcclosure<T>(func: T): T\n```\n\nReturns a C closure that wraps `func`. The result is functionally identical to `func`, but identifies as a C closure, and may have different metadata.\n\n> ### ⚠️ Warning\n> Attempting to yield inside a C closure will throw an error.\\\n> Instead, use the task library to defer actions to different threads.\n\n### Parameters\n\n * `func` - The function to wrap.\n\n### Example\n\n```lua\nlocal foo = function() end\nlocal bar = newcclosure(foo)\n\nprint(iscclosure(foo)) --> false\nprint(iscclosure(bar)) --> true\n```"
  },
  {
    "path": "api/console.md",
    "content": "# Console\n\nThe **console** functions are used to interact with one console window.\n\nBehavior and examples documented on this page are based on Script-Ware.\n\n---\n\n## rconsoleclear\n\n```lua\nfunction rconsoleclear(): ()\n```\n\nClears the output of the console window.\n\n### Aliases\n\n * `consoleclear`\n\n### Example\n\n```lua\n-- Create the console window\nrconsolesettitle(\"New console\")\nrconsoleprint(\"Hello, world!\")\nrconsolecreate()\n\n-- Clears the output \"Hello, world!\"\nrconsoleclear()\n```\n\n---\n\n## rconsolecreate\n\n```lua\nfunction rconsolecreate(): ()\n```\n\nOpens the console window. Text previously output to the console will not be cleared.\n\n> ### 🔎 Note\n> Some executors also allow functions like `rconsoleprint` to open the console.\\\n> This is confusing behavior that should not be relied on.\n\n### Aliases\n\n * `consolecreate`\n\n### Example\n\nCreate a program that generates a mountainous landscape:\n\n```lua\n-- Create the console window\nrconsolesettitle(\"Beautiful Mountains\")\nrconsolecreate()\n\nlocal function generate()\n\t-- Generate a random decimal number for noise\n\tlocal seed = math.random(100, 999) + math.random()\n\n\t-- Prints 25 lines of text\n\tfor i = 1, 25 do\n\t\tlocal noise = math.noise(i / 8, seed) + 0.5\n\t\tlocal height = math.floor(noise * 50)\n\t\tlocal line = string.rep(\"*\", height)\n\t\trconsoleprint(line .. \"\\n\")\n\tend\n\n\t-- Prompts the user to generate a new set of mountains\n\t-- or exit the console window\n\trconsoleprint(\"\\nEnter 'Y' to generate a new landscape, or nothing to exit\\n\")\n\n\tlocal input = rconsoleinput()\n\n\tif string.lower(input) == \"y\" then\n\t\trconsoleclear()\n\t\tgenerate()\n\telse\n\t\trconsoledestroy()\n\tend\nend\n\ngenerate()\n```\n\n---\n\n## rconsoledestroy\n\n```lua\nfunction rconsoledestroy(): ()\n```\n\nCloses the console window and clears its output. The title will not be changed.\n\n### Aliases\n\n * `consoledestroy`\n\n### Example\n\n```lua\n-- Create a console window titled \"New console\" and with the output \"Hello, world!\"\nrconsolesettitle(\"New console\")\nrconsoleprint(\"Hello, world!\")\nrconsolecreate()\n\n-- Close the console window, clearing its output\nrconsoledestroy()\n\n-- Reopen the console window titled \"New console\" with no output\nrconsolecreate()\n```\n\n---\n\n## rconsoleinput\n\n`⏰ Yields`\n\n```lua\nfunction rconsoleinput(): string\n```\n\nWaits for the user to input text into the console window. Returns the result.\n\n### Aliases\n\n * `consoleinput`\n\n### Example\n\n```lua\n-- Create the console window\nrconsolesettitle(\"Your Info\")\nrconsoleprint(\"What is your name?\\nMy name is: \")\nrconsolecreate()\n\n-- Retrieve the user's input\nlocal name = rconsoleinput()\nrconsoleprint(\"Hello, \" .. name .. \"!\")\n\n-- Cleanup\ntask.wait(1)\nrconsoledestroy()\n```\n\n---\n\n## rconsoleprint\n\n```lua\nfunction rconsoleprint(text: string): ()\n```\n\nPrints `text` to the console window. Does not clear existing text or create a new line.\n\n### Parameters\n\n* `text` - The text to append to the output.\n\n### Aliases\n\n * `consoleprint`\n\n### Example\n\n```lua\n-- Create a console window titled \"New console\" with the\n-- output \"Hello, world!! How are you today?\"\nrconsolesettitle(\"New console\")\nrconsoleprint(\"Hello, world!\")\nrconsoleprint(\"! How are you today?\")\nrconsolecreate()\n```\n\n---\n\n## rconsolesettitle\n\n```lua\nfunction rconsolesettitle(title: string): ()\n```\n\nSets the title of the console window to `title`.\n\n### Parameters\n\n * `title` - The new title.\n\n### Aliases\n\n * `rconsolename`\n * `consolesettitle`\n\n### Example\n\n```lua\n-- Create a console window titled \"My console\"\nrconsolesettitle(\"My console\")\nrconsolecreate()\n```"
  },
  {
    "path": "api/crypt.md",
    "content": "# Crypt\n\nThe **crypt** library provides methods for the encryption and decryption of string data.\n\nBehavior and examples documented on this page are based on Script-Ware.\n\n---\n\n## crypt.base64encode\n\n```lua\nfunction crypt.base64encode(data: string): string\n```\n\nEncodes a string of bytes into Base64.\n\n### Parameters\n\n * `data` - The data to encode.\n\n### Aliases\n\n * `crypt.base64.encode`\n * `crypt.base64_encode`\n * `base64.encode`\n * `base64_encode`\n\n### Example\n\n```lua\nlocal base64 = crypt.base64encode(\"Hello, World!\")\nlocal raw = crypt.base64decode(base64)\n\nprint(base64) --> SGVsbG8sIFdvcmxkIQ==\nprint(raw) --> Hello, World!\n```\n\n---\n\n## crypt.base64decode\n\n```lua\nfunction crypt.base64decode(data: string): string\n```\n\nDecodes a Base64 string to a string of bytes.\n\n### Parameters\n\n * `data` - The data to decode.\n\n### Aliases\n\n * `crypt.base64.decode`\n * `crypt.base64_decode`\n * `base64.decode`\n * `base64_decode`\n\n### Example\n\n```lua\nlocal base64 = crypt.base64encode(\"Hello, World!\")\nlocal raw = crypt.base64decode(base64)\n\nprint(base64) --> SGVsbG8sIFdvcmxkIQ==\nprint(raw) --> Hello, World!\n```\n\n---\n\n## crypt.encrypt\n\n`🪲 Compatibility` `🔎 RFC`\n\n```lua\nfunction crypt.encrypt(data: string, key: string, iv: string?, mode: string?): (string, string)\n```\n\nEncrypts an unencoded string using AES encryption. Returns the base64 encoded and encrypted string, and the IV.\n\nIf an AES IV is not provided, a random one will be generated for you, and returned as a 2nd base64 encoded string.\n\nThe cipher modes are 'CBC', 'ECB', 'CTR', 'CFB', 'OFB', and 'GCM'. The default is 'CBC'.\n\n> ### 🪲 Compatibility issues\n> Too few executors support this function and a reliable example cannot be made.\n\n### Parameters\n\n * `data` - The unencoded content.\n * `key` - A base64 256-bit key.\n * `iv` - Optional base64 AES initialization vector.\n * `mode` - The AES cipher mode.\n\n---\n\n## crypt.decrypt\n\n`🪲 Compatibility` `🔎 RFC`\n\n```lua\nfunction crypt.decrypt(data: string, key: string, iv: string, mode: string): string\n```\n\nDecrypts the base64 encoded and encrypted content. Returns the raw string.\n\nThe cipher modes are 'CBC', 'ECB', 'CTR', 'CFB', 'OFB', and 'GCM'.\n\n> ### 🪲 Compatibility issues\n> Too few executors support this function and a reliable example cannot be made.\n\n### Parameters\n\n * `data` - The base64 encoded and encrypted content.\n * `key` - A base64 256-bit key.\n * `iv` - The base64 AES initialization vector.\n * `mode` - The AES cipher mode.\n\n---\n\n## crypt.generatebytes\n\n```lua\nfunction crypt.generatebytes(size: number): string\n```\n\nGenerates a random sequence of bytes of the given size. Returns the sequence as a base64 encoded string.\n\n### Parameters\n\n * `size` - The number of bytes to generate.\n\n### Example\n\n```lua\nlocal bytes = crypt.generatebytes(16)\nprint(bytes) --> bXlzcWwgYm9vbGVhbnM=\nprint(#crypt.base64decode(bytes)) --> 16\n```\n\n---\n\n## crypt.generatekey\n\n```lua\nfunction crypt.generatekey(): string\n```\n\nGenerates a base64 encoded 256-bit key. The result can be used as the second parameter for the `crypt.encrypt` and `crypt.decrypt` functions.\n\n### Example\n\n```lua\nlocal bytes = crypt.generatekey()\nprint(#crypt.base64decode(bytes)) --> 32 (256 bits)\n```\n\n---\n\n## crypt.hash\n\n```lua\nfunction crypt.hash(data: string, algorithm: string): string\n```\n\nReturns the result of hashing the data using the given algorithm.\n\nSome algorithms include 'sha1', 'sha384', 'sha512', 'md5', 'sha256', 'sha3-224', 'sha3-256', and 'sha3-512'.\n\n### Parameters\n\n * `data` - The unencoded content.\n * `algorithm` - A hash algorithm.\n\n### Example\n\n```lua\nlocal hash = crypt.hash(\"Hello, World!\", \"md5\")\nprint(hash) --> 65A8E27D8879283831B664BD8B7F0AD4\n```"
  },
  {
    "path": "api/debug.md",
    "content": "# Debug\n\nThe **debug** library is an extension of the Luau debug library, providing greater control over Luau functions.\n\n---\n\n## debug.getconstant\n\n`⛔ Exception`\n\n```lua\nfunction debug.getconstant(func: function | number, index: number): any\n```\n\nReturns the constant at `index` in the constant table of the function or level `func`. Throws an error if the constant does not exist.\n\n### Parameters\n\n * `func` - A function or stack level.\n * `index` - The numerical index of the constant to retrieve.\n\n### Example\n\n```lua\nlocal function foo()\n\tprint(\"Hello, world!\")\nend\n\nprint(debug.getconstant(foo, 1)) --> \"print\"\nprint(debug.getconstant(foo, 2)) --> nil\nprint(debug.getconstant(foo, 3)) --> \"Hello, world!\"\n```\n\n---\n\n## debug.getconstants\n\n```lua\nfunction debug.getconstants(func: function | number): {any}\n```\n\nReturns the constant table of the function or level `func`.\n\n> ### 🔎 Tip\n> Traversing the table with `ipairs` is not recommended, as constants can be `nil` or skipped entirely.\n\n### Parameters\n\n * `func` - A function or stack level.\n\n### Example\n\n```lua\nlocal function foo()\n\tlocal num = 5000 .. 50000\n\tprint(\"Hello, world!\", num, warn)\nend\n\nfor i, v in pairs(debug.getconstants(foo)) do\n\tprint(i, v)\nend\n--> 1 50000\n--> 2 \"print\"\n--> 4 \"Hello, world!\"\n--> 5 \"warn\"\n```\n\n---\n\n## debug.getinfo\n\n`🪲 Inconsistent`\n\n```lua\nfunction debug.getinfo(func: function | number): DebugInfo\n```\n\nReturns debugger information about a function or stack level.\n\n### DebugInfo\n\n| Field | Type | Description |\n| ----- | ---- | ----------- |\n| `source` | string | The name of the chunk that created the function. |\n| `short_src` | string | A \"printable\" version of `source` to be used in error messages. |\n| `func` | function | The function itself. |\n| `what` | string | The string \"Lua\" if the function is a Luau function, or \"C\" if it is a C function. |\n| `currentline` | number | The current line where the given function is executing. When no line information is available, `currentline` is set to -1. |\n| `name` | string | The name of the function. If it cannot find a name, then `name` is a blank string. |\n| `nups` | number | The number of upvalues in the function. |\n| `numparams` | number | The number of parameters in the function (always 0 for C functions). |\n| `is_vararg` | number | Whether the function has a variadic argument (1 if it does, 0 if it does not). |\n\n> ### 🪲 Compatibility\n> Some executors are missing certain fields.\n\n### Parameters\n\n * `func` - A function or stack level.\n\n### Example\n\n```lua\nlocal function foo()\n\tprint(\"Hello, world!\")\nend\n\nfor k, v in pairs(debug.getinfo(foo)) do\n\tprint(k, v, \"(\" .. type(v) .. \")\")\nend\n```\n\n---\n\n## debug.getproto\n\n`⛔ Exception` `🛡️ Security`\n\n```lua\nfunction debug.getproto(func: function | number, index: number, active: boolean?): function | {function}\n```\n\nReturns the proto at `index` in the function or level `func` if `active` is false.\n\nIf `active` is true, then every active function of the proto is returned.\n\n> ### 🛡️ Security\n> In some executors, the proto is non-functional if `active` is false. Debug information is preserved.\\\n> To retrieve a callable function, you can set `active` to true and index the first proto.\n\n### Parameters\n\n * `func` - A function or stack level.\n * `index` - The numerical index of the proto to retrieve.\n * `active` - Whether to return its list of active closures.\n\n### Example\n\n```lua\nlocal function myFunction()\n\tlocal function proto()\n\t\tprint(\"Hello, world!\")\n\tend\nend\n\nlocal proto = debug.getproto(myFunction, 1, true)[1]\nproto() --> Hello, world!\n```\n\n---\n\n## debug.getprotos\n\n`🛡️ Security`\n\n```lua\nfunction debug.getprotos(func: function | number): {function}\n```\n\nReturns a list of protos of the function or level `func`.\n\n> ### 🛡️ Security\n> In some executors, the proto is non-functional, but debug information is preserved.\\\n> To retrieve a callable function, see [`debug.getproto`](#debuggetproto).\n\n### Parameters\n\n * `func` - A function or stack level.\n\n### Example\n\n```lua\nlocal function myFunction()\n\tlocal function _1()\n\t\tprint(\"Hello,\")\n\tend\n\tlocal function _2()\n\t\tprint(\"world!\")\n\tend\nend\n\nfor i in ipairs(debug.getprotos(myFunction)) do\n\tlocal proto = debug.getproto(myFunction, i, true)[1]\n\tproto()\nend\n--> Hello,\n--> world!\n```\n\n---\n\n## debug.getstack\n\n`⛔ Exception`\n\n```lua\nfunction debug.getstack(level: number, index: number?): any | {any}\n```\n\nReturns the value at `index` in the stack frame `level`. Throws an error if no value could be found.\n\nIf `index` is not specified, then the entire stack frame is returned.\n\n### Parameters\n\n * `level` - The stack frame to look up.\n * `index` - The numerical index of the value to retrieve.\n\n### Example\n\n```lua\nlocal _ = \"a\" .. \"b\"\nprint(debug.getstack(1, 1)) --> ab\n```\n\n```lua\nlocal _ = \"a\" .. \"b\"\ntable.foreach(debug.getstack(1), print)\n--> ab\n--> table.foreach()\n--> debug.getstack()\n--> 1\n```\n\n---\n\n## debug.getupvalue\n\n`⛔ Exception`\n\n```lua\nfunction debug.getupvalue(func: function | number, index: number): any\n```\n\nReturns the upvalue at `index` in the function or level `func`. Throws an error if the upvalue does not exist.\n\nAn upvalue is a local variable used by an inner function, and is also called an *external local variable*.\n\nRead more on [Lua visibility rules](http://www.lua.org/manual/5.1/manual.html#2.6).\n\n> ### 🔎 Note\n> Some Luau optimizations automatically inline certain constants like strings and integers.\\\n> They can be retrieved through [`debug.getconstant`](#debuggetconstant) instead.\n\n### Parameters\n\n * `func` - A function or stack level.\n * `index` - The numerical index of the upvalue to retrieve.\n\n### Example\n\n```lua\nlocal upvalue = function ()\nend\n\nlocal function foo()\n\tprint(upvalue)\nend\n\nprint(debug.getupvalue(foo, 1)) --> upvalue\n```\n\nAn example of Luau optimization:\n\n```lua\nlocal upvalue = \"Hello, world!\"\n\nlocal function foo()\n\tprint(upvalue)\nend\n\nprint(debug.getupvalue(foo, 1)) --> Errors \"upvalue index out of range\"\nprint(debug.getconstant(foo, 3)) --> Hello, world!\n```\n\n---\n\n## debug.getupvalues\n\n```lua\nfunction debug.getupvalues(func: function | number): {any}\n```\n\nReturns a list of upvalues of the function or level `func`.\n\n> ### 🔎 Tip\n> Traversing the table with `ipairs` is not recommended, as upvalues can be `nil` or skipped entirely.\n\n### Parameters\n\n * `func` - A function or stack level.\n\n### Example\n\n```lua\nlocal upvalue1, upvalue2 = function () end, function () end\n\nlocal function foo()\n\tprint(upvalue1, upvalue2)\nend\n\nfor k, v in pairs(debug.getupvalues(foo)) do\n\tprint(k, v, \"(\" .. type(v) .. \")\")\nend\n--> 1 upvalue1() (function)\n--> 2 upvalue2() (function)\n```\n\n---\n\n## debug.setconstant\n\n`⛔ Exception`\n\n```lua\nfunction debug.setconstant(func: function | number, index: number, value: any): ()\n```\n\nSets the constant at `index` in the function or level `func` to `value`.\n\n> ### ⛔ Exception\n> The type of `value` must match the type of the constant at `index`.\n\n### Parameters\n\n * `func` - A function or stack level.\n * `index` - The numerical index of the constant to set.\n * `value` - The value to set.\n\n### Example\n\n```lua\nlocal function foo()\n\tprint(\"Goodbye, world!\")\nend\n\ndebug.setconstant(foo, 3, \"Hello, world!\")\nfoo() --> Hello, world!\n```\n\n---\n\n## debug.setstack\n\n`⛔ Exception`\n\n```lua\nfunction debug.setstack(level: number, index: number, value: any): ()\n```\n\nSets the register at `index` in the stack frame `level` to `value`.\n\n> ### ⛔ Exception\n> The type of `value` must match the type of the register at `index`.\n\n### Parameters\n\n * `level` - The stack frame to look up.\n * `index` - The numerical index of the register to set.\n * `value` - The value to set.\n\n### Example\n\n```lua\nlocal function foo()\n\t-- Change the first value from \"Goodbye, world!\" to \"Hello, world!\"\n\treturn \"Goodbye, world!\", debug.setstack(1, 1, \"Hello, world!\")\nend\n\nprint(foo()) --> Hello, world!\n```\n\n---\n\n## debug.setupvalue\n\n```lua\nfunction debug.setupvalue(func: function | number, index: number, value: any): ()\n```\n\nSets the upvalue at `index` in the function or level `func` to `value`.\n\n### Parameters\n\n * `func` - A function or stack level.\n * `index` - The numerical index of the upvalue to set.\n * `value` - The value to set.\n\n### Example\n\n```lua\nlocal function somethingImportant()\n\tprint(\"Goodbye, world!\")\nend\n\nlocal function foo()\n\tsomethingImportant()\nend\n\ndebug.setupvalue(foo, 1, function ()\n\tprint(\"Hello, world!\")\nend)\n\nfoo() --> Hello, world!\n```\n"
  },
  {
    "path": "api/filesystem.md",
    "content": "# Filesystem\n\nThe **filesystem** functions allow read and write access to a designated folder in the directory of the executor, typically called *workspace*.\n\n---\n\n## readfile\n\n```lua\nfunction readfile(path: string): string\n```\n\nReturns the contents of the file located at `path`.\n\n### Parameters\n\n * `path` - The path to the file.\n\n### Example\n\n```lua\nwritefile(\"file.txt\", \"Hello, world!\")\nprint(readfile(\"file.txt\")) --> Hello, world!\n```\n\n---\n\n## listfiles\n\n```lua\nfunction listfiles(path: string): {string}\n```\n\nReturns a list of files and folders in the folder located at `path`. The returned list contains whole paths.\n\n### Parameters\n\n * `path` - The path to the folder.\n\n### Example\n\nPrints every file and folder in *workspace*.\n\n```lua\nlocal function descend(path, level)\n\tlevel = level or 0\n\tfor _, file in ipairs(listfiles(path)) do\n\t\tprint(string.rep(\"  \", level) .. file)\n\t\tif isfolder(file) then\n\t\t\tdescend(file, level + 1)\n\t\tend\n\tend\nend\n\ndescend(\".\")\n```\n\n---\n\n## writefile\n\n```lua\nfunction writefile(path: string, data: string): ()\n```\n\nWrites `data` to the file located at `path` if it is not a folder.\n\n### Parameters\n\n * `path` - A path to the file.\n * `data` - The data to write.\n\n### Example\n\n```lua\nwritefile(\"file.txt\", \"Hello, world!\")\nprint(readfile(\"file.txt\")) --> Hello, world!\n```\n\n---\n\n## makefolder\n\n```lua\nfunction makefolder(path: string): ()\n```\n\nCreates a folder at `path` if it does not already exist.\n\n### Parameters\n\n * `path` - The target location.\n\n### Example\n\n```lua\nmakefolder(\"folder\")\nwritefile(\"folder/file.txt\", \"Hello, world!\")\nprint(readfile(\"folder/file.txt\")) --> Hello, world!\n```\n\n---\n\n## appendfile\n\n```lua\nfunction appendfile(path: string, data: string): ()\n```\n\nAppends `data` to the end of the file located at `path`. Creates the file if it does not exist.\n\n### Parameters\n\n * `path` - A path to the file.\n * `data` - The data to append.\n\n### Example\n\n```lua\nwritefile(\"services.txt\", \"A list of services:\\n\")\n\nfor _, service in ipairs(game:GetChildren()) do\n\tif service.ClassName ~= \"\" then\n\t\tappendfile(\"services.txt\", service.ClassName .. \"\\n\")\n\tend\nend\n```\n\n---\n\n## isfile\n\n```lua\nfunction isfile(path: string): boolean\n```\n\nReturns whether or not `path` points to a file.\n\n### Parameters\n\n * `path` - The path to check.\n\n### Example\n\n```lua\nwritefile(\"file.txt\", \"Hello, world!\")\nprint(isfile(\"file.txt\")) --> true\n```\n\n---\n\n## isfolder\n\n```lua\nfunction isfolder(path: string): boolean\n```\n\nReturns whether or not `path` points to a folder.\n\n### Parameters\n\n * `path` - The path to check.\n\n### Example\n\n```lua\nmakefolder(\"folder\")\nprint(isfolder(\"folder\")) --> true\n```\n\n---\n\n## delfile\n\n```lua\nfunction delfile(path: string): ()\n```\n\nRemoves the file located at `path`.\n\n### Parameters\n\n * `path` - The path to the file.\n\n### Example\n\n```lua\nwritefile(\"file.txt\", \"Hello, world!\")\nprint(isfile(\"file.txt\")) --> true\n\ndelfile(\"file.txt\")\nprint(isfile(\"file.txt\")) --> false\n```\n\n---\n\n## delfolder\n\n```lua\nfunction delfolder(path: string): ()\n```\n\nRemoves the folder located at `path`.\n\n### Parameters\n\n * `path` - The path to the folder.\n\n### Example\n\n```lua\nmakefolder(\"folder\")\nprint(isfolder(\"folder\")) --> true\n\ndelfolder(\"folder\")\nprint(isfolder(\"folder\")) --> false\n```\n\n---\n\n## loadfile\n\n```lua\nfunction loadfile(path: string, chunkname: string?): (function?, string?)\n```\n\nGenerates a chunk from the file located at `path`. The environment of the returned function is the global environment.\n\nIf there are no compilation errors, the chunk is returned by itself; otherwise, it returns `nil` plus the error message.\n\n`chunkname` is used as the chunk name for error messages and debug information. When absent, it defaults to a **random string**.\n\n### Parameters\n\n * `path` - A path to the file containing Luau code.\n * `chunkname` - Optional name of the chunk.\n\n### Example\n\n```lua\nwritefile(\"file.lua\", \"local number = ...; return number + 1\")\nlocal func, err = loadfile(\"file.lua\")\nlocal output = assert(func, err)(1)\nprint(output) --> 2\n```\n\n---\n\n## dofile\n\n```lua\nfunction dofile(path: string): ()\n```\n\nAttempts to load the file located at `path` and execute it on a new thread.\n\n> ### 🔎 Note\n> Some executors may provide the file name to the top-level vararg of the file (`...`).\n\n### Parameters\n\n * `path` - The path to the file.\n\n### Example\n\n```lua\nwritefile(\"code.lua\", \"print('Hello, world!')\")\ndofile(\"code.lua\") --> \"Hello, world!\"\n```\n"
  },
  {
    "path": "api/input.md",
    "content": "# Input\n\nThe **input** functions allow you to dispatch inputs on behalf of the user.\n\n---\n\n## isrbxactive\n\n```lua\nfunction isrbxactive(): boolean\n```\n\nReturns whether the game's window is in focus. Must be true for other input functions to work.\n\n### Aliases\n\n * `isgameactive`\n\n### Example\n\n```lua\nif isrbxactive() then\n\tmouse1click()\nend\n```\n\n---\n\n## mouse1click\n\n```lua\nfunction mouse1click(): ()\n```\n\nDispatches a left mouse button click.\n\n---\n\n## mouse1press\n\n```lua\nfunction mouse1press(): ()\n```\n\nDispatches a left mouse button press.\n\n---\n\n## mouse1release\n\n```lua\nfunction mouse1release(): ()\n```\n\nDispatches a left mouse button release.\n\n---\n\n## mouse2click\n\n```lua\nfunction mouse2click(): ()\n```\n\nDispatches a right mouse button click.\n\n---\n\n## mouse2press\n\n```lua\nfunction mouse2press(): ()\n```\n\nDispatches a right mouse button press.\n\n---\n\n## mouse2release\n\n```lua\nfunction mouse2release(): ()\n```\n\nDispatches a right mouse button release.\n\n---\n\n## mousemoveabs\n\n```lua\nfunction mousemoveabs(x: number, y: number): ()\n```\n\nMoves the mouse cursor to the specified absolute position.\n\n### Parameters\n\n * `x` - The x-coordinate of the mouse cursor.\n * `y` - The y-coordinate of the mouse cursor.\n\n### Example\n\nMove the cursor in a circle around the screen:\n\n```lua\n-- Wait for the game window to be selected\nwhile not isrbxactive() do\n\ttask.wait()\nend\n\nlocal size = workspace.CurrentCamera.ViewportSize\n\t\nfor i = 0, 50 do\n\tlocal x = math.sin(i / 50 * math.pi * 2) / 2 + 0.5\n\tlocal y = math.cos(i / 50 * math.pi * 2) / 2 + 0.5\n\tmousemoveabs(x * size.X, y * size.Y)\n\ttask.wait(0.05)\nend\n```\n\n---\n\n## mousemoverel\n\n```lua\nfunction mousemoverel(x: number, y: number): ()\n```\n\nAdjusts the mouse cursor by the specified relative amount.\n\n### Parameters\n\n * `x` - The x-offset of the mouse cursor.\n * `y` - The y-offset of the mouse cursor.\n\n### Example\n\nMoves the cursor in a small circle:\n\n```lua\n-- Wait for the game window to be selected\nwhile not isrbxactive() do\n\ttask.wait()\nend\n\nfor i = 0, 20 do\n\tlocal x = math.sin(i / 20 * math.pi * 2)\n\tlocal y = math.cos(i / 20 * math.pi * 2)\n\tmousemoverel(x * 100, y * 100)\n\ttask.wait(0.05)\nend\n```\n\n---\n\n## mousescroll\n\n```lua\nfunction mousescroll(pixels: number): ()\n```\n\nDispatches a mouse scroll by the specified number of pixels.\n\n### Parameters\n\n * `pixels` - The number of pixels to scroll."
  },
  {
    "path": "api/instances.md",
    "content": "# Instances\n\nThe **Instance** functions are used to interact with game objects and their properties.\n\n---\n\n## fireclickdetector\n\n```lua\nfunction fireclickdetector(object: ClickDetector, distance: number?, event: string?): ()\n```\n\nDispatches a click or hover event to the given ClickDetector. When absent, `distance` defaults to zero, and `event` defaults to \"MouseClick\".\n\nPossible input events include 'MouseClick', 'RightMouseClick', 'MouseHoverEnter', and 'MouseHoverLeave'.\n\n### Parameters\n\n * `object` - The ClickDetector to dispatch to.\n * `distance` - Optional distance to the object.\n * `event` - Optional event to fire.\n\n### Example\n\n```lua\nlocal clickDetector = workspace.Door.Button.ClickDetector\nfireclickdetector(clickDetector, 10 + math.random(), \"MouseClick\")\n```\n\n---\n\n## getcallbackvalue\n\n```lua\nfunction getcallbackvalue(object: Instance, property: string): function?\n```\n\nReturns the function assigned to a callback property of `object`, which cannot be indexed normally.\n\n### Parameters\n\n * `object` - The object to get the callback property from.\n * `property` - The name of the callback property.\n\n### Example\n\n```lua\nlocal bindable = Instance.new(\"BindableFunction\")\n\nfunction bindable.OnInvoke()\n\tprint(\"Hello, world!\")\nend\n\nprint(getcallbackvalue(bindable, \"OnInvoke\")) --> function()\nprint(bindable.OnInvoke) --> Throws an error\n```\n\n---\n\n## getconnections\n\n```lua\nfunction getconnections(signal: RBXScriptSignal): {Connection}\n```\n\nCreates a list of Connection objects for the functions connected to `signal`.\n\n### Connection\n\n| Field | Type | Description |\n| ----- | ---- | ----------- |\n| `Enabled` | boolean | Whether the connection can receive events. |\n| `ForeignState` | boolean | Whether the function was connected by a foreign Luau state (i.e. CoreScripts). |\n| `LuaConnection` | boolean | Whether the connection was created in Luau code. |\n| `Function` | function? | The function bound to this connection. Nil when `ForeignState` is true. |\n| `Thread` | thread? | The thread that created the connection. Nil when `ForeignState` is true. |\n\n| Method | Description |\n| ----- | ----------- |\n| `Fire(...: any): ()` | Fires this connection with the provided arguments. |\n| `Defer(...: any): ()` | [Defers](https://devforum.roblox.com/t/beta-deferred-lua-event-handling/1240569) an event to connection with the provided arguments. |\n| `Disconnect(): ()` | Disconnects the connection. |\n| `Disable(): ()` | Prevents the connection from firing. |\n| `Enable(): ()` | Allows the connection to fire if it was previously disabled. |\n\n### Parameters\n\n * `signal` - The signal to retrieve connections from.\n\n### Example\n\n```lua\nlocal connections = getconnections(game.DescendantAdded)\n\nfor _, connection in ipairs(connections) do\n\tconnection:Disable()\nend\n```\n\n---\n\n## getcustomasset\n\n```lua\nfunction getcustomasset(path: string, noCache: boolean): string\n```\n\nReturns a `rbxasset://` content id for the asset located at `path`, allowing you to use unmoderated assets. Internally, files are copied to the game's content directory.\n\nIf `noCache` is false, the file will be cached, allowing subsequent calls to `getcustomasset` to return the same content id.\n\n### Parameters\n\n * `path` - The path to the asset.\n * `noCache` - Whether or not to cache the asset.\n\n### Example\n\n```lua\nlocal image = Instance.new(\"ImageLabel\")\nimage.Image = getcustomasset(\"image.png\")\nprint(image.Image) --> rbxasset://nTYyO6iSF3mND4FJ/image.png\n```\n\n---\n\n## gethiddenproperty\n\n```lua\nfunction gethiddenproperty(object: Instance, property: string): (any, boolean)\n```\n\nReturns the value of a hidden property of `object`, which cannot be indexed normally.\n\nIf the property is hidden, the second return value will be `true`. Otherwise, it will be `false`.\n\n### Parameters\n\n * `object` - The object to index.\n * `property` - The name of the hidden property.\n\n### Example\n\n```lua\nlocal fire = Instance.new(\"Fire\")\nprint(gethiddenproperty(fire, \"size_xml\")) --> 5, true\nprint(gethiddenproperty(fire, \"Size\")) --> 5, false\n```\n\n---\n\n## gethui\n\n```lua\nfunction gethui(): Folder\n```\n\nReturns a hidden GUI container. Should be used as an alternative to CoreGui and PlayerGui.\n\nGUI objects parented to this container will be protected from common detection methods.\n\n### Example\n\n```lua\nlocal gui = game:GetObjects(\"rbxassetid://1234\")[1]\ngui.Parent = gethui()\n```\n\n---\n\n## getinstances\n\n```lua\nfunction getinstances(): {Instance}\n```\n\nReturns a list of every Instance referenced on the client.\n\n### Example\n\n```lua\nlocal objects = getinstances()\n\nlocal gameCount = 0\nlocal miscCount = 0\n\nfor _, object in ipairs(objects) do\n\tif object:IsDescendantOf(game) then\n\t\tgameCount += 1\n\telse\n\t\tmiscCount += 1\n\tend\nend\n\nprint(gameCount) --> The number of objects in the `game` hierarchy.\nprint(miscCount) --> The number of objects outside of the `game` hierarchy.\n```\n\n---\n\n## getnilinstances\n\n```lua\nfunction getnilinstances(): {Instance}\n```\n\nLike `getinstances`, but only includes Instances that are not descendants of a service provider.\n\n### Example\n\n```lua\nlocal objects = getnilinstances()\n\nfor _, object in ipairs(objects) do\n\tif object:IsA(\"LocalScript\") then\n\t\tprint(object, \"is a LocalScript\")\n\tend\nend\n```\n\n---\n\n## isscriptable\n\n`🪲 Compatibility`\n\n```lua\nfunction isscriptable(object: Instance, property: string): boolean\n```\n\nReturns whether the given property is scriptable (does not have the `notscriptable` tag).\n\nIf `true`, the property is scriptable and can be indexed normally. If `nil`, the property does not exist.\n\n> ### 🪲 Known Issues\n> This appears to be backwards on Script-Ware. An example will not be provided until behavior is consistent.\n\n### Parameters\n\n * `object` - The object to index.\n * `property` - The name of the property.\n\n---\n\n## sethiddenproperty\n\n```lua\nfunction sethiddenproperty(object: Instance, property: string, value: any): boolean\n```\n\nSets the value of a hidden property of `object`, which cannot be set normally. Returns whether the property was hidden.\n\n### Parameters\n\n * `object` - The object to index.\n * `property` - The name of the hidden property.\n * `value` - The value to set.\n\n### Example\n\n```lua\nlocal fire = Instance.new(\"Fire\")\nprint(sethiddenproperty(fire, \"Size\", 5)) --> false (not hidden)\nprint(sethiddenproperty(fire, \"size_xml\", 15)) --> true (hidden)\nprint(gethiddenproperty(fire, \"size_xml\")) --> 15, true (hidden)\n```\n\n---\n\n## setrbxclipboard\n\n```lua\nfunction setrbxclipboard(data: string): boolean\n```\n\nSets the Studio client's clipboard to the given `rbxm` or `rbxmx` model data. This allows data from the game to be copied into a Studio client.\n\n### Parameters\n\n * `data` - The model data to copy to the clipboard.\n\n### Example\n\n```lua\nlocal data = readfile(\"model.rbxm\")\nsetrbxclipboard(data) -- Can be pasted into Studio\n```\n\n---\n\n## setscriptable\n\n`🪲 Compatibility`\n\n```lua\nfunction setscriptable(object: Instance, property: string, value: boolean): boolean\n```\n\nSet whether the given property is scriptable. Returns whether the property was scriptable prior to changing it.\n\n> ### 🪲 Known Issues\n> This appears to be backwards on Script-Ware. An example will not be provided until behavior is consistent.\n\n### Parameters\n\n * `object` - The object to index.\n * `property` - The name of the property.\n * `value` - Whether the property should be scriptable."
  },
  {
    "path": "api/metatable.md",
    "content": "# Metatable\n\nThe **metatable** functions allow elevated access to locked metatables.\n\n---\n\n## getrawmetatable\n\n```lua\nfunction getrawmetatable(object: table): table\n```\n\nReturns the metatable of `object`, where the `__metatable` field would normally lock the metatable.\n\n### Parameters\n\n * `object` - An object with a metatable.\n\n### Example\n\n```lua\nlocal object = setmetatable({}, { __metatable = \"Locked!\" })\nprint(getmetatable(object)) --> Locked!\nprint(getrawmetatable(object)) --> table\n```\n\n---\n\n## hookmetamethod\n\n```lua\nfunction hookmetamethod(object: table, method: string, hook: function): function\n```\n\nReplaces `func` with `hook` internally, where `hook` will be invoked in place of `func` when called.\n\nReturns a new function that can be used to access the original definition of `func`.\n\n> ### ⚠️ Not yieldable\n> The function `hook` is **not** allowed to yield or block the thread.\n\n> ### ⚠️ Recursion\n> Try not to invoke `method` from within the function `hook`!\\\n> For example, do not index a property of an Instance from within a hook to `__index`.\n\n### Parameters\n\n * `object` - An object with a metatable.\n * `method` - The name of the method to hook.\n * `hook` - The function to replace `func` with.\n\n### Example\n\nPrevent scripts in PlayerGui from invoking the `__namecall` hook:\n\n```lua\nlocal refs = {}\nlocal bannedScripts = game:GetService(\"Players\").LocalPlayer.PlayerGui\n\nrefs.__namecall = hookmetamethod(game, \"__namecall\", function(...)\n\tlocal caller = getcallingscript()\n\n\t-- Use '.' notation to call the IsDescendantOf method without invoking\n\t-- __namecall and causing a recursive loop.\n\tlocal isBanned = caller.IsDescendantOf(caller, bannedScripts)\n\n\tif isBanned then\n\t\terror(\"Not allowed to invoke __namecall\")\n\tend\n\n\treturn refs.__namecall(...)\nend)\n```\n\n---\n\n## getnamecallmethod\n\n```lua\nfunction getnamecallmethod(): string\n```\n\nReturns the name of the method that invoked the `__namecall` metamethod.\n\n### Example\n\nBans the use of `game:service()`:\n\n```lua\nlocal refs = {}\n\nrefs.__namecall = hookmetamethod(game, \"__namecall\", function(...)\n\tlocal self = ...\n\tlocal method = getnamecallmethod()\n\n\tif self == game and method == \"service\" then\n\t\terror(\"Not allowed to run game:service()\")\n\tend\n\n\treturn refs.__namecall(...)\nend)\n```\n\n---\n\n## isreadonly\n\n```lua\nfunction isreadonly(object: table): boolean\n```\n\nReturns whether `object` is frozen or read-only. Identical to `table.isfrozen`.\n\n### Parameters\n\n * `object` - A table or userdata.\n\n### Example\n\n```lua\nlocal object = {}\ntable.freeze(object)\nprint(isreadonly(object)) --> true\n```\n\n---\n\n## setrawmetatable\n\n```lua\nfunction setrawmetatable(object: table, metatable: table): ()\n```\n\nSets the metatable of `object` to `metatable`, where the `__metatable` field would normally lock the metatable.\n\n### Parameters\n\n * `object` - A table or userdata.\n * `metatable` - The metatable to set.\n\n### Example\n\n```lua\nlocal object = setmetatable({}, {})\nprint(getmetatable(object)) --> table\nsetrawmetatable(object, { __metatable = \"Hello, world!\" })\nprint(getmetatable(object)) --> Hello, world!\n```\n\n---\n\n## setreadonly\n\n```lua\nfunction setreadonly(object: table, readonly: boolean): ()\n```\n\nSets whether `object` is frozen or read-only.\n\n### Parameters\n\n * `object` - A table or userdata.\n * `readonly` - Whether or not `object` should be frozen.\n\n### Example\n\n```lua\nlocal object = {}\n\ntable.freeze(object)\nprint(isreadonly(object)) --> true\n\nsetreadonly(object, false)\nprint(isreadonly(object)) --> false\n```"
  },
  {
    "path": "api/misc.md",
    "content": "# Miscellaneous\n\nThe **miscellaneous** functions are a temporary collection of functions that are not yet categorized.\n\n---\n\n## identifyexecutor\n\n```lua\nfunction identifyexecutor(): (string, string)\n```\n\nReturns the name and version of the current executor.\n\n### Aliases\n\n * `getexecutorname`\n\n---\n\n## lz4compress\n\n```lua\nfunction lz4compress(data: string): string\n```\n\nCompresses `data` using LZ4 compression.\n\n### Parameters\n\n * `data` - The uncompressed data.\n\n### Example\n\n```lua\nlocal text = \"Hello, world! Hello, world! Goodbye, world!\"\nprint(#text) --> 43\nprint(#lz4compress(text)) --> 34\n```\n\n---\n\n## lz4decompress\n\n```lua\nfunction lz4decompress(data: string, size: number): string\n```\n\nDecompresses `data` using LZ4 compression, with the decompressed size specified by `size`.\n\n### Parameters\n\n * `data` - The compressed data.\n * `size` - The size of the decompressed data.\n\n### Example\n\n```lua\nlocal text = \"Hello, world! Hello, world!\"\nlocal compressed = lz4compress(text)\nprint(lz4decompress(compressed, #text)) --> \"Hello, world! Hello, world!\"\n```\n\n---\n\n## messagebox\n\n`⏰ Yields`\n\n```lua\nfunction messagebox(text: string, caption: string, flags: number): number\n```\n\nCreates a message box with the specified text, caption, and flags. Yields until the message box is closed, and returns the user input code.\n\nDocumentation regarding the flags and return codes can be found [here](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox).\n\n### Parameters\n\n * `text` - The text to display in the message box.\n * `caption` - The caption of the message box.\n * `flags` - The flags to use.\n\n### Example\n\nPrompts the user with a message box with three options and a warning icon:\n\n```lua\nlocal MB_ICONWARNING = 0x00000030\nlocal MB_CANCELTRYCONTINUE = 0x00000006\nlocal MB_DEFBUTTON2 = 0x00000100\n\nlocal IDCANCEL = 0x00000002\nlocal IDTRYAGAIN = 0x00000004\nlocal IDCONTINUE = 0x00000005\n\nlocal input = messagebox(\n\t\"Resource not available\\nDo you want to try again?\",\n\t\"Resource not found\",\n\tbit32.bor(MB_ICONWARNING, MB_CANCELTRYCONTINUE, MB_DEFBUTTON2)\n)\n\nif input == IDCANCEL then\n\tprint(\"Canceled\")\nelseif input == IDTRYAGAIN then\n\tprint(\"Try again\")\nelseif input == IDCONTINUE then\n\tprint(\"Continue\")\nend\n```\n\n---\n\n## queue_on_teleport\n\n```lua\nfunction queue_on_teleport(code: string): ()\n```\n\nQueues the specified script to be executed after the player teleports to a different place.\n\n### Parameters\n\n * `code` - The script to execute.\n\n### Aliases\n\n * `queueonteleport` - Will supercede this function in the future.\n\n### Example\n\n```lua\nlocal source = game:GetObjects(\"rbxassetid://1234\")[1].Source\nqueue_on_teleport(source)\nloadstring(source)()\n```\n\n---\n\n## request\n\n`⏰ Yields`\n\n```lua\nfunction request(options: HttpRequest): HttpResponse\n```\n\nSends an HTTP request using the specified options. Yields until the request is complete, and returns the response.\n\n### Request\n\n| Field | Type | Description |\n| ----- | ---- | ----------- |\n| `Url` | string | The URL for the request. |\n| `Method` | string | The HTTP method to use. Can be `GET`, `POST`, `PATCH`, or `PUT`. |\n| `Body` | string? | The body of the request. |\n| `Headers` | table? | A table of headers. |\n| `Cookies` | table? | A table of cookies. |\n\n### Response\n\n| Field | Type | Description |\n| ----- | ---- | ----------- |\n| `Body` | string | The body of the response. |\n| `StatusCode` | number | The number status code of the response. |\n| `StatusMessage` | string | The status message of the response. |\n| `Success` | boolean | Whether or not the request was successful. |\n| `Headers` | table | A dictionary of headers. |\n\n### Headers\n\nThe executor provides the following headers for identification on a web server:\n\n| Header | Description |\n| ------ | ----------- |\n| `PREFIX-User-Identifier` | A string unique to each user, and does not change if the script executor is used across computers. |\n| `PREFIX-Fingerprint` | The hardware identifier of the user. |\n| `User-Agent` | The name and version of the executor. |\n\n### Parameters\n\n * `options` - The options to use.\n\n### Aliases\n\n * `http.request`\n * `http_request`\n\n### Example\n\n```lua\nlocal response = request({\n\tUrl = \"http://example.com/\",\n\tMethod = \"GET\",\n})\n\nprint(response.StatusCode .. \" - \" .. response.StatusMessage) --> 200 - HTTP/1.1 200 OK\n```\n\n---\n\n## setclipboard\n\n```lua\nfunction setclipboard(text: string): ()\n```\n\nCopies `text` to the clipboard.\n\n### Parameters\n\n * `text` - The text to copy.\n\n### Aliases\n\n * `toclipboard`\n\n### Example\n\n```lua\nlocal character = game:GetService(\"Players\").LocalPlayer.Character\nlocal components = table.pack(character.PrimaryPart.CFrame:GetComponents())\nsetclipboard(\"CFrame.new(\" .. table.concat(components, \", \") .. \")\")\n```\n\n---\n\n## setfpscap\n\n```lua\nfunction setfpscap(fps: number): ()\n```\n\nSets the in-game FPS cap to `fps`. If `fps` is 0, the FPS cap is disabled.\n\n### Parameters\n\n * `fps` - The FPS cap.\n\n### Example\n\n```lua\nsetfpscap(0) -- Unlocks the FPS cap\n```"
  },
  {
    "path": "api/scripts.md",
    "content": "# Scripts\n\nThe **script** functions provide access to script environments and internal state.\n\n---\n\n## getgc\n\n```lua\nfunction getgc(includeTables: boolean?): {function | userdata | table}\n```\n\nReturns a list of objects in the Luau garbage collector.\n\nIf `includeTables` is false, tables will not be included in the list.\n\n### Parameters\n\n * `includeTables` - Whether or not to include tables in the list.\n\n### Example\n\n**TODO** - Write a real-world example use case.\n\n---\n\n## getgenv\n\n```lua\nfunction getgenv(): { [string]: any }\n```\n\nReturns the custom global environment of the executor. It can be used to add global functions or share variables between scripts.\n\n### Example\n\nPrevent a script from being run twice:\n\n```lua\nif getgenv().__IS_LOADED then\n\terror(\"This script is already loaded!\")\nend\n\ngetgenv().__IS_LOADED = true\n```\n\n---\n\n## getloadedmodules\n\n```lua\nfunction getloadedmodules(excludeCore: boolean?): {ModuleScript}\n```\n\nReturns a list of ModuleScripts that have been loaded. If `excludeCore` is true, CoreScript-related modules will not be included in the list.\n\n### Parameters\n\n * `excludeCore` - Whether or not to exclude core modules from the list.\n\n### Example\n\n```lua\nlocal modules = getloadedmodules(true)\n\nfor _, module in ipairs(modules) do\n\tprint(module:GetFullName())\nend\n```\n\n---\n\n## getrenv\n\n```lua\nfunction getrenv(): { [string]: any }\n```\n\nReturns the global environment of the game client. It can be used to access the global functions that LocalScripts and ModuleScripts use.\n\n### Example\n\nPrevent scripts in PlayerScripts from being required:\n\n```lua\nlocal refs = {}\nlocal bannedScripts = game:GetService(\"Players\").LocalPlayer.PlayerScripts\n\nrefs.require = hookfunction(require, function(...)\n\tlocal module = ...\n\tif\n\t\ttypeof(module) == \"Instance\"\n\t\tand module:IsA(\"ModuleScript\")\n\t\tand module:IsDescendantOf(bannedScripts)\n\tthen\n\t\terror(\"You are not allowed to require this module!\")\n\tend\n\treturn refs.require(...)\nend)\n```\n\n---\n\n## getrunningscripts\n\n```lua\nfunction getrunningscripts(): {LocalScript | ModuleScript}\n```\n\nReturns a list of scripts that are currently running.\n\n### Example\n\n```lua\nlocal scripts = getrunningscripts()\n\nfor _, object in ipairs(scripts) do\n\tprint(object:GetFullName(), \"(\" .. object.ClassName .. \")\")\nend\n```\n\n---\n\n## getscriptbytecode\n\n```lua\nfunction getscriptbytecode(script: LocalScript | ModuleScript): string\n```\n\nReturns the raw Luau bytecode of the given script.\n\n### Parameters\n\n * `script` - A client-running LocalScript or ModuleScript.\n\n### Aliases\n\n * `dumpstring`\n\n### Example\n\n```lua\nlocal animate = game:GetService(\"Players\").LocalPlayer.Character.Animate\nlocal bytecode = getscriptbytecode(animate)\n```\n\n---\n\n## getscriptclosure\n\n```lua\nfunction getscriptclosure(script: LocalScript | ModuleScript): function\n```\n\nGenerates a new closure using the bytecode of `script`.\n\n### Parameters\n\n * `script` - The script to recreate.\n\n### Aliases\n\n * `getscriptfunction`\n\n### Example\n\nCompare the return value of a ModuleScript:\n\n```lua\nlocal module = game:GetService(\"CoreGui\").RobloxGui.Modules.Common.Constants\n\nlocal constants = getrenv().require(module)\nlocal generatedConstants = getscriptclosure(module)()\n\nprint(constants == generatedConstants) --> false\nfor k, v in pairs(constants) do\n\tprint(k, typeof(v) == typeof(generatedConstants[k])) --> true\nend\n```\n\n---\n\n## getscripthash\n\n```lua\nfunction getscripthash(script: LocalScript | ModuleScript): string\n```\n\nReturns a SHA384 hash of the script's bytecode. This is useful for detecting changes to a script's source code.\n\n### Parameters\n\n * `script` - A client-running LocalScript or ModuleScript.\n\n### Example\n\n```lua\nlocal animate = game:GetService(\"Players\").LocalPlayer.Character.Animate\nlocal hash = getscripthash(animate)\n\ntask.delay(1.5, function ()\n\tanimate.Source = \"print('Hello World!')\"\nend)\n\nfor i = 1, 5 do\n\ttask.wait(0.5)\n\n\tlocal newHash = getscripthash(animate)\n\n\tif hash ~= newHash then\n\t\tprint(\"The script has changed!\")\n\t\thash = newHash\n\telse\n\t\tprint(\"The script has not changed.\")\n\tend\nend\n```\n\n---\n\n## getscripts\n\n```lua\nfunction getscripts(): {LocalScript | ModuleScript}\n```\n\nReturns a list of every script in the game.\n\n### Example\n\n```lua\nlocal scripts = getscripts()\n\nfor _, object in ipairs(scripts) do\n\tprint(object:GetFullName(), \"(\" .. object.ClassName .. \")\")\nend\n```\n\n---\n\n## getsenv\n\n```lua\nfunction getsenv(script: LocalScript | ModuleScript): { [string]: any }\n```\n\nReturns the global environment of the given script. It can be used to access variables and functions that are not defined as local. \n\n### Parameters\n\n * `script` - A client-running LocalScript or ModuleScript.\n\n### Example\n\n```lua\nlocal animate = game:GetService(\"Players\").LocalPlayer.Character.Animate\nlocal environment = getsenv(animate)\n\nfor k, v in pairs(environment) do\n\tprint(k, v, \"(\" .. typeof(v) .. \")\")\nend\n```\n\n---\n\n## getthreadidentity\n\n```lua\nfunction getthreadidentity(): number\n```\n\nReturns the identity of the current thread.\n\nLearn more about thread identities [here](https://roblox.fandom.com/wiki/Security_context).\n\n### Aliases\n\n * `getidentity`\n * `getthreadcontext`\n\n### Example\n\n```lua\nlocal identity = getthreadidentity()\nprint(identity) --> 7\n```\n\n---\n\n## setthreadidentity\n\n```lua\nfunction setthreadidentity(identity: number): ()\n```\n\nSets the current thread identity.\n\nLearn more about thread identities [here](https://roblox.fandom.com/wiki/Security_context).\n\n### Aliases\n\n * `setidentity`\n * `setthreadcontext`\n\n### Example\n\n```lua\nsetthreadidentity(3)\nprint(getthreadidentity()) --> 3\n```"
  }
]