t1k:unity:base:code-conventions
| Field | Value |
|---|---|
| Module | base |
| Version | 2.2.2 |
| Effort | high |
| Tools | — |
Keywords: code conventions, coding standards, naming, style
How to invoke
Section titled “How to invoke”/t1k:unity:base:code-conventionsUnity C# Code Conventions
Section titled “Unity C# Code Conventions”Triggers
Section titled “Triggers”- C# code, naming, convention, style, constant, hardcoded, magic number
- new class, new file, new component, new system, refactor
- code review, code quality, code standards
Naming Conventions (C# + Unity)
Section titled “Naming Conventions (C# + Unity)”Casing Rules
Section titled “Casing Rules”| Element | Casing | Example |
|---|---|---|
| Namespace | PascalCase | DOTSCombat |
| Class, Struct | PascalCase | AttackTimerSystem |
| Interface | IPascalCase | IHealthProvider |
| Enum | PascalCase | AttackType |
| Enum member | PascalCase | AttackType.Ranged |
| Public method | PascalCase | CalculateDamage() |
| Private method | PascalCase | ApplyKnockback() |
| Property | PascalCase | MaxHealth |
| Public field | PascalCase | DamageMultiplier |
| Private field | camelCase | attackTimer |
| Parameter | camelCase | targetEntity |
| Local variable | camelCase | closestEnemy |
Constant (const) | PascalCase | MaxStackCount |
| Static readonly | PascalCase | DefaultColor |
| Type parameter | TPascalCase | TComponent |
Unity-Specific Naming
Section titled “Unity-Specific Naming”| Element | Pattern | Example |
|---|---|---|
| MonoBehaviour | Noun/NounPhrase | PlayerController |
| IComponentData | Domain suffix | HealthData, AttackTimer |
| Tag component | Is prefix or no suffix | IsMoving, Dead |
| ISystem | Verb + System | AttackTimerSystem |
| Baker | Authoring + Baker | class HealthBaker : Baker<HealthAuthoring> |
| Authoring | Authoring suffix | HealthAuthoring |
| IAspect | Aspect suffix | CombatAspect |
| ScriptableObject | Noun | ArenaConfig |
| Editor script | Descriptive verb/noun | BattlefieldAssemblySetup |
| Test class | Tests suffix | AttackTimerSystemTests |
Library vs Demo Naming (CRITICAL)
Section titled “Library vs Demo Naming (CRITICAL)”- Library packages (
Packages/): NEVER use game/demo names. Types must be generic and reusable across games.- BAD:
ColorFitGameState,BackpackResult,BattleDemoPhase - GOOD:
QueuePuzzleGameState,GridFillSystem,CharacterMovementSystem - Test: “Would this name make sense in a completely different game?” If no → rename it.
- BAD:
- Demo code (
Assets/Demos/): Game-specific names are fine here (ColorFitCanvasUI,BattleDemoSceneSetup)
File Naming
Section titled “File Naming”- One type per file, filename matches type name:
AttackTimerSystem.cs - Keep files under 200 lines — split into partial classes or helper systems
- Editor scripts in
Editor/folder with Editor-only asmdef
No Hardcoded Values (CRITICAL)
Section titled “No Hardcoded Values (CRITICAL)”Strings — NEVER inline literals for:
Section titled “Strings — NEVER inline literals for:”- Shader names:
"Universal Render Pipeline/Lit"→ShaderConstants.UrpLit - Shader properties:
"_BaseMap"→ShaderConstants.PropBaseMap - GameObject names:
"BattlefieldArena"→private const string ArenaRootName - File paths:
"Assets/Prefabs/"→private const string PrefabFolder
Acceptable inline strings: Debug.Log(), [MenuItem("...")] attributes, nameof(), one-time errors.
Numbers — NEVER inline numeric literals:
Section titled “Numbers — NEVER inline numeric literals:”-1sentinel →private const int InvalidIndex = -1;0.1fthreshold →private const float DamageThreshold = 0.1f;2450render queue →private const int AlphaTestRenderQueue = 2450;
→ See references/constants-patterns.md for the full SharedConstants class pattern and file-local private const usage.
Code Organization
Section titled “Code Organization”Class Structure Order
Section titled “Class Structure Order”- Constants (
const,static readonly) - Static fields / Instance fields
- Constructors / Properties
- Public → Internal → Private methods
- Nested types
Assembly Definitions
Section titled “Assembly Definitions”- Each folder with distinct dependencies gets its own
.asmdef - Editor code MUST be in Editor-only asmdef (
Editor/folder) - Test code MUST have
UNITY_INCLUDE_TESTSdefine constraint
Namespace Conventions
Section titled “Namespace Conventions”- Match folder structure:
Packages/[pkg]/Runtime/Combat/→[Namespace].Combat - Editor:
[YourPackage].Editor| Tests:[YourNamespace].Tests
DOTS-Specific Conventions
Section titled “DOTS-Specific Conventions”Component Design
Section titled “Component Design”- Pure data, no logic — structs implementing
IComponentData - No managed types (
string,class,List<T>) — useFixedString32Bytes/FixedString64Bytes - Tag components: empty struct (
struct Dead : IComponentData {}) - Prefer
EnableableComponentover add/remove for frequent state changes
System Design
Section titled “System Design”ISystem(struct) overSystemBase(class) for Burst compatibility[BurstCompile]on struct AND all lifecycle methods[RequireMatchingQueriesForUpdate]to skip when no matching entities- Cache
ComponentLookup<T>inOnCreate, update inOnUpdate - Hoist
SystemAPI.Time.ElapsedTimebefore foreach loops
System Ordering
Section titled “System Ordering”[UpdateInGroup(typeof(SimulationSystemGroup))][UpdateAfter(typeof(DetectionSystem))][UpdateBefore(typeof(NavigationSystemGroup))]→ See references/anti-patterns.md for the full anti-patterns table with correct alternatives.
Null Check Performance
Section titled “Null Check Performance”obj == nullonUnityEngine.Objectsubclasses invokes the overridden==operator, which calls into native code — measurably slower in hot paths- Prefer implicit bool:
if (myObj)instead ofif (myObj != null)for destroyed-object checks - NEVER use
??or?.with Unity objects — they bypass the overridden operator entirely (seeunity-monobehaviourskill for details)
Editor Script Conventions
Section titled “Editor Script Conventions”- Menu path:
"Tools/[Package]/[Action]"— must be compile-time string literal - Always check existence before creating:
AssetDatabase.LoadAssetAtPath<T>(path) - Clean up temporaries:
Object.DestroyImmediate(tempGo) - Save after creation:
AssetDatabase.SaveAssets()+EditorSceneManager.SaveScene() - Execute Unity Editor actions via MCP tools — never ask user to run menu items manually
Reference Files
Section titled “Reference Files”| File | Content |
|---|---|
references/constants-patterns.md | SharedConstants class, private const, naming prefixes |
references/anti-patterns.md | Common anti-patterns table with correct alternatives |
Gotchas
Section titled “Gotchas”- Code conventions enforced via
.editorconfigonly on supporting IDEs — Rider, VS Code (with C# Dev Kit), VS yes; Sublime/Vim no — pair with a CI lint to catch drift. - Assembly definition naming has a hard 64-char path limit on Windows — long namespaces hit this in CI before any developer notices.
#regionblocks are an anti-pattern in modern C# — prefer extracting to partial classes; conventions should call this out explicitly.- Demo/Test/Temp/Placeholder namespace ban needs a CI hook — 20/22 audited demos violated CLAUDE.md “no Demo/Test/Temp/Placeholder in production names” (260520-R3); enforcement via
.editorconfigalone is insufficient. Add a grep-based CI gate that fails onnamespace.*Demoin production assemblies (not test asmdefs). Source: review-260520-round3-production.md §R3P2