← UnityCONTENT HISTORY

Update to Unity

Snapshot Sep 30, 2026 · 23:16 UTC · version 0.1.6-beta

Collection source: not recorded for this historical snapshot.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "description": "Sets up, diagnoses, and fixes pixel perfect 2D rendering in Unity projects. Use when working on any retro-style or pixel art 2D game.",
  "included_files": [
    {
      "relative_path": "references/api-reference.md",
      "size_in_bytes": 4149
    },
    {
      "relative_path": "references/camera-setup-builtin.cs",
      "size_in_bytes": 1726
    },
    {
      "relative_path": "references/camera-setup-urp.cs",
      "size_in_bytes": 2350
    },
    {
      "relative_path": "references/pipeline-detection.cs",
      "size_in_bytes": 2223
    },
    {
      "relative_path": "references/sprite-settings.cs",
      "size_in_bytes": 1362
    }
  ],
  "name": "2d-pixel-perfect",
  "skill_md_contents": "---\nname: 2d-pixel-perfect\ndescription: Sets up, diagnoses, and fixes pixel perfect 2D rendering in Unity projects. Use when working on any retro-style or pixel art 2D game.\n---\n\nSet up, diagnose, and fix pixel perfect 2D rendering in Unity projects.\n\n---\n\n## ⚠️ There Are Two Completely Separate Implementations\n\nPixel perfect rendering in Unity is **not one system** — it is two separate, incompatible implementations, one per render pipeline. **Always detect the pipeline before writing or diagnosing any code.** \n\n| | URP | Built-in |\n|---|---|---|\n| **Component** | `UnityEngine.Rendering.Universal.PixelPerfectCamera` | `UnityEngine.U2D.PixelPerfectCamera` |\n| **Package** | Built into URP — no extra install | `com.unity.2d.pixel-perfect` v6.0.0+ |\n| **API style** | Enums (`gridSnapping`, `cropFrame`) | Booleans (`pixelSnapping`, `upscaleRT`, `cropFrameX/Y`) |\n\n**Do not install `com.unity.2d.pixel-perfect` in a URP project.**\n\n**→ Always call `DetectPipeline()` first** (`references/pipeline-detection.cs`), then branch your setup, diagnostics, and fixes based on the result.\n\n---\n\n## When NOT to use this skill\n\n- **HD 2D or high-resolution 2D games** — pixel snapping and point filtering will make smooth art look wrong\n- **UI-only scenes** — use Canvas Scaler instead\n- **HDRP projects** — Pixel Perfect Camera is not supported\n\n---\n\n## Critical Reminders\n\n⚠️ **Detect the render pipeline first** — URP and Built-in use different Pixel Perfect Camera components that are not interchangeable.\n⚠️ **Filter Mode = Point is the #1 fix** — bilinear filtering is Unity's default and is almost always the cause of blurry sprites.\n⚠️ **Anti-Aliasing must be disabled** — in Quality Settings and on the camera. AA actively blurs pixel edges.\n\n## Key Principles\n\n### 1. Pipeline Detection & Camera Component Selection\n\nSee the two-path comparison table at the top of this file. Assembly name note: the standalone Built-in package installs into a `Runtime/` folder, but the asmdef `\"name\"` field is `Unity.2D.PixelPerfect` — no `Runtime` suffix. HDRP is unsupported — see the HDRP fallback section under Common Issues.\n\n**→ Code: `references/pipeline-detection.cs`** — `DetectPipeline()`, `GetPixelPerfectCameraType()`, and migration mismatch check.\n\n### 2. Diagnostic-First Approach\n\nAlways diagnose before making changes. Report findings, then fix only what is broken.\n\n### 3. Work in the correct scope\n\nDefault to scene scope. Scan project-wide only when the user explicitly requests it.\n\n---\n\n## Diagnostic Checklist\n\n**Sprite import settings:**\n- [ ] Filter Mode = `Point (no filter)` on all in-scope sprites\n- [ ] Mip Maps = disabled\n- [ ] Compression = `None` / Uncompressed\n- [ ] PPU consistent across all sprites in scene\n- [ ] Sprite pivots set to Custom / Pixels mode — a center pivot on an odd-dimension sprite (e.g. 15×15) lands at 7.5px, causing 0.5px misalignment\n\n**→ Code: `references/sprite-settings.cs`** — `GetImporter()` and `FixSpriteImportSettings()`.\n\n**Editor snap settings:**\n- [ ] Grid Size = `1 / assetsPPU` on all axes (e.g. PPU 16 → 0.0625, PPU 100 → 0.01)\n- [ ] Grid Snapping enabled in the Grid and Snap overlay\n- [ ] To snap existing GameObjects: select them → Align Selected → All Axes\n\n**Camera setup:**\n- [ ] Camera projection = Orthographic\n- [ ] Pixel Perfect Camera component present and correct type for pipeline\n- [ ] `allowHDR`, `allowMSAA`, `allowDynamicResolution` all `false`\n- [ ] Scene view shows two green bounding boxes on the camera gizmo — solid = visible area, dotted = reference resolution\n\n**→ Code: `references/camera-setup-urp.cs`** — full URP camera + PP Camera configuration.\n**→ Code: `references/camera-setup-builtin.cs`** — Built-in standalone configuration.\n\n**Project quality settings:**\n- [ ] Anti-Aliasing = 0 in Quality Settings\n- [ ] Anisotropic Filtering = Disabled\n\n---\n\n## API Reference\n\nFull property/method tables, `GridSnapping` and `CropFrame` enum values, and recommended configurations:\n**→ `references/api-reference.md`** — read this when writing or reviewing camera setup code.\n\nQuick enum summary:\n\n**`GridSnapping`**: `None` · `PixelSnapping` (standard) · `UpscaleRenderTexture` (authentic low-res; incompatible with post-processing and UI text)\n\n**`CropFrame`**: `None` · `Pillarbox` · `Letterbox` · `Windowbox` (safest default) · `StretchFill`\n\n---\n\n## Reference Resolution\n\nChoose before building any assets. Never change after asset production starts.\n\n| Reference resolution | 1080p | 1440p | 4K |\n|---|---|---|---|\n| 320 × 180 | 6× | 8× | 12× |\n| 480 × 270 | 4× | ~5.3× | 8× |\n| 640 × 360 | 3× | 4× | 6× |\n\n320×180 is the safest general choice. For screens with no integer fit (e.g. 1366×768), use `cropFrame = Windowbox` to add black bars rather than stretching to a fractional scale.\n\n---\n\n## Migration & Compatibility\n\n### URP project with the Built-in standalone component\n\n**Symptom**: `DetectPipeline()` returns URP but camera has `UnityEngine.U2D.PixelPerfectCamera`. Symptoms are subtle because the standalone component has `ENABLE_URP` conditional code.\n\n**Fix**:\n1. Remove `com.unity.2d.pixel-perfect` from Package Manager\n2. Remove `UnityEngine.U2D.PixelPerfectCamera` from each camera\n3. Add `UnityEngine.Rendering.Universal.PixelPerfectCamera`\n4. Reconfigure — booleans (`pixelSnapping`, `upscaleRT`, `cropFrameX/Y`) become enums (`gridSnapping`, `cropFrame`)\n\n**→ Detection code: `references/pipeline-detection.cs`** (bottom of file).\n\n### Old URP namespace (pre-Unity 2022 / URP pre-13.x)\n\n**Symptom**: Compiler errors referencing `UnityEngine.Experimental.Rendering.Universal`.\n\n**Fix**: Replace `using UnityEngine.Experimental.Rendering.Universal;` with `using UnityEngine.Rendering.Universal;`. Update any assembly-qualified type strings. The `[MovedFrom]` attribute handles serialization automatically — components on GameObjects survive the upgrade.\n\n---\n\n## Common Issues & Solutions\n\n### Blurry sprites\n**Fix**: Set Filter Mode to Point on all in-scope sprites, disable Mip Maps, disable AA in Quality Settings.\n**→ Code: `references/sprite-settings.cs`**\n\n### Tilemap gaps between tiles\nWork through in order — workarounds like negative cell gap or PPU = 31.99 break when the camera moves.\n\n| # | Check | Fix |\n|---|---|---|\n| 1 | Sprite Atlas with Tight Packing off, Padding ≥ 4, Sprite Packer Mode enabled? | Enable Sprite Packer Mode in Editor settings; on the atlas set Padding ≥ 4 and turn Tight Packing off |\n| 2 | Mipmaps disabled on tileset textures and atlas? | Disable Generate Mip Maps |\n| 3 | AA = 0, MSAA off on camera? | Disable AA globally |\n| 4 | Compression = None? | RGBA 32-bit uncompressed |\n| 5 | All tile sprites have even pixel dimensions? | Odd dimensions cause 0.5px grid offset |\n| 6 | PPU = tile pixel width? (16×16 → PPU 16) | PPU mismatch leaves physical gaps |\n| 7 | Gaps only during camera movement after all above pass? | Use PP Camera pixel snapping; do not use `cellGap = -0.01f` |\n\n### Cinemachine conflict\n**Cause**: Both Cinemachine and the Pixel Perfect Camera write to orthographic size every frame.\n\n**Fix**: Add `CinemachinePixelPerfect` extension via the Add Extension dropdown on each Virtual Camera. Do not add it via `AddComponent` in code.\n\n**Known limitations**:\n- Camera blends between virtual cameras are not pixel-perfect during transitions\n- `UpscaleRenderTexture` reduces valid pixel-perfect ortho sizes, which may cause framing to deviate\n- Target Group + Framing Transposer causes visible choppiness (no fix available)\n\n### Post-processing blur with `upscaleRT`\n**Cause**: Post-processing runs after the PP Camera upscales the render texture.\n\n**Simple fix**: Disable `upscaleRT`. Post-processing then runs at native screen resolution.\n\n**Advanced fix (Unity 6 URP)**: Inject a `ScriptableRendererFeature2D` at `RenderPassEvent2D.AfterRenderingPostProcessing`. Use 2D-specific base classes — `ScriptableRendererFeature` (3D base class) is silently ignored in a URP 2D renderer.\n\n### UI text blurry with `upscaleRT`\n**Status**: Known Unity bug, declined to fix (still present Unity 6, 2025).\n\n**Root causes**: (A) Canvas renders into the low-res buffer and is upscaled with the scene. (B) TMP's SDF gradient threshold is miscalibrated at low reference resolutions.\n\n**Fixes in order of reliability**:\n1. `Screen Space - Overlay` on Canvas — bypasses the camera, renders at native resolution\n2. Dedicated UI camera with no PP Camera component, `Screen Space - Camera` mode\n3. Unity 6 only: `Font Material → Debug Settings → Sharpness = 1` (mitigates B, not A)\n\n### Physics / render desync (micro-stutter)\n**Cause**: Physics runs at a fixed timestep; interpolated positions produce fractional values that snap to different pixels each frame.\n\n**Fix**:\n- Enable `Rigidbody2D.interpolation = RigidbodyInterpolation2D.Interpolate` on physics-driven sprites\n- Set `Time.fixedDeltaTime = 1f / 60f` to match target frame rate\n- Keep camera tracking in `LateUpdate`, not `FixedUpdate`\n\n### Non-integer scaling / pixel decimation\n**Cause**: Screen resolution is not a clean integer multiple of the reference resolution.\n\n**Fix**: Choose a reference resolution from the table above. Use `cropFrame = Windowbox` when no integer fit exists.\n\n### Missing URP 2D Renderer\n**Fix**:\n1. `Assets > Create > Rendering > URP 2D Renderer Data`\n2. Assign it to your URP Asset under Renderer List\n3. Requires `com.unity.render-pipelines.universal` 12.0+\n\n### HDRP fallback\nPixel Perfect Camera is unsupported in HDRP.\n\n**Built-in / Unity 5.x**: Use `RenderTexture` + `Graphics.Blit` with `FilterMode.Point`.\n\n**Unity 6 URP**: Use `ScriptableRendererFeature2D` + `ScriptableRenderPass2D` injected at `RenderPassEvent2D.AfterRendering` with `AddRasterRenderPass`. Note: `OnRenderImage` and `Graphics.Blit` are incompatible with Unity 6's render graph.\n"
}

SHA-256 of public snapshot: 3abc9213beee292793afdeb836eaa18a2529056c537b4f05ae5e50b237535417