Skip to content

t1k:unity:base:code-conventions

FieldValue
Modulebase
Version2.2.2
Efforthigh
Tools

Keywords: code conventions, coding standards, naming, style

/t1k:unity:base:code-conventions

  • C# code, naming, convention, style, constant, hardcoded, magic number
  • new class, new file, new component, new system, refactor
  • code review, code quality, code standards
ElementCasingExample
NamespacePascalCaseDOTSCombat
Class, StructPascalCaseAttackTimerSystem
InterfaceIPascalCaseIHealthProvider
EnumPascalCaseAttackType
Enum memberPascalCaseAttackType.Ranged
Public methodPascalCaseCalculateDamage()
Private methodPascalCaseApplyKnockback()
PropertyPascalCaseMaxHealth
Public fieldPascalCaseDamageMultiplier
Private fieldcamelCaseattackTimer
ParametercamelCasetargetEntity
Local variablecamelCaseclosestEnemy
Constant (const)PascalCaseMaxStackCount
Static readonlyPascalCaseDefaultColor
Type parameterTPascalCaseTComponent
ElementPatternExample
MonoBehaviourNoun/NounPhrasePlayerController
IComponentDataDomain suffixHealthData, AttackTimer
Tag componentIs prefix or no suffixIsMoving, Dead
ISystemVerb + SystemAttackTimerSystem
BakerAuthoring + Bakerclass HealthBaker : Baker<HealthAuthoring>
AuthoringAuthoring suffixHealthAuthoring
IAspectAspect suffixCombatAspect
ScriptableObjectNounArenaConfig
Editor scriptDescriptive verb/nounBattlefieldAssemblySetup
Test classTests suffixAttackTimerSystemTests
  • 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.
  • Demo code (Assets/Demos/): Game-specific names are fine here (ColorFitCanvasUI, BattleDemoSceneSetup)
  • 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
  • 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:”
  • -1 sentinel → private const int InvalidIndex = -1;
  • 0.1f threshold → private const float DamageThreshold = 0.1f;
  • 2450 render queue → private const int AlphaTestRenderQueue = 2450;

→ See references/constants-patterns.md for the full SharedConstants class pattern and file-local private const usage.

  1. Constants (const, static readonly)
  2. Static fields / Instance fields
  3. Constructors / Properties
  4. Public → Internal → Private methods
  5. Nested types
  • 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_TESTS define constraint
  • Match folder structure: Packages/[pkg]/Runtime/Combat/[Namespace].Combat
  • Editor: [YourPackage].Editor | Tests: [YourNamespace].Tests
  • Pure data, no logic — structs implementing IComponentData
  • No managed types (string, class, List<T>) — use FixedString32Bytes/FixedString64Bytes
  • Tag components: empty struct (struct Dead : IComponentData {})
  • Prefer EnableableComponent over add/remove for frequent state changes
  • ISystem (struct) over SystemBase (class) for Burst compatibility
  • [BurstCompile] on struct AND all lifecycle methods
  • [RequireMatchingQueriesForUpdate] to skip when no matching entities
  • Cache ComponentLookup<T> in OnCreate, update in OnUpdate
  • Hoist SystemAPI.Time.ElapsedTime before foreach loops
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateAfter(typeof(DetectionSystem))]
[UpdateBefore(typeof(NavigationSystemGroup))]

→ See references/anti-patterns.md for the full anti-patterns table with correct alternatives.

  • obj == null on UnityEngine.Object subclasses invokes the overridden == operator, which calls into native code — measurably slower in hot paths
  • Prefer implicit bool: if (myObj) instead of if (myObj != null) for destroyed-object checks
  • NEVER use ?? or ?. with Unity objects — they bypass the overridden operator entirely (see unity-monobehaviour skill for details)
  • 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
FileContent
references/constants-patterns.mdSharedConstants class, private const, naming prefixes
references/anti-patterns.mdCommon anti-patterns table with correct alternatives
  • Code conventions enforced via .editorconfig only 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.
  • #region blocks 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 .editorconfig alone is insufficient. Add a grep-based CI gate that fails on namespace.*Demo in production assemblies (not test asmdefs). Source: review-260520-round3-production.md §R3P2