Claude Skill

roblox-luau-core

Use for Luau language semantics, tables, control flow, string patterns, scope, closures, and cross-language translation errors.

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download tabooharmony-roblox-brain-skills_core_roblox-luau-core-6051c35.zip · 11 KB
Part of tabooharmony/roblox-brain — 29 skills

Install

skills CLI npx skills add https://github.com/TabooHarmony/roblox-brain/tree/main/skills/core/roblox-luau-core
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install tabooharmony-roblox-brain@llmmart
Git git clone https://github.com/TabooHarmony/roblox-brain.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole tabooharmony/roblox-brain collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Luau Core Language

When to Load

Load for pure Luau syntax and semantics: truthiness, tables, iteration, functions, scope, operators, string patterns, and ports from JavaScript or Python. Use roblox-luau-types for type annotations, roblox-luau-patterns for ownership and lifecycle, and domain skills for Roblox APIs.

Quick Reference

  • Only false and nil are falsy. 0, "", and {} are truthy.
  • Equality does not coerce types. 0 == "0" is false. Inequality is ~=.
  • Array conventions are 1-based. #array is meaningful only for a sequence without nil gaps.
  • Assigning nil removes a table key. Assigning a table copies the reference. table.clone is shallow.
  • Dictionary iteration order is unspecified. Do not make behavior depend on it.
  • Dynamic keys require brackets: record[field]. Dot syntax uses a literal identifier.
  • Missing arguments become nil; extra results and arguments can be discarded by context.
  • Prefer an if expression over condition and a or b when a may be false or nil.
  • Local names are scoped from their declaration onward. Forward-declare mutually recursive functions.
  • Luau string patterns are not regular expressions. Their syntax and capabilities differ.
  • Backtick interpolation and .. concatenation are both valid. Choose the clearer form; collect many fragments and join once in a hot loop.
  • NaN does not equal itself and defeats </> comparisons; test with x ~= x.
  • Binary data uses the buffer library: fixed size, 0-based offsets, explicit-width reads/writes. Avoid buffer.readinteger/writeinteger (stubs only, not released runtime).
  • For Base64, hashing, or compression use EncodingService (buffers, not strings; JSON still via HttpService). Details: see full reference.
local label = if enabled then "On" else "Off"
local message = `{name}: {score}`

local byId: {[number]: string} = {}
byId[userId] = name

for index, value in values do
    print(index, value)
end

Translation traps

  • JavaScript ===, !==, null, optional chaining, spread, arrow functions, and array methods are not Luau syntax.
  • Python None, zero-based list assumptions, list comprehensions, exceptions, and implicit tuple behavior do not translate directly.
  • x or fallback tests truthiness, not only absence. It replaces a valid false value.
  • typeof(value) recognizes Roblox datatypes; type(value) reports the underlying Luau type category.

Review

Valid Luau, no nil gaps in sequences, no assumed dictionary order, no accidental aliases, no cross-language syntax, no boolean expressions hiding false or nil.

Detailed language traps and translation examples: references/full.md

