mcpField
U
unity-csharp

unity-csharp

github.com/alexanderstephenthompsonDevelopment70 installs
Repository

About unity-csharp

unity-csharp is a skill for developers writing and optimizing Unity C# code, including VR and mobile projects. It combines component and lifecycle patterns with profiling guidance and performance practices.

Key features

  1. 01MonoBehaviour lifecycle and component design
  2. 02Caching, events, coroutines, and null safety
  3. 03ScriptableObject data patterns
  4. 04Draw-call, batching, and LOD optimization
  5. 05VR and mobile profiling guidance

Use cases

  1. 01Structure scripts around focused Unity components
  2. 02Reduce repeated component lookups and Update work
  3. 03Optimize rendering for VR or mobile targets
  4. 04Profile CPU, memory, and draw-call issues

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/alexanderstephenthompson/claude-hub --skill unity-csharp

After installing, type/unity-csharpin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

assets/
component-checklist.md
vr-performance-limits.md
references/
lifecycle.md
profiling.md

Details

From the project README

Unity C# Skill

Version: 2.0 Stack: Unity, C#

Patterns for writing clean, performant Unity C# code. Includes VR/mobile optimization.


Scope and Boundaries

This skill covers:

  • MonoBehaviour lifecycle and component architecture
  • Unity-specific C# patterns (caching, events, coroutines, null safety)
  • Performance optimization (draw calls, batching, LODs, pooling)
  • VR/mobile performance targets and profiling
  • ScriptableObject usage

Defers to other skills:

  • vrc-udon: VRChat-specific scripting (UdonSharp)
  • vrc-worlds: VRChat world setup and limits
  • vrc-avatars: VRChat avatar setup and limits

Use this skill when: Writing C# scripts for Unity, or optimizing Unity performance for VR/mobile.


Core Principles

  1. Composition Over Inheritance — Small, focused components.
  2. Avoid Update() When Possible — Event-driven or coroutines instead.
  3. Cache References — GetComponent is expensive; cache in Awake.
  4. ScriptableObjects for Data — Decouple data from behavior.
  5. Null-Safe Access — Unity objects can be destroyed at any time.
  6. Measure First — Profile before optimizing; gut feelings lie.
  7. Batch Aggressively — Same material = potential batch. Draw calls matter most in VR.

Patterns

Reference Caching
public class PlayerController : MonoBehaviour
{
    private Rigidbody _rb;
    private Animator _animator;

    [SerializeField] private Transform _cameraTarget;

    private void Awake()
    {
        _rb = GetComponent<Rigidbody>();
        _animator = GetComponent<Animator>();
    }

    private void FixedUpdate()
    {
        _rb.AddForce(Vector3.up);
    }
}
Event System (ScriptableObject)
[CreateAssetMenu(menuName = "Events/Game Event")]
public class GameEvent : ScriptableObject
{
    private readonly List<GameEventListener> _listeners = new();

    public void Raise()
    {
        for (int i = _listeners.Count - 1; i >= 0; i--)
            _listeners[i].OnEventRaised();
    }

    public void RegisterListener(GameEventListener listener) =>
        _listeners.Add(listener);

    public void UnregisterListener(GameEventListener listener) =>
        _listeners.Remove(listener);
}

public class GameEventListener : MonoBehaviour
{
    [SerializeField] private GameEvent _event;
    [SerializeField] private UnityEvent _response;

    private void OnEnable() => _event.RegisterListener(this);
    private void OnDisable() => _event.UnregisterListener(this);
    public void OnEventRaised() => _response.Invoke();
}
Null-Safe Pattern
// Unity overloads == for destroyed objects
if (_target != null)
{
    _target.DoSomething();
}

// Best: explicit destroyed check
if (_target != null && !_target.Equals(null))
{
    _target.DoSomething();
}
Coroutine Pattern
private IEnumerator FadeOut(float duration)
{
    float elapsed = 0f;
    Color startColor = _renderer.material.color;

    while (elapsed < duration)
    {
        elapsed += Time.deltaTime;
        float t = elapsed / duration;
        _renderer.material.color = Color.Lerp(startColor, Color.clear, t);
        yield return null;
    }

    gameObject.SetActive(false);
}
Object Pooling
public class ObjectPool : MonoBehaviour
{
    [SerializeField] private GameObject _prefab;
    [SerializeField] private int _initialSize = 10;

    private Queue<GameObject> _pool = new();

    private void Awake()
    {
        for (int i = 0; i < _initialSize; i++)
        {
            var obj = Instantiate(_prefab);
            obj.SetActive(false);
            _pool.Enqueue(obj);
        }
    }

    public GameObject Get()
    {
        if (_pool.Count == 0)
            return Instantiate(_prefab);

        var pooled = _pool.Dequeue();
        pooled.SetActive(true);
        return pooled;
    }

    public void Return(GameObject obj)
    {
        obj.SetActive(false);
        _pool.Enqueue(obj);
    }
}
Static Batching
gameObject.isStatic = true;

// Or specific flags
GameObjectUtility.SetStaticEditorFlags(gameObject,
    StaticEditorFlags.BatchingStatic |
    StaticEditorFlags.OcclusionStatic);

VR Performance Targets

MetricQuest 2Quest 3PC VR
Draw Calls<100<150<200
Triangles<100K<150K<1M
Frame Time<14ms (72fps)<11ms (90fps)<11ms (90fps)
Texture Memory<200MB<500MB<1GB
LOD Configuration
LOD 0: 100% triangles (0-10m)
LOD 1: 50% triangles (10-25m)
LOD 2: 25% triangles (25-50m)
Culled: 0 triangles (50m+)
Material Atlasing
Before: 20 objects x 20 materials = 20 draw calls (no batching)
After:  20 objects x 1 atlas material = 1 draw call (batched)

Anti-Patterns

Anti-PatternProblemFix
GetComponent in UpdateExpensive every frameCache in Awake
Find or FindObjectOfTypeSlow, fragileInject references or use events
Heavy Update loopsPerformance drainUse events, coroutines, or FixedUpdate
String comparisons for tagsTypo-prone, slowUse CompareTag or constants
Public fields for everythingNo encapsulationUse [SerializeField] private
Unique material per objectNo batching possibleShare materials, use atlases
No LODsFull detail at any distanceAdd LOD groups
Instantiate/Destroy in gameplayGC spikes, stuttersObject pooling
Realtime lights everywhereExpensive shadowsBake lighting, limit realtime
No occlusion cullingRender hidden objectsBake occlusion data

Checklist

Code Quality
  • References cached in Awake
  • No GetComponent in Update/FixedUpdate
  • No Find methods in runtime code
  • ScriptableObjects for shared data
  • Events for decoupled communication
  • Null checks for destroyable objects
Performance
  • Static objects marked static
  • Materials shared where possible
  • Texture atlases for small props
  • LOD groups on significant meshes
  • Occlusion culling baked
  • Object pooling for spawned objects
  • Lighting baked (not all realtime)
Profiling
  • Frame Debugger checked for draw calls
  • Profiler run for CPU spikes
  • Memory Profiler checked for leaks
  • Tested on target device (not just editor)

References

  • references/lifecycle.md — MonoBehaviour lifecycle and execution order
  • references/profiling.md — Unity Profiler usage and interpretation

Assets

  • assets/component-checklist.md — Unity component design checklist
  • assets/vr-performance-limits.md — VR platform performance limits and targets

Comments

Markdown supported