Imported from andrian-syh/roblox-optimum (
skills/best-practices/SKILL.md). Install upstream withnpx skills add andrian-syh/roblox-optimum --skill best-practices. Copyright stays with the author (MIT).
Roblox Game Development Best Practices
Framework-agnostic standards for writing clean, efficient, lightweight, and resource-frugal Luau code. These rules fit any architecture — they govern how each script is written, not how the project is structured.
Goals, in priority order: correct → secure (server-authoritative) → efficient (CPU/memory/network) → readable → consistent.
Session Invariants (must survive compaction)
A summary that drops these rules silently downgrades every file written afterwards. Two standing obligations:
- Carry it forward verbatim in any summary, handoff, plan, or task note. It is active instruction, never compressed into "follow the Roblox skill".
- Re-read this file before acting whenever the card's full text is not visible in your context. Never reconstruct these rules from memory — a half-remembered layout rule looks deliberate and is worse than none.
ROBLOX LUAU SKILL - INVARIANT CARD
1 Three sections, this order:
-- // VARIABLES // -- Services > Modules > Objects > Configuration > State Management
-- // FUNCTIONS // -- definitions only (ModuleScript: Private before Public)
-- // INITIALIZATION // -- everything that runs
2 Documentation Comments (Luau Comments) - default style, adapts to the project.
Default block: --[[ ]] above the function, desc > @param > @return.
Moonwave --[=[ ]=] or --- is equally correct when that is the project's style.
- Desc <= 3 lines and <= 250 chars, contract-level, states PURPOSE.
- Desc never names what the body does to get there: no APIs, algorithms,
collaborators, data structures, or code paths.
- Desc carries NO volatile content: no numbers, thresholds, tunable names,
feature names, or anything that needs editing when the body is retuned.
When a detail cannot be avoided, state it at the most general level
that stays true after the body changes.
- Tags use Moonwave syntax: @param <name> <type> -- <description>
and @return <type> -- <description>. Only when they add what the
signature cannot show.
- English preferred as the universal language. No em dashes or double-hyphen
dashes as punctuation (the -- in a tag is a separator, not punctuation).
No emoji.
- IN-BODY COMMENTS: banned in code you write. Make names and
structure say it; put the why in the block above. Never delete
an existing one; propose removal once, Advisory only.
- Self-documenting code outranks commentary everywhere.
- Existing project comment style wins. Recommend this style when the user
asks to restyle; never impose it.
3 Server is authoritative. Validate every remote arg: type, range, ownership, rate.
4 Clean up everything created. Every connection has an owner and a teardown path.
5 No avoidable per-frame garbage. Never poll what has a signal.
Cold paths are exempt, and periodic work on a timer is scheduling.
6 UpdateAsync + backoff. Save on PlayerRemoving. Flush on BindToClose.
7 Re-validate after every yield: player gone? instance dead? session changed?
Only where a yield sits between the check and its use.
8 Never add --!strict unbidden. Never make a [Beta] feature the production default.
9 Reuse before writing: project, then stdlib, then engine API. Search, never
assume - no claim about a file you have not opened. No wrapper or
abstraction without a caller. But brevity has two hard limits:
- It NEVER reduces what was asked for. Short because it does less = failed.
- It NEVER costs readability. One statement per line, descriptive names,
blank lines kept. Less code means less WORK, not less whitespace.
10 User authority outranks this skill. Recommend; never refactor unasked.
Everything below expands these; nothing below overrides them.
Reference Routing
Load only what the situation needs. Each reference is self-contained; read one, not the set. Nothing below loads until a line matches the task at hand.
Authoring
- templates.md — writing a new Script/LocalScript/ModuleScript
- section-layout.md — layout detail, subsection contents, Documentation Comment rules, rejected examples
- style-rules.md — naming, deprecated APIs, misremembered APIs,
const, typing opt-in, module hygiene - adaptive-mode.md — existing codebase with its own conventions
- community-libraries.md — ProfileStore, Packet, Trove, Knit, Fusion, ...
- minimal-code.md — about to write a helper that may already exist; keeping code dense
- edge-cases.md — nil, empty, stale, duplicate, reused, or departed state a function will meet
- luau-language.md — truthiness and coercion, table copy semantics,
requiresemantics, typing depth,vector/buffer/math,task.spawnvstask.defer, deferred events, error handling, time APIs, native codegen
Implementing a known system — read the one file whose domain matches; each gives assembly order and case-specific failure modes.
- cases/data-economy.md — player data, currency, inventory, trading
- cases/monetization.md — Developer Products, passes/subscriptions, gacha/loot boxes
- cases/progression.md — leaderboards, daily rewards, streaks, offline progress
- cases/combat.md — damage/hit validation, abilities and cooldowns, projectiles, NPC/mob AI
- cases/session-flow.md — round/match lifecycle, matchmaking and reserved servers, cross-server events
- cases/world-interaction.md — interactables and prompts, placement/building, pets and followers
- cases/client-infra.md — HUD/state sync, rate limiting and anti-cheat, analytics instrumentation
Deepening a concern
- performance.md — hot loops, memory, network traffic, physics queries and contact detection, rendering, profiling
- device-performance.md — frame budget in ms, low-end and "potato" devices, quality degradation, time-slicing, per-player bandwidth
- patterns/data.md — state ownership, data stores (+ version history), failure policy after the last retry, per-owner locks
- patterns/network.md — remotes, cross-server (MemoryStore, MessagingService, reserved servers), StreamingEnabled
- patterns/lifecycle.md — connection cleanup, character lifecycle (Humanoid vs CCL), object pooling
- patterns/world.md — CollectionService binding and attributes, client input, anti-patterns to reject on sight
- patterns.md — index of the four pattern files above
- security.md — anti-exploit, remote validation depth, movement sanity checks, text filtering
- monetization-policy.md —
ProcessReceipt, Developer Products and passes, PolicyService compliance - server-authority.md — anything touching movement, physics, input, camera, animation timing,
BindToSimulation, network ownership - ui-crossplatform.md — UI construction, cross-platform and accessibility, input device handling
- genres.md — simulator, FPS, obby, RPG, racing, horror, social, tower defense, battlegrounds
Process
- workflow.md — resolving a session-setup decision, supervision behavior, opening a review, the preflight before a non-trivial system
- team-workflow.md — more than one person on the project, or one person keeping it tidy: git alongside a place file, branch places, who owns which tree, the review gate, shipping
- Tooling — a Studio MCP connection, a sync toolchain (Rojo, Argon, Script Sync, Azul), or proving a change works in a running session: the studio-ops skill owns all three
- false-positives.md — reviewing code: whether a finding is real, how severe, what NOT to flag
- review-checklist.md — finishing any task: the completion gate before calling work done
- api-currency.md — whether a newer engine/Luau API is confirmed before relying on it or flagging it missing
- limits-budgets.md — platform ceilings: DataStore size/requests, MemoryStore, messaging, attributes, animation tracks
Lookup files — limits-budgets.md, genres.md, edge-cases.md are tables, not narratives. Grep the row you need instead of reading them whole.
User Authority
This skill is guidance, not a mandate — full control always stays with the user:
- The user's explicit instructions override any convention in this skill. If an instruction conflicts with a Non-Negotiable Runtime Rule, state the risk once, briefly, then follow the user's decision.
- Never take actions the user didn't ask for on the strength of this skill alone: no unrequested refactors, restructuring, file creation, or "while I'm here" cleanups. Recommend; don't act.
- Invoked with no task ("use best practices", "follow this skill from now on"): acknowledge that the standards are active and stop — no codebase analysis, no setup questions (references/workflow.md).
Session Setup (decide once, then cache)
Five decisions govern every later task. Resolve each once, cache it, never re-ask per file — and resolve them lazily, at the first task that depends on one. How to resolve each, and how the supervision level modifies it: references/workflow.md.
| Decision | Default when unresolved |
|---|---|
Supervision level — invocation argument ask/bal/go, or !ask/!bal/!go inline |
The configured level ${user_config.supervision} if that names one of ask, bal, or go, otherwise Balanced. Never ask which level the user wants — absence is the answer |
| Default vs Adaptive mode | Default for new files; for edits, match the file being edited and note the assumption |
| Community libraries | None — use the built-in patterns |
| Server Authority | OFF — most places are not server-authoritative, and assuming otherwise produces confidently wrong code |
Environment facts — SignalBehavior, StreamingEnabled, rig type, strictness header |
Assume none of them; each inverts correct guidance between values |
Default applies these conventions as written; Adaptive proposes an adaptation of the project's own style and waits for confirmation (references/adaptive-mode.md). Only style and structure ever adapt, and community libraries win for the concern they own. Never migrate a project to Server Authority on this skill's initiative.
Judging code instead of writing it
Reviewing a file, auditing a place, or scoring architectural health belongs to the code-review skill. Working out why a reported symptom happens, when no file has been named yet, belongs to the diagnose skill — reaching for the first plausible file produces a change that looks like a fix and leaves the defect in place. This one applies when the task is to produce or change Luau — including fixing findings a review or a diagnosis already reported.
While writing, the same guardrails still hold: one severity per observation (Blocker / Correctness / Advisory), after the confidence gate, and Advisory is proposed rather than applied. Gate and calibration: references/workflow.md. What NOT to flag: references/false-positives.md.
Environment & Scale
- Detect the project environment first — Studio-native, or a filesystem project synced by Script Sync, Rojo, Argon, or Azul. Which side is the source of truth differs per tool, and assuming wrong overwrites the user's work. Never start, stop, or reconfigure a sync session unasked, and on an MCP connection run the preflight before any write. The detail lives in the studio-ops skill; when a task turns on which side wins, or on proving a change works in a running session, that skill owns it.
- Verify newer APIs, and state the basis for every engine fact. Memory is never presented as fact. Two authorities, two questions: does it exist — the versioned API dump or an in-Studio probe; what does it do — the Engine API Reference. The docs site lags the engine, so a member missing from a reference page is undocumented, not unshipped; never call an API nonexistent on that basis. Cite the check, or say "unverified" and name the one that would settle it: references/api-currency.md.
- Maturity tags: [GA] safe as a default · [Beta] opt-in, may change · [Undocumented] shipped, but no reference page — probe its semantics · [Verify] confirm in the target place · [UNVERIFIED] unconfirmed by this skill. Never make a [Beta] feature a production default — offer it, state its status, recommend the stable path.
- Scale the ceremony to the script. Tiny scripts (< ~40 lines) may use the three top-level headers with no subsections; add deeper headers only when a section needs them, never empty placeholders. Pure data/type modules (config tables, item catalogs, shared types) are exempt from the three-section layout.
Script Section Layout (MANDATORY)
Card items 1–2 hold the layout and Documentation Comment rules. Two things the card does not carry:
- Module requires are ordered by source: ServerScriptService → ServerStorage → ReplicatedStorage → Workspace → script-relative, counting only locations the script can legally reach.
- Function order inside FUNCTIONS and what belongs in each VARIABLES subsection are specified, not free.
Full specification — the five-level header hierarchy, subsection contents, the two description rules with worked rejections, and the self-documenting-code rule: references/section-layout.md. Annotated templates: references/templates.md.
Language & Style Rules
The ones that apply on nearly every task:
- Naming:
PascalCaseservices and module tables ·camelCaselocals, functions, Instance references ·UPPER_SNAKE_CASEConfiguration constants. Module publicsPascalCase, privatescamelCase. - Always
game:GetService(); never direct indexing (theworkspaceglobal is fine). - Never use deprecated APIs —
wait/spawn/delay,tick, lowercase:connect/:wait,Body*movers,Humanoid:LoadAnimation,SetPrimaryPartCFrame, and the rest of the list in references/style-rules.md. Discouraged-but-functional APIs (theInstance.newparent arg,FireAllClients) are not deprecated ones and are Advisory at most. - Type safety is opt-in. Never add or raise
--!strictunbidden; match what the file or project already declares. - Guard external and yielding calls (
DataStore,MarketplaceService,HttpService,TeleportService) withpcallplus a retry policy and a stated failure policy (references/patterns/data.md). - Reuse before writing, and keep it dense — search the project, the standard library, then the engine API. Brevity never reduces what gets delivered and never costs readability.
- Stay framework-agnostic by construction: bind by tags and attributes, discover by service, assume no folder layout.
Complete set — const bindings, CollectionService binding, circular requires, one responsibility per module, the full deprecation list, and the commonly-misremembered-API table: references/style-rules.md.
Non-Negotiable Runtime Rules
Card items 3-8 are the rules themselves and are always in context. Full statements, the scope that keeps each from being over-applied, and the domain file behind each: references/runtime-rules.md.
Server authority · cleanup with a teardown path · no per-frame garbage · react instead of poll · UpdateAsync with backoff and a BindToClose flush · batched, delta-shaped network traffic · re-validation after every yield.
These hold through every mode, level, and community library. Before flagging a violation in review, check the scoped exceptions in references/false-positives.md — each rule has shapes that only look like violations.
System Design Preflight
Before implementing any non-trivial system, settle five questions in order — which case is this · what are the ceilings · what is the server/client split and who owns each fact · does this already exist · how will it be proven to work: references/workflow.md.
If the system touches movement, input, camera, animation timing, or simulation stepping, resolve the Server Authority decision first — it changes the answers.
Review Checklist
Before calling any Luau work finished, run references/review-checklist.md — layout, comments, cleanup, hot loops, ownership, failure policy, locks, edge cases, validation, evidence for engine facts, delivery completeness. A finishing gate: read it at the end of the task, not the start.