unitydiff
v0.1.0
Published
Human-readable diffs for Unity scene, prefab, and asset files
Maintainers
Readme
unitydiff
Human-readable diffs for Unity projects. Stop staring at incomprehensible YAML — see what actually changed.
Assets/Scenes/Level3.unity
Canvas / TopPanel / ScoreText
~ PlayerUI
~ fontSize: 36 → 42
~ color: rgba(1, 1, 1, 1) → rgba(1, 0.9, 0, 1)
Player
+ Added BoxCollider2D
~ Transform
~ localPosition: (0, 0, 0) → (2.5, 0, 0)
~ PlayerController
~ maxHealth: 100 → 150
+ dashCooldown: 0.5The problem
Unity stores scenes, prefabs, and assets as multi-document YAML. When you git diff a scene file, you get hundreds of lines of noise like:
m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalPosition: {x: 2.5, y: 0, z: 0}Nobody on your team knows what that means without opening Unity. Designers, artists, and producers are locked out of understanding what changed.
unitydiff parses Unity's YAML format semantically, matches objects by their persistent fileID, and tells you in plain English: "Player's position changed from (0, 0, 0) to (2.5, 0, 0)".
Four ways to use it
1. GitHub Action (automatic PR comments)
Add unitydiff to any Unity project. Every PR that touches .unity, .prefab, or .asset files gets an automatic comment with the human-readable diff.
# .github/workflows/unitydiff.yml
name: Unity Diff
on:
pull_request:
paths: ['**/*.unity', '**/*.prefab', '**/*.asset']
permissions:
contents: read
pull-requests: write
jobs:
diff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: drLemis/unitydiff@mainThe action posts a collapsible Markdown comment with hierarchy paths, human-readable names, and change summaries. If no Unity files changed, it stays silent.
2. Web UI (no install, no CLI)
Open the web UI → — works for designers, artists, and producers who don't use the command line.
Features:
- Drag & drop two Unity files to compare them instantly
- Git integration — connect to GitHub, GitLab, or Gitea/Forgejo repos, pick branches and commits, compare directly
- Hierarchy paths — see "Canvas / TopPanel / ScoreText" instead of just "ScoreText"
- Scene hierarchy tree — visual tree view showing the full object hierarchy with changed nodes highlighted
- Collapsible sections with change count badges
- Copy as Markdown — one click to copy the diff for pasting into issues/docs
- Runs entirely in your browser — no files are uploaded anywhere
- Works offline — save the HTML file and open it locally
3. Git diff driver (automatic git diff)
Make git diff use unitydiff automatically for Unity files:
npx unitydiff setup # configures local repo
npx unitydiff setup --global # configures all reposThis sets diff.unitydiff.command in your git config and adds the right .gitattributes rules. After that, git diff produces human-readable output for .unity, .prefab, and .asset files instead of raw YAML noise.
4. CLI
npm install -g unitydiffOr use without installing:
npx unitydiff HEAD~1 HEADCLI usage
Compare two git refs
unitydiff HEAD~1 HEAD # Last commit vs current
unitydiff main feature/new-enemies # Compare branches
unitydiff HEAD~1 HEAD --scenes # Only .unity files
unitydiff HEAD~1 HEAD --prefabs # Only .prefab files
unitydiff HEAD~1 HEAD --assets # Only .asset filesCompare two files directly
unitydiff old/MainScene.unity new/MainScene.unityOutput formats
unitydiff HEAD~1 HEAD # Colored terminal (default)
unitydiff HEAD~1 HEAD -f markdown # GFM markdown
unitydiff HEAD~1 HEAD -f json # Structured JSON
unitydiff HEAD~1 HEAD --summary # Just countsFilter out noisy properties
unitydiff HEAD~1 HEAD --ignore m_LocalRotation m_LocalScaleTeams that don't care about rotation/scale changes can silence them entirely.
Supported file types
| Extension | Type | Supported |
|-----------|------|-----------|
| .unity | Scene files | Yes |
| .prefab | Prefab files | Yes |
| .asset | ScriptableObject assets | Yes |
What it detects
- Added/removed GameObjects — new objects in the scene
- Added/removed components — BoxCollider2D added to Player, etc.
- Property changes — position, rotation, scale, colors, numbers, strings
- MonoBehaviour field changes — your custom script fields (maxHealth, moveSpeed, etc.)
- ScriptableObject changes — game config files, data assets
- Vectors and colors — displayed as
(x, y, z)andrgba(r, g, b, a)instead of raw YAML - Hierarchy paths — full object path like "Canvas / TopPanel / ScoreText"
- Reference resolution —
{fileID: 12345}becomes "Player (Transform)" instead of an opaque number - Script name resolution — MonoBehaviour components show actual script names (e.g. "PlayerController") via
.metafile GUID lookup - Prefab variant overrides —
PrefabInstancem_Modificationblocks are flattened into individual property changes - Nested prefab instances — overrides grouped by target for multi-level prefab nesting, with added/removed component tracking
- Animation curve summaries — keyframe arrays show count + duration instead of raw data (e.g. "[200 keyframes, 2.50s]")
Resilience
unitydiff is designed to handle real-world Unity files gracefully:
- Large fileIDs — 64-bit fileIDs are stored as strings to avoid JavaScript precision loss
- Binary blobs — detected and wrapped instead of crashing the parser
- Huge arrays — AnimationClip keyframe data and similar large arrays are collapsed into summaries
- Unparseable documents — skipped instead of failing the whole file
- PrefabInstance overrides —
m_Modificationentries are flattened into diffable properties - Script name resolution —
.metafile GUIDs are resolved to actual script/asset names automatically
How it works
Unity YAML files use a tagged multi-document format. Each object starts with:
--- !u!<classID> &<fileID>- classID identifies the type (1 = GameObject, 4 = Transform, 114 = MonoBehaviour, etc.)
- fileID is a persistent unique identifier that survives edits
unitydiff:
- Splits the file into individual documents
- Parses each document's class ID and file ID (preserving large IDs as strings)
- Builds an object graph (GameObjects → Components → Properties)
- Walks the Transform hierarchy to construct full paths
- Matches objects between old/new versions by fileID
- Deep-compares properties and classifies changes
- Resolves fileID references to human-readable names
- Outputs the result in the requested format
Programmatic API
import {
parseUnityFile,
diffParsedFiles,
formatMarkdown,
createRefResolver,
buildGuidMapFromGit,
resolveMonoBehaviourNames,
} from 'unitydiff';
const oldFile = parseUnityFile(oldContent, 'Scene.unity');
const newFile = parseUnityFile(newContent, 'Scene.unity');
// Resolve MonoBehaviour script names from .meta files
const guids = buildGuidMapFromGit();
resolveMonoBehaviourNames(oldFile.objects, guids);
resolveMonoBehaviourNames(newFile.objects, guids);
const changes = diffParsedFiles(oldFile, newFile);
const resolver = createRefResolver(oldFile.objects, newFile.objects);
console.log(formatMarkdown([changes], resolver));Roadmap
- [x] CLI with terminal, markdown, and JSON output
- [x] Web viewer with drag-and-drop comparison
- [x] GitHub/GitLab/Gitea integration in the web UI
- [x] Hierarchy paths for full object context
- [x] Human-readable reference resolution
- [x] Collapsible sections in web UI and markdown
- [x] GitHub Action for automatic PR comments
- [x]
--ignoreflag for filtering noisy properties - [x] Large fileID precision (string-based storage)
- [x] Parser resilience (binary blobs, huge arrays, corrupt documents)
- [x] Git diff driver (
unitydiff setupfor.gitattributesintegration) - [x]
.metafile GUID → script name resolution - [x] Prefab variant/override detection
- [x] Nested prefab instance diffing
- [x] Animation curve summaries (keyframe count + duration)
- [x] Scene hierarchy tree view in web UI
- [x] CI pipeline (test on Node 18/20/22, auto-publish on tags)
- [x] Integration test suite (85 tests, performance benchmarks)
License
MIT