Files (roblox-brain)
  • references
    • full.md 23.6 KB
      # Luau Core Language: Full Reference
      
      This reference covers the language plus the Roblox-facing facts agents need most often: engine deprecations, sandbox deltas from Lua 5.1, the native codegen directives, and Roblox naming conventions. Deeper engine behavior belongs in the domain skills.
      
      ## 1. Values, truthiness, and equality
      
      Only `false` and `nil` are falsy. Zero, empty strings, and empty tables are truthy.
      
      ```luau
      if 0 then
          print("runs")
      end
      
      print(0 == "0") -- false
      print(1 == true) -- false
      ```
      
      Equality does not coerce between numbers, strings, and booleans. Inequality is `~=`. Use explicit empty or zero checks when those values are invalid.
      
      The common fallback expression `value or defaultValue` replaces both `nil` and `false`. If `false` is valid, test for `nil` explicitly.
      
      ```luau
      local result = if value == nil then defaultValue else value
      ```
      
      Prefer Luau's `if` expression when the true branch could be `false` or `nil`. The older `condition and trueValue or falseValue` idiom cannot preserve a falsy true value.
      
      ## 2. Tables are several shapes, not one promise
      
      A table can represent a sequence, dictionary, record, set, object, or module. Choose one shape intentionally.
      
      ```luau
      local sequence = { "first", "second" }
      local record = { name = "Ada", score = 10 }
      local dictionary: {[number]: string} = {}
      dictionary[userId] = "Ada"
      local set: {[string]: boolean} = { admin = true }
      ```
      
      Array conventions are 1-based. The length operator is useful for a contiguous sequence. Once a numeric-keyed table has nil gaps, do not rely on `#table` as a count or boundary.
      
      Assigning `nil` removes a key. Use `table.remove(sequence, index)` when removing from the middle of a sequence and preserving contiguity matters.
      
      Dot syntax is literal field syntax. Dynamic keys require brackets:
      
      ```luau
      local field = "score"
      print(record[field])
      ```
      
      Dictionary iteration order is unspecified. Sort explicit keys or values before emitting stable output.
      
      ## 3. Reference and copy semantics
      
      Tables are references. Assignment aliases the same table.
      
      ```luau
      local original = { score = 10, nested = { enabled = true } }
      local alias = original
      alias.score = 20
      print(original.score) -- 20
      ```
      
      `table.clone` creates a shallow copy. Nested tables remain shared.
      
      ```luau
      local copy = table.clone(original)
      copy.score = 30
      copy.nested.enabled = false -- also changes original.nested.enabled
      ```
      
      Do not add a generic recursive deep-copy helper without defining how it handles metatables, cycles, shared subgraphs, Instances, and unsupported keys. Copy only the data shape the caller owns.
      
      `table.freeze` prevents writes to that table, not recursively to all nested tables. Treat it as one boundary, not deep immutability.
      
      ## 4. Iteration and mutation
      
      Generalized iteration is valid Luau:
      
      ```luau
      for index, value in sequence do
          print(index, value)
      end
      
      for key, value in dictionary do
          print(key, value)
      end
      ```
      
      Use numeric loops when index range is the contract. Avoid removing sequence elements while iterating forward because indices shift. Iterate backward, record removals, or build a filtered result.
      
      ```luau
      for index = #sequence, 1, -1 do
          if shouldRemove(sequence[index]) then
              table.remove(sequence, index)
          end
      end
      ```
      
      `table.find` searches array values and returns an index or nil. It does not search dictionary keys or apply a predicate. `table.sort` mutates the sequence and its comparator must define a consistent strict order.
      
      ## 5. Scope, functions, and multiple values
      
      A local name is visible from its declaration onward. Code above a local declaration does not capture that later local.
      
      ```luau
      local second
      
      local function first(value: number)
          if value > 0 then
              second(value - 1)
          end
      end
      
      function second(value: number)
          if value > 0 then
              first(value - 1)
          end
      end
      ```
      
      Forward declaration is appropriate for mutual recursion. Otherwise place a callee before its callers.
      
      Functions can return multiple values. Context can keep or discard them:
      
      ```luau
      local function divide(a: number, b: number): (number?, string?)
          if b == 0 then
              return nil, "division by zero"
          end
          return a / b, nil
      end
      
      local quotient, problem = divide(6, 2)
      ```
      
      Parentheses and table constructors affect multiple-value expansion. When this matters, assign the values explicitly rather than relying on terse expression behavior.
      
      Missing arguments are `nil`; extra arguments can be ignored. A function that requires arity or non-nil inputs must validate or express that contract through types and call structure.
      
      Loop variables in a numeric or generic `for` have iteration-local behavior. Variables mutated outside the loop are shared by closures. Capture the intended value in a new local when ownership is unclear.
      
      ### `const` bindings
      
      <!-- temporal: 2026-03 -->
      `const` was added in Luau 0.711 (March 2026) and is newer than most models' training cutoffs. Older tooling and lint stubs may reject it; the keyword is valid ([release notes](https://github.com/luau-lang/luau/releases/tag/0.711), [RFC](https://github.com/luau-lang/rfcs/blob/master/docs/const-keyword.md)).
      
      ```luau
      const maxRetries = 3
      -- maxRetries = 5 -- rejected at compile time: constant rebinding
      
      const config = { speed = 16 } -- the binding is frozen, not the table
      config.speed = 20 -- allowed; use table.freeze for value immutability
      ```
      
      A `const` binding freezes the name, not the value; it applies to the binding like `local`, and the table itself stays mutable unless frozen. It is a contextual keyword, valid only where `local` is. `const` must be initialized at declaration. Prefer `const` for module-level values and constants that must never be rebound; it lets the typechecker and tools treat the symbol as stable.
      
      ## 6. Method syntax
      
      A colon adds an implicit first argument named `self`.
      
      ```luau
      function object:move(amount)
          self.position += amount
      end
      
      object:move(2)
      -- equivalent call shape: object.move(object, 2)
      ```
      
      A dot does not add `self`. Define and call a function consistently. Constructors and module functions usually use dot syntax; instance methods usually use colon syntax.
      
      Metatable object design and lifecycle belong in `roblox-luau-patterns`.
      
      ## 7. Strings and patterns
      
      Backtick interpolation and `..` concatenation are both valid:
      
      ```luau
      local message = `{name} reached {score}`
      local path = prefix .. "/" .. suffix
      ```
      
      Use the clearer form. When assembling many pieces in a loop, collect fragments in a sequence and call `table.concat` once if measurements show allocation matters.
      
      Luau uses Lua-style string patterns, not regular expressions. Do not paste regex syntax and assume equivalent behavior.
      
      Common classes include `%a` letters, `%d` digits, `%w` alphanumeric, and `%s` whitespace. Uppercase forms negate a class. Pattern magic characters must be escaped according to Lua pattern rules.
      
      ```luau
      local year, month, day = string.match("2026-07-26", "^(%d+)-(%d+)-(%d+)$")
      local compact = string.gsub("too   wide", "%s+", " ")
      for word in string.gmatch("one two", "%S+") do
          print(word)
      end
      ```
      
      A plausible-looking email regex translated into a Lua pattern is not robust email validation. Validate only the format the product actually needs.
      
      ## 8. Numeric behavior
      
      Luau provides ordinary arithmetic, compound assignment such as `+=`, and floor division `//`. Be explicit around division by zero, negative values, clamping, and units.
      
      `NaN` propagates through arithmetic and is unequal to everything including itself. Range guards written as `if v < min or v > max` silently accept NaN because both comparisons are false. Guard with `v ~= v`.
      
      Floor division `//` truncates toward negative infinity (`-7 // 2 == -4`). `0/0` is NaN.
      
      ### buffer library
      
      - Fixed-size binary data without table overhead: `buffer.create(size)`, then read/write typed values at offsets.
      - Offsets are 0-based, sizes in bytes. Out-of-range access errors; the buffer does not grow.
      - Reads/writes take explicit width and endianness (`readu8`/`readi16`/`readf32` family). No platform-dependent sizing.
      - Do not use `buffer.readinteger`/`buffer.writeinteger`: they appear in some type definitions but are not in the released runtime.
      
      ```luau
      local bounded = math.clamp(value, minimum, maximum)
      local whole = numerator // denominator
      ```
      
      Floating-point equality is often the wrong test for derived values. Use a tolerance selected from the domain, not one universal epsilon.
      
      Do not normalize a zero-length vector without deciding the fallback direction. Roblox datatype math belongs in the relevant camera, physics, or building skill.
      
      ### math library quick map
      
      One-line semantics; full reference at [luau.org/library](https://luau.org/library). Angles are radians; use `math.rad`/`math.deg` to convert.
      
      - `math.abs`, `math.floor`, `math.ceil`, `math.sqrt` (NaN on negative input), `math.exp`, `math.log(n, base?)` (base defaults to e; NaN on negative, `-inf` on 0), `math.log10(n)`.
      - Trig: `math.sin`/`math.cos`/`math.tan` take radians; `math.asin`/`math.acos` return NaN outside `[-1, 1]`; `math.atan2(y, x)` resolves the quadrant from both signs (range `[-pi, pi]`) and is the correct angle from a displacement, not `math.atan(y/x)` which loses quadrant. Hyperbolic: `sinh`, `cosh`, `tanh`. `math.atan(n)` returns `[-pi/2, pi/2]`.
      - `math.round` rounds to nearest, halfway away from zero; `math.floor`/`math.ceil` bound it. `math.fmod(x, y)` truncates toward zero and returns NaN when y is 0, unlike `x % y` which follows the sign of y. `math.modf(n)` returns integer and fractional parts, both with the input's sign. `math.frexp`/`math.ldexp` split/rebuild a significand and binary exponent.
      - `math.clamp(n, min, max)` errors when `min > max`. `math.sign(n)` is `-1`/`1`/`0` (0 for NaN too). `math.max`/`math.min` require at least one argument and error otherwise.
      - `math.random()` returns `[0, 1]`; `math.random(n)` returns `[1, n]`; `math.random(min, max)` returns `[min, max]`. Arguments are truncated to integers, so `math.random(1.5)` always returns 1. `math.randomseed(seed)` reseeds the generator for a deterministic sequence.
      - `math.isnan`, `math.isinf`, `math.isfinite` classify problem values without `x ~= x` tricks.
      - `math.noise(x, y?, z?)` is 3D Perlin noise, roughly `[-1, 1]`, inputs defaulting to 0. Smooth; use for procedural terrain and variation, not as a hash. For whole-terrain generation prefer a dedicated terrain or noise skill.
      - Luau adds `math.lerp(a, b, t)` (`a + (b - a) * t`; at exactly `t == 1` returns `b`) and `math.map(x, inMin, inMax, outMin, outMax)` (linear range remap); neither exists in plain Lua 5.x.
      
      ### EncodingService
      
      Roblox's engine service for Base64, hashing, and compression: `game:GetService("EncodingService")`. It operates on `buffer` values (use `buffer.fromstring`/`buffer.tostring` to convert), not strings, except the string hash. Docs: [EncodingService](https://create.roblox.com/docs/reference/engine/classes/EncodingService). <!-- temporal: 2026-08 -->
      
      - `EncodingService:Base64Encode(input: buffer): buffer` and `:Base64Decode(input: buffer): buffer` (decode throws on invalid input).
      - `EncodingService:ComputeBufferHash(input: buffer, algorithm: HashAlgorithm): buffer` and `:ComputeStringHash(input: string, algorithm: HashAlgorithm): string`. These are fast hashes (the `HashAlgorithm` enum), not password hashes or key derivation; use server-validated tokens or an external KDF for credential purposes.
      - `EncodingService:CompressBuffer(input, CompressionAlgorithm, compressionLevel?)`: Zstd levels -7 to 22; higher compresses more, costs more time.
      - `EncodingService:DecompressBuffer(input, CompressionAlgorithm)` throws when the size header is missing/corrupt or exceeds 1GB. For untrusted compressed data (e.g. from a client RemoteEvent), call `:GetDecompressedBufferSize(input, algorithm)` first; when it returns nil, refuse to decompress. Cap sizes by input source: compression amplification is a DoS vector.
      - This is the engine alternative to hand-rolled Base64 or `HttpService:JSONEncode` misuse for binary payloads. For JSON, still use `HttpService`; EncodingService is for bytes.
      
      
      ## 9. Cross-language translation traps
      
      ### JavaScript to Luau
      
      - `===` becomes `==`; `!==` becomes `~=`.
      - `null` and `undefined` do not map to two separate values; Luau uses `nil`.
      - Arrow functions, optional chaining, nullish coalescing, and spread syntax are not Luau syntax. JS `const`/`let` are unrelated to Luau's `const` keyword (a binding-freezing declaration added in 0.711) and there is no `let` at all.
      - Array `.map`, `.filter`, `.find(predicate)`, `.push`, and `.length` are not methods on Luau tables.
      - Object property enumeration order is not a portable dictionary-order contract.
      - `try/catch` is not syntax; fallible execution uses `pcall` or `xpcall`, with domain-specific recovery.
      - `async/await` is not syntax. Scheduling and Promise libraries belong in `roblox-luau-patterns`.
      
      ### Python to Luau
      
      - Sequences conventionally start at 1, not 0.
      - `None`, `True`, `False`, `elif`, list comprehensions, decorators, and exception syntax do not translate directly.
      - Dictionaries, lists, objects, and sets can all be represented with tables, but their invariants must be stated.
      - Tuple-like multiple returns are language behavior, not a single tuple object.
      - Indentation does not delimit blocks; `then`, `do`, and `end` do.
      
      Translate the data model and control flow, not token by token.
      
      ## 10. Deprecated and inherited APIs
      
      Roblox deprecation is a spectrum. **Deprecated** here means the API carries an official Deprecated tag (creator docs show it struck through). **Discouraged** means it works today, has no tag, but Roblox documents a reason to avoid it. Both get replacements; only the first group will ever show deprecation tooling.
      
      <!-- temporal: 2026-09 -->
      Verify current tags against the class pages before quoting them in reviews; Roblox adds tags over time and legacy globals live in [Roblox globals](https://create.roblox.com/docs/reference/engine/globals/RobloxGlobals).
      
      ### Officially deprecated (tagged)
      
      | Deprecated | Replacement | Notes |
      | --- | --- | --- |
      | `wait(seconds)` | `task.wait(seconds)` | Old global throttles to ~29 ms minimum and returns `(elapsed, gameTime)`; `task.wait` resumes on the next Heartbeat step without throttling. |
      | `spawn(f)` | `task.spawn(f)` | Old global throttles the first resumption and passes extra args; `task.spawn` runs immediately. |
      | `delay(t, f)` | `task.delay(t, f)` | Same throttling issues as `spawn`. |
      | `:connect` / `:wait` (lowercase) | `:Connect` / `:Wait` | Legacy lowercase aliases on `RBXScriptSignal`; PascalCase names are canonical and get new behavior. |
      | `BodyPosition` | `AlignPosition` | Legacy `BodyMover` family, all deprecated. |
      | `BodyGyro` | `AlignOrientation` | |
      | `BodyVelocity` | `LinearVelocity` | |
      | `BodyForce`, `BodyThrust` | `VectorForce` | |
      | `BodyAngularVelocity` | `AngularVelocity` (or `Torque`) | |
      | `RocketPropulsion` | `LineForce` / `AlignPosition` + `AlignOrientation` | |
      | `Humanoid:LoadAnimation` | `Animator:LoadAnimation` | Create the `Animator` on the server; calling the deprecated method from a client can create a client-only `Animator` that never replicates. Same applies to `AnimationController:LoadAnimation`. |
      | `Part.Velocity` / `Part.RotVelocity` | `AssemblyLinearVelocity` / `AssemblyAngularVelocity` | Assembly-level physics; per-part behavior was inconsistent for non-root parts. Use `BasePart:GetVelocityAtPosition()` for a specific point. |
      | `Model:SetPrimaryPartCFrame` | `PVInstance:PivotTo` | `GetPrimaryPartCFrame` → `PVInstance:GetPivot`. `PivotTo` needs no `PrimaryPart` and preserves offsets. |
      
      Roblox's own deprecated-to-modern quick reference (creator docs `reference/engine/llms.txt`) confirms the mover and task rows above.
      
      ### Functional but discouraged (no official tag)
      
      | API | Why discouraged | Use instead |
      | --- | --- | --- |
      | `tick()` | Not officially deprecated, but can be off by up to one second and returns inconsistent results across time zones and operating systems (Roblox's own docs say this). | `os.time()` (Unix seconds), `os.clock()` (benchmarks), global `time()` (session time), `workspace:GetServerTimeNow()` (synced), `DateTime` for timestamps. |
      | `Instance.new(class, parent)` | Works, but the docs mark the parent argument as not recommended: parenting first makes every later property write replicate and re-run listeners. | Create, set properties, then assign `.Parent` last. Setting parent in the constructor is acceptable only when no properties are set afterwards or the parent is not yet replicated. |
      
      Treat "deprecated" and "discouraged" as distinct when editing code: rewrite deprecated calls, and flag discouraged ones only when the surrounding code is already being touched.
      
      ## 11. Luau sandbox versus Lua 5.1
      
      Luau starts from Lua 5.1 and subtracts. When porting Lua code or answering "why is X missing," these removals are intentional sandbox design, not bugs (sources: [luau.org/sandbox](https://luau.org/sandbox), [Luau globals](https://create.roblox.com/docs/reference/engine/globals/LuaGlobals)).
      
      | Removed or reduced | Detail |
      | --- | --- |
      | `io` library | Removed entirely (file and process access). |
      | `package` library | Removed entirely (native module loading). |
      | `dofile` / `loadfile` | Removed (filesystem access). |
      | `string.dump` | Removed; bytecode access is unsafe to validate. `loadstring` accepts source only, never bytecode. |
      | `debug` library | Removed to a large extent; only `debug.traceback` and `debug.info` remain. |
      | `os` | Reduced to `os.clock`, `os.date`, `os.difftime`, `os.time`. No `os.execute`, `os.exit`, `os.getenv`, `os.rename`, `os.remove`, `os.tmpname`. |
      | `collectgarbage` | Only `"count"` works; other options are rejected because GC manipulation breaks isolation. `collectgarbage()` is effectively a weaker `gcinfo()` and deprecated in Roblox. |
      | `newproxy` | Accepts `nil`/`false` (bare userdata) or `true` (empty metatable); the generator-function form is gone. |
      | Builtin globals | Libraries, the string metatable, and the builtin globals table are read-only; monkey-patching `string` or `_G` builtin tables fails. Each script gets its own globals table that reads through to the builtins, so per-script globals still work. |
      | `getfenv` / `setfenv` | Still present (legacy code relies on them) but costly to isolation: they can inject globals into callers on the stack. Avoid in new code; `debug.info`/upvalues and module returns cover the legitimate cases. |
      
      ## 12. The vector library
      
      Luau's native `vector` type underlies `Vector3`-style math. In Roblox, the library is the 3-wide VM type that `Vector3` interoperates with; the library itself is small ([luau.org/library](https://luau.org/library)).
      
      ```luau
      local v = vector.create(1, 2, 3)
      local m = vector.magnitude(v)
      local n = vector.normalize(v)
      local d = vector.dot(v, n)
      local c = vector.cross(v, n)
      local a = vector.angle(v, n)
      -- componentwise: vector.floor / ceil / abs / sign / clamp / min / max
      -- constants: vector.zero, vector.one
      ```
      
      - Components are `x`/`y`/`z` (case-insensitive access); vectors are immutable, so there is no component write.
      - Operator support: `+`, `-`, `*`, `/`, unary minus, and indexing are built into the VM, which is why vector math is fast under `--!native`.
      - **There is no `vector.lerp`.** Linear interpolation is not in the library; use `math.lerp(a, b, t)` per component, or Roblox's `Vector3:Lerp()` for the engine datatype. Do not invent `vector.lerp` when translating code.
      - 4-wide mode (`LUA_VECTOR_SIZE`) exists for other embedders, not for Roblox, which is 3-wide.
      
      ## 13. Naming conventions
      
      Roblox's official Lua style guide ([roblox.github.io/lua-style-guide](https://roblox.github.io/lua-style-guide/), verified 2026-09) sets the house conventions for Luau code:
      
      | Construct | Convention | Example |
      | --- | --- | --- |
      | Classes, enum-like objects, module publics | `PascalCase` | `DataLoader`, `RobuxShop` |
      | Locals, member values, functions | `camelCase` | `currentRound`, `beginVote()` |
      | Local constants | `UPPER_SNAKE_CASE` | `MAX_RETRIES = 5` |
      | Private members | underscore-prefixed camelCase | `_connection` |
      | Acronyms inside a name | Only capitalize the first letter | `aJsonVariable`, `MakeHttpCall` |
      | Abbreviation as a set | Keep it fully capitalized | `anRGBValue`, `GetXYZ` |
      | All words | Spell words out; avoid abbreviations | `label`, not `lbl` |
      
      The acronym rule has two cases: an acronym like `JSON` or `HTTP` becomes `Json`/`Http` mid-name, while a set abbreviation like `RGB` or `XYZ` stays uppercase because it stands for full words. Spell-out is a readability rule, not a length limit; prefer the clearer name even when it is longer.
      
      ## 14. Native codegen (--!native / @native)
      
      Roblox compiler feature: server-side Luau compiles to machine code instead of VM bytecode. Best for numeric, table, and `buffer` heavy code with few library or API calls. Sources: [native code generation](https://create.roblox.com/docs/luau/native-code-gen), [Luau comments](https://create.roblox.com/docs/luau/comments). <!-- temporal: 2026-09 -->
      
      ```luau
      --!native
      --!optimize 2
      
      local function kernel(v: Vector3, n: number): number
          local sum = 0
          for i = 1, n do
              sum += v.X * i
          end
          return sum
      end
      ```
      
      - **Scoping: server-side.** The docs describe `--!native` for server-side scripts; do not add it to client scripts expecting the documented behavior.
      - `--!native` on a Script compiles all of its functions (and the top-level scope only if deemed profitable). `@native` above an individual function narrows it to that function.
      - **Pair with `--!optimize 2`.** Level 2 enables optimizations that harm debuggability (Studio test default is 1, live games default to 2); the pairing is the standard native idiom.
      - **Instruction ceilings** (hit = Output window error, fix by splitting functions):
        - 64K instructions in a single code block (`exceeded single code block instruction limit`)
        - 32K internal blocks in one function (`exceeded function code block limit`)
        - 1M instructions per script (`exceeded total module instruction limit`)
        - A memory limit for natively compiled code, separate from the 1M instruction ceiling; the docs warn that a natively compiled module consuming near a million instructions "takes up a lot of memory and you may exceed the memory limit."
      - **No official speedup number is published.** Roblox says only that it can improve execution speed for some server scripts. Never quote a benchmark ratio as official; measure with the Script Profiler (native functions are marked) and `debug.dumpcodesize()`.
      - Deoptimizers that drop functions back to the interpreter: `getfenv`/`setfenv`, builtin calls with non-numeric arguments, and passing values that violate annotated parameter types. Annotate hot parameters (especially `Vector3`) so codegen can specialize.
      
      ## 15. Review checklist
      
      - Syntax is Luau, not JavaScript, Python, or a different Lua version.
      - Only `false` and `nil` are treated as falsy.
      - Valid `false` values survive fallback logic.
      - Sequences are contiguous when `#`, insertion, or removal relies on that shape.
      - Dictionary behavior does not depend on iteration order.
      - Table aliases and shallow copies are intentional.
      - Dynamic keys use bracket syntax.
      - Local declaration order and closure capture are correct.
      - Method definition and call syntax agree.
      - Multiple return values preserve success, absence, and error states.
      - String patterns are Lua patterns, not unverified regex translations.
      - Removed globals (`io`, `package`, `string.dump`, absent `os` members) are treated as sandbox design, not ported from Lua 5.1 assumptions.
      - Deprecated APIs use their replacements; discouraged APIs are flagged with reasons, not called silently.
      - Names follow the Roblox style guide: PascalCase types/publics, camelCase locals, `LOUD_SNAKE_CASE` constants (often written UPPER_SNAKE_CASE elsewhere), first-letter-only acronyms, spelled-out words.
      - Engine behavior and project architecture are routed to their canonical skills.
      
  • SKILL.md 2.9 KB
    ---
    name: roblox-luau-core
    description: "Use for Luau language semantics, tables, control flow, string patterns, scope, closures, and cross-language translation errors."
    last_reviewed: 2026-08-31
    sources:
      - https://luau.org/syntax
      - https://luau.org/library
    ---
    
    # Luau Core Language
    
    ## When to Load
    
    Load for pure Luau syntax and semantics: truthiness, tables, iteration, functions, scope, operators, string patterns, and ports from JavaScript or Python. Use `roblox-luau-types` for type annotations, `roblox-luau-patterns` for ownership and lifecycle, and domain skills for Roblox APIs.
    
    ## Quick Reference
    
    - Only `false` and `nil` are falsy. `0`, `""`, and `{}` are truthy.
    - Equality does not coerce types. `0 == "0"` is false. Inequality is `~=`.
    - Array conventions are 1-based. `#array` is meaningful only for a sequence without nil gaps.
    - Assigning `nil` removes a table key. Assigning a table copies the reference. `table.clone` is shallow.
    - Dictionary iteration order is unspecified. Do not make behavior depend on it.
    - Dynamic keys require brackets: `record[field]`. Dot syntax uses a literal identifier.
    - Missing arguments become `nil`; extra results and arguments can be discarded by context.
    - Prefer an `if` expression over `condition and a or b` when `a` may be `false` or `nil`.
    - Local names are scoped from their declaration onward. Forward-declare mutually recursive functions.
    - Luau string patterns are not regular expressions. Their syntax and capabilities differ.
    - Backtick interpolation and `..` concatenation are both valid. Choose the clearer form; collect many fragments and join once in a hot loop.
    - NaN does not equal itself and defeats `<`/`>` comparisons; test with `x ~= x`.
    - Binary data uses the `buffer` library: fixed size, 0-based offsets, explicit-width reads/writes. Avoid `buffer.readinteger`/`writeinteger` (stubs only, not released runtime).
    - For Base64, hashing, or compression use `EncodingService` (buffers, not strings; JSON still via `HttpService`). Details: see full reference.
    
    ```luau
    local label = if enabled then "On" else "Off"
    local message = `{name}: {score}`
    
    local byId: {[number]: string} = {}
    byId[userId] = name
    
    for index, value in values do
        print(index, value)
    end
    ```
    
    ### Translation traps
    
    - JavaScript `===`, `!==`, `null`, optional chaining, spread, arrow functions, and array methods are not Luau syntax.
    - Python `None`, zero-based list assumptions, list comprehensions, exceptions, and implicit tuple behavior do not translate directly.
    - `x or fallback` tests truthiness, not only absence. It replaces a valid `false` value.
    - `typeof(value)` recognizes Roblox datatypes; `type(value)` reports the underlying Luau type category.
    
    ### Review
    
    Valid Luau, no nil gaps in sequences, no assumed dictionary order, no accidental aliases, no cross-language syntax, no boolean expressions hiding `false` or `nil`.
    
    > Detailed language traps and translation examples: [references/full.md](references/full.md)
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related