# code-lua > Use when writing Lua code for game development (LÖVE2D, Defold, WoW addons), Neovim plugins, or embedded scripting. Use when you think code is "too simple for types" or "just a prototype" - these are symptoms this skill applies. - Author: jeffzi - Repository: jeffzi/.claude - Version: 20260122103856 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/jeffzi/.claude - Web: https://mule.run/skillshub/@@jeffzi/.claude~code-lua:20260122103856 --- --- name: code-lua description: > Use when writing Lua code for game development (LÖVE2D, Defold, WoW addons), Neovim plugins, or embedded scripting. Use when you think code is "too simple for types" or "just a prototype" - these are symptoms this skill applies. --- # Lua Coding **Core principle:** Every function gets type annotations. Quick code becomes production code. ## Formatting - **Indentation:** 3 spaces (not tabs, not 2 or 4) - **Line length:** 100 characters max - **Trailing commas:** Always in multi-line tables ## Type Annotations **ALWAYS add LuaLS/EmmyLua annotations.** ```lua --- Return squared even numbers from input. --- @param items number[] Input values. --- @return number[] local function process(items) local result = {} for i = 1, #items do local x = items[i] if x % 2 == 0 then result[#result + 1] = x ^ 2 end end return result end ``` ### Documentation Style | Element | Style | Example | | --------- | --------------- | -------------------------------- | | Function | Infinitive verb | _"Return the user's full name."_ | | Parameter | Noun phrase | _"User's given name."_ | **Avoid:** third-person (_"Returns"_), articles (_"The first name"_). ## Naming Conventions | Element | Convention | Example | | ------------------- | ------------------- | -------------------------- | | Variables/functions | `snake_case` | `local player_score` | | Classes/modules | `CamelCase` | `local PlayerManager = {}` | | Constants | `UPPER_CASE` | `local MAX_HEALTH = 100` | | Private members | `_prefix` | `self._internal_state` | | Boolean functions | `is_`/`has_` prefix | `is_valid()`, `has_item()` | | Metatables | `*_mt` suffix | `local Player_mt = {}` | ## Pitfalls | Trap | Instead | | ---------------------------------------- | --------------------------------------- | | `if x then` for nil check | `if x ~= nil then` | | `ipairs()` in performance-critical paths | `for i = 1, #t do` | | Chained `..` with 4+ strings | `table.concat()` | | `assert.are.equal()` (dots) | `assert.are_equal()` (underscores) | | `require "mod"` | `require("mod")` | | `local f = function()` | `local function f()` | | Comments explaining WHAT code does | Only explain WHY | | Silent failures | Return `nil, err` for expected failures | | Table creation in hot paths | Reuse tables, reset fields | ### Ternary Abuse `a and b or c` is for **trivial defaults only**. ```lua -- OK local name = user_name or "guest" local status = is_active and "online" or "offline" -- BAD: arithmetic local scale = (time > 0) and (min / time) or fallback -- BAD: nested local x = a and (b and c or d) or e -- BAD: long expressions local msg = player:is_alive() and player:get_name() or "unknown" ``` **If you pause to parse it, use if/else.** ## Testing with Busted Tests in `tests/` with `*_test.lua` suffix. ```lua describe("PlayerManager", function() test("creates player with default health", function() local player = PlayerManager.new("test") assert.are_equal(100, player.health) end) end) ``` - Use `test` blocks, **not `it`** (no BDD style) - One `describe` per module, **flat structure** - no nested `describe` blocks - Use `before_each` for shared setup, `pending("reason")` for planned tests ### Test Design **MVP tests: minimum tests, maximum coverage.** All code paths must be covered. Use `luacov` to verify - uncovered lines mean missing tests. | Merge when | Keep separate when | | ------------------------------------- | --------------------- | | Same code path, different inputs | Different code paths | | Related edge cases (nil, empty, zero) | Complex setup differs | | Same behavior across APIs | Tests need isolation | ## Rationalizations That Mean Failure | Excuse | Reality | | ------------------------- | ------------------------------------------------- | | "Too simple for types" | Type annotations catch bugs at write-time. | | "Just prototyping" | Prototypes become production. No shortcuts. | | "Would add in production" | Quick code IS production code. | | "ipairs is more readable" | Readability doesn't matter if your code stutters. | | "This table is temporary" | Temporary tables cause GC spikes. Reuse them. | ## Verification **MANDATORY before completing any task:** ```bash luacheck . # Lint llscheck --checklevel Hint # Types busted # Tests (if tests/ exists) busted --coverage && luacov # Coverage (if .luacov exists) ``` **Task is NOT complete until all pass.** ## Related Commands - `/review-lua` - Review Lua code against these rules