plugins/unity-master/skills/unity-editor-tooling/SKILL.md
Unity Editor tooling, build automation, and asset pipeline customization. PROACTIVELY activate for: (1) writing custom Editor scripts, (2) custom inspectors and PropertyDrawer attributes, (3) EditorWindow creation, (4) ScriptedImporter for custom asset types, (5) build pipeline scripting (BuildPipeline.BuildPlayer, IBuildPostprocessor), (6) platform-switching automation, (7) CI/CD for Unity (GameCI, GitHub Actions, Unity Build Automation), (8) Assembly Definition (.asmdef) organization, (9) preprocessor symbols and platform defines, (10) Editor-only code with #if UNITY_EDITOR. Provides: custom inspector templates, EditorWindow examples, build script patterns, GameCI setup, .asmdef best practices, and CI YAML for Unity builds.
npx skillsauth add JosiahSiegel/claude-plugin-marketplace unity-editor-toolingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Reference for extending the Unity Editor, automating builds, testing, version control configuration, and package development. Covers custom inspectors, editor windows, build pipeline scripting, CI/CD, and the Unity Test Framework.
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(EnemySpawner))]
public class EnemySpawnerEditor : Editor
{
SerializedProperty spawnPoints;
SerializedProperty enemyPrefab;
SerializedProperty spawnInterval;
void OnEnable()
{
spawnPoints = serializedObject.FindProperty("_spawnPoints");
enemyPrefab = serializedObject.FindProperty("_enemyPrefab");
spawnInterval = serializedObject.FindProperty("_spawnInterval");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(enemyPrefab);
EditorGUILayout.Slider(spawnInterval, 0.1f, 10f, new GUIContent("Spawn Interval"));
EditorGUILayout.Space();
EditorGUILayout.LabelField("Spawn Points", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(spawnPoints, true);
if (GUILayout.Button("Add Spawn Point at Origin"))
{
spawnPoints.InsertArrayElementAtIndex(spawnPoints.arraySize);
var newElement = spawnPoints.GetArrayElementAtIndex(spawnPoints.arraySize - 1);
newElement.vector3Value = Vector3.zero;
}
serializedObject.ApplyModifiedProperties();
}
void OnSceneGUI()
{
var spawner = (EnemySpawner)target;
// Draw handles in scene view for each spawn point
for (int i = 0; i < spawner.SpawnPointCount; i++)
{
Vector3 point = spawner.GetSpawnPoint(i);
Vector3 newPoint = Handles.PositionHandle(point, Quaternion.identity);
if (point != newPoint)
{
Undo.RecordObject(spawner, "Move Spawn Point");
spawner.SetSpawnPoint(i, newPoint);
}
}
}
}
#endif
Key rules:
#if UNITY_EDITOR or place in Editor/ foldersSerializedProperty for undo/redo support and multi-object editingserializedObject.Update() before and ApplyModifiedProperties() after changesUndo.RecordObject() before direct modifications[CustomPropertyDrawer(typeof(MinMaxRange))]
public class MinMaxRangeDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
var min = property.FindPropertyRelative("min");
var max = property.FindPropertyRelative("max");
float minVal = min.floatValue;
float maxVal = max.floatValue;
position = EditorGUI.PrefixLabel(position, label);
EditorGUI.MinMaxSlider(position, ref minVal, ref maxVal, 0f, 100f);
min.floatValue = minVal;
max.floatValue = maxVal;
EditorGUI.EndProperty();
}
}
Use PropertyDrawers for reusable field-level customization. Use CustomEditors for component-level customization.
public class LevelEditorWindow : EditorWindow
{
[MenuItem("Tools/Level Editor")]
static void ShowWindow() => GetWindow<LevelEditorWindow>("Level Editor");
Vector2 scrollPos;
string searchFilter = "";
void OnGUI()
{
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
searchFilter = EditorGUILayout.TextField(searchFilter, EditorStyles.toolbarSearchField);
if (GUILayout.Button("Refresh", EditorStyles.toolbarButton, GUILayout.Width(60)))
RefreshData();
EditorGUILayout.EndHorizontal();
scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
// Draw content
EditorGUILayout.EndScrollView();
}
void OnSelectionChange() => Repaint(); // React to selection changes
}
Use EditorWindow for standalone tools. Use [MenuItem] for menu bar integration. Override OnSelectionChange, OnHierarchyChange, OnProjectChange for reactive updates.
[ScriptedImporter(1, "leveldata")]
public class LevelDataImporter : ScriptedImporter
{
public override void OnImportAsset(AssetImportContext ctx)
{
string json = File.ReadAllText(ctx.assetPath);
var levelData = ScriptableObject.CreateInstance<LevelData>();
JsonUtility.FromJsonOverwrite(json, levelData);
ctx.AddObjectToAsset("main", levelData);
ctx.SetMainObject(levelData);
}
}
Register custom file extensions. Unity re-imports automatically when the source file changes.
public static class BuildScript
{
[MenuItem("Build/Build Windows")]
public static void BuildWindows()
{
var options = new BuildPlayerOptions
{
scenes = EditorBuildSettings.scenes
.Where(s => s.enabled)
.Select(s => s.path).ToArray(),
locationPathName = "Builds/Windows/Game.exe",
target = BuildTarget.StandaloneWindows64,
options = BuildOptions.None
};
var report = BuildPipeline.BuildPlayer(options);
if (report.summary.result != BuildResult.Succeeded)
throw new Exception($"Build failed: {report.summary.totalErrors} errors");
}
}
name: Unity Build
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
targetPlatform: [StandaloneWindows64, StandaloneLinux64, WebGL]
steps:
- uses: actions/checkout@v4
with:
lfs: true
- uses: game-ci/unity-builder@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
targetPlatform: ${{ matrix.targetPlatform }}
buildMethod: BuildScript.Build${{ matrix.targetPlatform }}
- uses: actions/upload-artifact@v4
with:
name: build-${{ matrix.targetPlatform }}
path: build/${{ matrix.targetPlatform }}
Activate a Unity license first using game-ci/unity-activate. Use Unity Build Automation (Cloud Build) as an alternative if CI runners lack capacity.
Project/
├── Scripts/
│ ├── Core/ Core.asmdef (no references)
│ ├── Gameplay/ Gameplay.asmdef (references: Core)
│ ├── UI/ UI.asmdef (references: Core, Gameplay)
│ ├── Networking/ Networking.asmdef (references: Core)
│ ├── Editor/ Editor.asmdef (references: Core; Editor-only platform)
│ └── Tests/
│ ├── EditMode/ Tests.EditMode.asmdef (references: Core; Test assemblies)
│ └── PlayMode/ Tests.PlayMode.asmdef (references: Core, Gameplay)
Benefits: Incremental compilation (only recompile changed assemblies), enforced dependency boundaries, required for testability.
Rules:
UnityEngine.TestRunner and UnityEditor.TestRunner[TestFixture]
public class InventoryTests
{
[Test]
public void AddItem_IncreasesCount()
{
var inventory = new Inventory(maxSlots: 10);
inventory.Add(new Item("Sword", 1));
Assert.AreEqual(1, inventory.Count);
}
[Test]
public void AddItem_WhenFull_ReturnsFalse()
{
var inventory = new Inventory(maxSlots: 1);
inventory.Add(new Item("Sword", 1));
Assert.IsFalse(inventory.Add(new Item("Shield", 1)));
}
}
[UnityTest]
public IEnumerator Player_TakesDamage_HealthDecreases()
{
var player = new GameObject().AddComponent<PlayerHealth>();
player.Initialize(100);
player.TakeDamage(30);
yield return null; // Wait one frame
Assert.AreEqual(70, player.CurrentHealth);
}
Run tests via Window > General > Test Runner. Edit Mode tests run instantly. Play Mode tests enter play mode and can test MonoBehaviour logic, coroutines, and physics.
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Uu]ser[Ss]ettings/
/[Mm]emoryCaptures/
/[Rr]ecordings/
*.csproj
*.sln
*.suo
*.user
*.pidb
*.booproj
*.unityproj
.gitattributes with *.unity merge=unityyamlmergecom.company.my-package/
├── package.json
├── Runtime/
│ ├── com.company.my-package.asmdef
│ └── MyScript.cs
├── Editor/
│ ├── com.company.my-package.editor.asmdef
│ └── MyEditorScript.cs
├── Tests/
│ ├── Runtime/
│ └── Editor/
├── Documentation~/
├── CHANGELOG.md
└── README.md
Install local packages via manifest.json: "com.company.my-package": "file:../../Packages/my-package" or via git URL.
references/editor-recipes.md -- Advanced editor patterns: Gizmos, Handles, SceneView overlays, custom menus, asset post-processors, build hooks (IPreprocessBuildWithReport), serialization callbacks, Terrain and ProBuilder scripting, multi-scene editing workflowsdevelopment
This skill should be used when the user asks to train, debug, scale, or improve ML models. PROACTIVELY activate for: (1) PyTorch, TensorFlow/Keras, JAX, Flax, Hugging Face Trainer/Accelerate training loops, (2) distributed training, DDP/FSDP/DeepSpeed, TPU/GPU setup, (3) mixed precision AMP/bf16, gradient accumulation, checkpointing, seeding, (4) overfitting, imbalance, loss functions, regularization, LR schedules, warmup, (5) memory optimization, gradient checkpointing, offloading, quantization-aware training. Provides: reproducible training best practices across deep learning and classical ML.
development
This skill should be used when the user asks to productionize, track, version, govern, monitor, or automate ML systems. PROACTIVELY activate for: (1) MLflow, Weights & Biases, Neptune, Comet, ClearML experiment tracking, (2) model registry, model versioning, artifact lineage, reproducibility, (3) Kubeflow, SageMaker Pipelines, Vertex AI Pipelines, Azure ML pipelines, Databricks workflows, (4) CI/CD, continuous training/evaluation, A/B tests, canary/shadow deployments, (5) drift detection, model monitoring, data validation, responsible AI governance. Provides: end-to-end MLOps architecture and operational safeguards.
development
This skill should be used when the user asks to optimize, export, serve, compress, or accelerate ML inference. PROACTIVELY activate for: (1) latency, throughput, p95/p99, batching, concurrency, KV cache, memory, or cost issues, (2) quantization INT8/INT4, GPTQ, AWQ, bitsandbytes, pruning, sparsity, distillation, (3) ONNX export, ONNX Runtime, TensorRT, TorchScript, torch.compile, XLA, OpenVINO, Core ML, TFLite, (4) Triton, TorchServe, TF Serving, BentoML, Seldon, KServe configuration, (5) edge deployment, CPU/GPU/TPU/Inferentia serving. Provides: hardware-aware inference optimization and safe benchmarking.
testing
This skill should be used when the user asks to tune hyperparameters, run sweeps, optimize search spaces, or use AutoML. PROACTIVELY activate for: (1) Optuna, Ray Tune, FLAML, AutoGluon, Hyperopt, Nevergrad, KerasTuner, W&B sweeps, (2) grid search, random search, Bayesian optimization, TPE, Gaussian processes, evolutionary search, (3) ASHA, Hyperband, successive halving, multi-fidelity optimization, population-based training, (4) learning-rate finder, batch-size search, early stopping, pruning, (5) reproducible sweep design and experiment analysis. Provides: budget-aware hyperparameter search strategy.