Back
PROJECT CLEANUP UTILITY
100% · First Class

What is Project Cleanup Utility?

Project Cleanup Utility main window // Project Cleanup Utility — main application window

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.

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.

  • Awarded 100% — First Class for GDEV50047 Tools Development — a perfect score
  • Full unused asset detection via GUID-based AssetDatabase.GetDependencies — no build required
  • Content-hash duplicate detection across 219 groups, 440 files — 14.13 MB flagged in a live TankController project scan
  • Safe quarantine workflow — moves assets to _Quarantine/ with manifest JSON, preserving original paths for full restore
  • Deletion safety ratings: Safe / Caution / Unsafe — based on reverse dependency analysis
  • Export to CSV and formatted Excel — scan report, full asset list, and dependency map sheets
  • Full accessibility layer: Colour-Blind Mode (Okabe-Ito palette), High Contrast, Font Size slider, UI Scale, keyboard navigation
  • Perforce (P4V) VCS integration — checks out, locks, and stages assets before quarantine/delete operations

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/
AssetScanner.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/
AssetInfo.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/
ProjectCleanupWindow.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/
AssetCategoryResolver.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 …

Asset Scanner

Asset scanner in progress // Asset scanner — scanning in progress

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.

Deletion safety is computed from the reverse-dependency graph:

● Safe — zero incoming references ● Caution — only ProjectSettings/BuildSettings reference it ● Unsafe — referenced by other project assets

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.

Overview Stats (TankController scan)
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
Moves assets to _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
Detects active Perforce provider via Provider.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
WhitelistConfig ScriptableObject stores exclusion rules: exact paths, folder prefixes, file extensions, and regex patterns. Persists across sessions via version control. Default exclusions for Packages/, Plugins/, StreamingAssets/, Resources/, and .cs/.asmdef/.dll.
CSV & Excel Export
Three-sheet export: Scan Report (summary stats), Asset List (Name, Category, Size, Refs, Deps, Safety, Path, GUID), and Dependency Map (asset, related asset, relationship type). Excel output is formatted and cell-styled. Respects the "Unused Only" filter toggle.
Multi-Column Asset List
Unity UI Toolkit MultiColumnListView. Sortable by Name, Type, Size, Refs, Deps, Safety, R/O, Path. Category dropdown filter. "Unused Only" toggle. Search box. Rich tooltip on each row showing file extension description. All recycled rows update safety colours via USS class swaps — never inline style.
Scan History & Comparison
Caches the previous scan result. Overview panel shows "Changes since last scan" — delta in asset count, unused count, and total size. Timestamp of last scan displayed alongside the comparison block.
Undo Support
All quarantine and restore operations register with Unity's Undo system. Ctrl+Z rolls back the last batch operation. AssetDatabase.StartAssetEditing / StopAssetEditing used to batch file moves for performance and atomicity.
Select All / Whitelist Selected
Toolbar actions for batch workflows: Select All surfaces all visible assets for action. Whitelist Selected adds all currently selected assets to WhitelistConfig in one click. Deselect All clears selection without losing scan state.

WCAG 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.

Colour-Blind Modes
Three modes using the Okabe-Ito palette — the most rigorously validated colour-blind safe palette in academic literature. Deuteranopia, Protanopia, Tritanopia. All colour swaps are USS-only, so the Safety column labels and category bars correctly update. A prior bug — inline label.style.color in C# blocking USS specificity — was fixed by moving all semantic colour to USS classes.
High Contrast Mode
A single USS class on the root element drives a full high-contrast theme — increased border widths, sharper background distinctions, elevated text brightness. Activates globally, affecting every panel and list row simultaneously.
Font Size Adjust
Live slider from –4px to +8px relative to base. Implemented via ApplyFontSize() 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
Full Tab/Enter/Arrow navigation. F5 re-scan. Ctrl+A select all. Delete key quarantines selection. Ctrl+1/2/3 tab switching. A shortcut help dialog surfaces all keybindings — bridging novice (visible buttons) and expert (keyboard-driven) usage modes, as per Norman (2013).
Key Engineering Lesson
Any element whose colour is a semantic signal — not merely decorative — must have its colour defined in USS from the start, so accessibility overrides can win. Inline label.style.color set in C# sits at the highest specificity and permanently blocks USS rules, regardless of selector complexity.

What Went Wrong

transform.scale breaking layout — The first UI Scale implementation set rootVisualElement.transform.scale to 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 via ApplyFontSize().

Safety label colours not updating in colour-blind mode — The Safety column bindCell callback was setting label.style.color directly 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.

:focus-within row highlight failing — A focused-row USS rule using :focus-within caused 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 :focus indicator was retained as a functional compromise.

Reflection The tool shipped covering scanning, categorisation, quarantine, restore, deletion, CSV/Excel export, full tab UI, comprehensive settings, and a complete accessibility layer. The one acknowledged gap: screen reader support via Unity's Accessibility hierarchy API — which is primarily designed for runtime UI and is not straightforwardly applicable to EditorWindow tooling. A future production version would also add automated contrast ratio validation at build time.