Project Cleanup Utility
A Unity 6 Editor tool that scans a project for unused and duplicate assets, rates how safe each one is to delete, and quarantines, restores or exports them — built on the Editor API and UI Toolkit.
- Type
- University Module
- Module
- GDEV50047
- Level
- 5 · Year 2
- Engine
- Unity 6 (Editor)
- Period
- Mar – May 2026
- Team
- Solo
- UI
- UI Toolkit (USS/UXML)
- C# Files
- 8
- Extensions
- 60+
What is Project Cleanup Utility?
Project Cleanup Utility is a Level 5 solo module project (GDEV50047) at Staffordshire University — a fully featured Unity 6 Editor tool for scanning, categorising, quarantining, and managing unused and duplicate assets in Unity projects. It was built entirely using the Unity Editor API and UI Toolkit, with no external dependencies or native plugins.
The tool was chosen over two other pitched alternatives (an FFmpeg video encoder and a ScriptableObject database editor) because it solves a well-documented, industry-wide pain point: Unity imports and indexes every file in the Assets folder regardless of use, silently accumulating dead weight across editor performance, version control storage, CI/CD pipelines, and developer cognitive load. No first-party Unity tool exists for this.
// Project Cleanup Utility — main application window
Development followed an iterative and incremental approach — scanning first, then quarantine, then dependency graph, then exports, then accessibility — each increment building on a working, tested foundation.
Clean Layered Design
The tool is structured across four layers — each with a single, clear responsibility. The UI layer never touches file I/O. The core layer never renders anything. Data models are plain serialisable objects with no Unity coupling. This separation made incremental development straightforward: each increment added a new layer without touching the others.
Core/
LogicAssetScanner.cs (696 lines) — GUID traversal, reverse-dependency map, string-reference heuristics, content-hash deduplication, Perforce status.
QuarantineManager.cs — move/restore/delete with manifest JSON.
DependencyGraphBuilder.cs — forward/reverse/synthetic reference queries.
Data/
ModelsAssetInfo.cs — full asset model: GUID, path, name, category, size, refs/deps lists, Safety rating, IsReadOnly, VCS status.
ScanResult.cs — aggregated scan output with computed stats.
WhitelistConfig.cs — ScriptableObject persisting path/folder/extension/regex exclusion rules.
UI/
PresentationProjectCleanupWindow.cs — EditorWindow host with three tabs: Overview, Assets, Quarantine.
ProjectCleanupUtility.uss — UI Toolkit stylesheet driving all colours, typography, and accessibility overrides.
All colour signals defined in USS — never inline C# — so colour-blind overrides work.
Utilities/
HelpersAssetCategoryResolver.cs — maps 60+ file extensions to 19 AssetCategory enum values. Returns display names and rich tooltip descriptions per extension. Centralised so scanner and UI always agree.
// AssetInfo data model — all state in one place public string Path, Name, GUID, Extension; public AssetCategory Category; public long SizeBytes; public List<string> DependsOn, ReferencedBy; public DeletionSafety Safety; // Safe / Caution / Unsafe / Unknown public bool IsWhitelisted, IsQuarantined, IsReadOnly; public VcsStatus PerforceStatus; // UpToDate / CheckedOutLocal / LockedByOther …
- AssetScanner.cs Core/
- QuarantineManager.cs Core/
- DependencyGraphBuilder.cs Core/
- AssetInfo.cs Data/
- ScanResult.cs Data/
- WhitelistConfig.cs Data/
- ProjectCleanupWindow.cs UI/
- ProjectCleanupUtility.uss UI/
- AssetCategoryResolver.cs Utilities/
Asset Scanner
AssetScanner.cs (696 lines) is the engine of the tool. It walks every asset in the project via
AssetDatabase.GetAllAssetPaths, builds a reverse-dependency map using AssetDatabase.GetDependencies, then classifies
each asset's deletion safety. A progress callback fires for every asset so the UI stays live during long scans.
The scanner accounts for string-based asset references — Resources.Load paths, Addressables keys, and serialised string fields in C# — using pre-compiled regex patterns, so assets only referenced by name rather than serialised GUID are not incorrectly flagged as unused.
// Asset scanner — scanning in progress
Deletion safety is computed from the reverse-dependency graph:
Content-hash duplicate detection groups assets by SHA-256 file content hash. Any group with two or more members is surfaced in the Overview panel with total wasted size. In a live TankController project scan: 219 hash groups, 440 duplicate files, 14.13 MB wasted.
| Value | Metric |
|---|---|
| 4264 | total assets |
| 1275 | unused |
| 1.4 GB | total size |
| 868.6 MB | unused |
| 60.6% | waste |
| 3.2s | scan time |
| 440 | duplicate files |
| 14.13 MB | in duplicate waste |
Full Feature Set
Safe Quarantine
Files_Quarantine/, preserving relative directory structure. Manifest JSON tracks original paths. Restore brings assets
back to exact original locations. Delete Permanently removes quarantined assets.Perforce VCS Integration
VCSProvider.isActive. Checks out, marks for delete, and handles LockedByOther state before any
file operation. VCS status surfaces in the asset list (UpToDate, CheckedOutLocal, LockedByOther, Added, Deleted, OutOfDate).Whitelist System
ConfigCSV & Excel Export
Export
Multi-Column Asset List
UI
Scan History & Comparison
OverviewUndo Support
SafetySelect All / Whitelist Selected
BatchWCAG 2.1-Informed Layer
The final development iteration was dedicated entirely to accessibility — a deliberate choice to ensure the tool shipped usable, not just functional. The implementation is informed by WCAG 2.1 Perceivable, Operable, and Understandable principles, and the Microsoft Inclusive Design methodology.
// Accessibility Settings — UI Scale 1.5x
Colour-Blind Modes
Perceivablelabel.style.color in C# blocking USS specificity — was fixed by moving all semantic colour to USS classes.High Contrast Mode
PerceivableFont Size Adjust
PerceivableApplyFontSize() which folds the delta into root font-size — not
transform.scale, which causes layout clipping in UI Toolkit. Persists across sessions via EditorPrefs.Keyboard Navigation
Operablelabel.style.color set in C# sits at the highest specificity and permanently
blocks USS rules, regardless of selector complexity.What Went Wrong
-
Bug 01
transform.scale breaking layout
The first UI Scale implementation set
rootVisualElement.transform.scaleto a Vector3 scalar. UI Toolkit's layout pass runs before the render transform, so at any scale other than 1.0, the visual content and layout bounds diverge — content clips off the bottom of the window. Fixed by abandoning transform.scale entirely and folding the scale factor into the base font size viaApplyFontSize(). -
Bug 02
Safety label colours not updating in colour-blind mode
The Safety column
bindCellcallback was settinglabel.style.colordirectly in C# — three separate hardcoded RGBA values. Inline styles override all USS rules regardless of specificity. Fixed by removing all inline colour from C# and using USS safety classes (safety-safe,safety-caution,safety-unsafe) managed by the bindCell callback. -
Bug 03
:focus-within row highlight failing
A focused-row USS rule using
:focus-withincaused silent console warnings in Unity's UI Toolkit. USS does not support the :focus-within pseudo-class in the Unity runtime. The row highlight was dropped; the per-control:focusindicator was retained as a functional compromise.
Trophies Earned
AssetDatabase.GetDependencies — no build required_Quarantine/ with manifest JSON, preserving original paths for full restore




