-
Notifications
You must be signed in to change notification settings - Fork 11
Features Editor Tools Editor Tools Guide
Batch tools for the asset work Unity makes you do one asset at a time. Crop a folder of sprites, build clips from a naming convention, apply one set of import settings to 400 textures, or find the serialized field Unity is silently throwing away — 20+ editor tools in all.
Everything here lives under Tools > Wallstop Studios > Unity Helpers unless stated otherwise. Two
tools also expose a public C# API you can drive from your own editor scripts:
Texture Settings Applier and
Sprite Settings Applier.
| I want to... | Tool |
|---|---|
| Strip transparent padding off a folder of sprites | Sprite Cropper |
| Apply one set of import settings to many textures | Texture Settings Applier |
| Apply different sprite settings per folder or name | Sprite Settings Applier |
| Stop guessing texture max sizes | Fit Texture Size |
| Put pivots on the visual center of mass | Sprite Pivot Adjuster |
| Upscale a batch of PNGs | Texture Resizer |
| Blur backgrounds for a UI pause menu | Image Blur Tool |
Turn Run_0.png ... Run_7.png into a clip |
Animation Creator |
| Turn a sliced sheet into several clips | Sprite Sheet Animation Creator |
| Split a sheet back into individual PNGs | Sprite Sheet Extractor |
| Change the timing or frame order of a clip | Sprite Animation Editor |
| Add footstep / hitbox events to a clip | Animation Event Editor |
| Sync clips between two folders | Animation Copier |
| Build a sprite atlas from a regex or a label | Sprite Atlas Generator |
| Catch broken prefabs before they ship | Prefab Checker |
Catch a missing override on a lifecycle method |
Unity Method Analyzer |
| Find a field Unity is silently not serializing | Serialized Field Validator |
| See everything wrong with the project at once | Asset Validation |
| React to assets being created or deleted | Asset Change Detection |
| Recompile without touching a file | Request Script Compilation |
| Keep failing test output after the run | Failed Tests Exporter |
| Start a test run a script outside the editor polls | Test Run Reporter |
Inspector attributes ([WGroup], [WButton], [WEnumToggleButtons], [WNotNull] and friends) are
covered in the Inspector documentation. The drawers documented
here are the ones these tools use most.
Tools > Wallstop Studios > Unity Helpers > Image Blur
You need a blurred copy of a background so the pause menu can sit on top of it without a render texture. This applies a Gaussian blur to a batch of images and writes the results next to the originals.
- Drag your background textures (or the folder holding them) onto Drag & Drop Images/Folders Here.
- Set Blur Radius — the slider runs
1to200;10is a soft haze,50is a heavy frost. - Click Apply Blur.
Each source produces a new file beside it; the originals are left alone:
Assets/UI/Backgrounds/
pause_bg.png # untouched
pause_bg_blurred_24.png # written by the tool
.jpg and .jpeg sources stay JPEG; every other format is written as PNG. Re-running at the same
radius appends _1, _2 and so on rather than overwriting.
Before you run it: the tool sets Read/Write Enabled and Compression: Uncompressed on every
source texture it reads and does not put them back. Re-apply your import settings afterwards, or run
Texture Settings Applier over the folder.
Visual Demo
Adjusting blur radius from 0 to 200 pixels on a UI background texture
Tools > Wallstop Studios > Unity Helpers > Sprite Cropper
Art tools export the whole canvas, so a 40-pixel-tall character often ships inside a 256x256 texture that is mostly transparency. Sprite Cropper trims each texture to its alpha bounds, moves the pivot so the sprite does not shift in the scene, and shrinks the 9-slice border by the same amount.
- Drop
Assets/Sprites/Charactersinto Input directories. - Leave Sprite Name Regex at
.*, or narrow it (^player_) to crop one character. - Set Left/Right/Top/Bottom Padding to
2if a shader samples outside the sprite (outlines, glow); otherwise leave them at0. - Tick Only Necessary so already-tight sprites are skipped.
- Click Find Sprites To Process, then Process N Sprites.
Results are written beside the source, or into Output Directory if you set one:
Assets/Sprites/Characters/
player_idle_0.png # 256x256, mostly transparency
Cropped_player_idle_0.png # 48x64, same pivot, sits in the same place in-scene
Overwrite Originals writes in place instead.
Before you run it:
- Output is always PNG bytes. In overwrite mode a
.jpgsource keeps its.jpgname and holds PNG data. - Only
Sprite Import Mode: Singletextures are cropped. Multi-sprite sheets are reported and skipped — run Sprite Sheet Extractor first if you need them split. - There is no undo, so commit before you run it.
- The collapsed Danger Zone at the bottom rewrites
.prefab,.unity,.asset,.mat,.animand.overrideControllerfiles to point at theCropped_*sprites. It makes you tick "I understand the risks and want to proceed." first, and it is the one action here you cannot walk back without version control.
Visual Demo
Before and after: transparent padding removed while preserving sprite content and pivot
Cropping first also makes Sprite Atlas Generator pack tighter.
Tools > Wallstop Studios > Unity Helpers > Texture Settings Applier
An artist drops 200 tiles into the project and every one arrives on Unity's defaults — bilinear filtering on pixel art, mipmaps you do not want, 8192 max size. This window applies one set of importer settings to every texture under a folder, with per-platform overrides.
- Drag
Assets/Sprites/Tilesinto Directory Sources (or add individual textures under Specific Textures). - Tick Apply Filter Mode and choose
Point; tick Apply MipMaps and leave Generate MipMaps off. - Under Default Platform Settings, set Max Texture Size to
2048and Compression toCompressedHQ. That group has no apply toggles — whatever it shows is written. - Click Calculate Stats — it reports
Textures to processandTextures that will change, and Preview (N) lists the first 200 paths. - Click Apply Settings to Textures.
Settings that tend to travel together:
| For | Filter Mode | Wrap Mode | Generate MipMaps | Compression |
|---|---|---|---|---|
| Pixel art and UI | Point |
Clamp |
off | CompressedHQ |
| Character sprites | Bilinear |
Clamp |
off | CompressedHQ |
| Tiling world textures | Trilinear |
Repeat |
on | CompressedHQ |
Platform Overrides adds an entry per platform (Standalone, Android, iPhone, WebGL,
Switch, ...). Each entry has its own apply toggles, so you can cap Android at 1024 while
Standalone keeps 2048.
Nothing on disk is rewritten — only import settings — and the change is recorded as a single
Apply Texture Settings undo step. Require Changes Before Apply (on by default) skips the
reimport entirely when nothing would differ.
The same logic is public, so a build step or a custom importer can use it directly:
using UnityEditor;
using UnityEngine;
using WallstopStudios.UnityHelpers.Editor.Sprites;
public static class TileImportStandard
{
public static void ApplyTo(string assetPath)
{
TextureSettingsApplierAPI.Config config = new()
{
applyFilterMode = true,
filterMode = FilterMode.Point,
applyMipMaps = true,
generateMipMaps = false,
applyPlatformMaxTextureSize = true,
platformMaxTextureSize = 2048,
platformOverrides = new[]
{
new TextureSettingsApplierAPI.PlatformOverride
{
name = "Android",
applyMaxTextureSize = true,
maxTextureSize = 1024,
},
},
};
if (!TextureSettingsApplierAPI.WillTextureSettingsChange(assetPath, in config))
{
return;
}
if (
TextureSettingsApplierAPI.TryUpdateTextureSettings(
assetPath,
in config,
out TextureImporter importer
)
)
{
importer.SaveAndReimport();
}
}
}Config is a struct with no defaults, so every field you care about must be set explicitly, and the
API never calls SaveAndReimport() for you — that is deliberate, so you can batch a whole folder
inside one AssetDatabase.StartAssetEditing() block. The default-platform name string is
"DefaultTexturePlatform".
Visual Reference
Texture Settings Applier with filter mode, wrap mode, and compression options
Tools > Wallstop Studios > Unity Helpers > Sprite Pivot Adjuster
A walk cycle where the character leans forward on some frames wobbles if every pivot is (0.5, 0.5),
because the geometric center of the texture is not the visual center of the character. This computes
an alpha-weighted center of mass per sprite and writes it as a custom pivot.
- Add
Assets/Sprites/Characters/Playerto Input Directories. - Leave Alpha Cutoff at
0.01so anti-aliased fringe pixels do not drag the pivot outward. - Leave Skip Unchanged (fuzzy) on — it avoids reimporting when the pivot moves less than
0.001. - Click Find Sprites To Process, then Dry Run to see the counts, then Adjust Pivots in Directory.
Import settings only; each changed importer is recorded as an Adjust Sprite Pivot undo step.
Before you run it:
- Single-sprite textures only.
- Textures without
Read/Write Enabledare skipped, not fixed. Turn Read/Write on with Texture Settings Applier first. - This window shares its remembered directory list with Sprite Cropper.
Visual Reference
Sprite Pivot Adjuster with alpha cutoff slider and directory selection
Tools > Wallstop Studios > Unity Helpers > Sprite Settings Applier
Same idea as Texture Settings Applier, but sprite-specific (pixels per
unit, pivot, sprite mode, extrude) and driven by profiles — so ui_ sprites can import at 100 PPU
with bilinear filtering while everything in Assets/Sprites/World imports at 16 PPU with point
filtering, in one pass.
- Drag
Assets/Spritesinto Directory Sources. - Under Sprite Settings Profiles, add one profile per rule. Each has Match By
(
Any,NameContains,PathContains,Regex,Extension), Match Pattern, and a Priority — the highest matching priority wins. - Tick only the
Apply ...toggles you want; each one reveals its value field. - Calculate Stats, then Apply Settings to Sprites.
Save Profiles Asset writes the rule set to a SpriteSettingsProfileCollection asset so the rest
of the team gets the same rules; Load Profiles Asset reads one back. There is no
Assets > Create entry for that asset — the button is how you make one.
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using WallstopStudios.UnityHelpers.Editor.Sprites;
public static class SpriteImportStandard
{
private static readonly List<SpriteSettings> Profiles = new()
{
new SpriteSettings
{
matchBy = SpriteSettings.MatchMode.PathContains,
matchPattern = "sprites/world",
priority = 1,
applyPixelsPerUnit = true,
pixelsPerUnit = 16,
applyFilterMode = true,
filterMode = FilterMode.Point,
},
new SpriteSettings
{
matchBy = SpriteSettings.MatchMode.NameContains,
matchPattern = "ui_",
priority = 5,
applyPixelsPerUnit = true,
pixelsPerUnit = 100,
applyFilterMode = true,
filterMode = FilterMode.Bilinear,
},
};
public static void ApplyTo(string assetPath)
{
List<SpriteSettingsApplierAPI.PreparedProfile> prepared =
SpriteSettingsApplierAPI.PrepareProfiles(Profiles);
if (!SpriteSettingsApplierAPI.WillTextureSettingsChange(assetPath, prepared))
{
return;
}
if (
SpriteSettingsApplierAPI.TryUpdateTextureSettings(
assetPath,
prepared,
out TextureImporter importer
)
)
{
importer.SaveAndReimport();
}
}
}PrepareProfiles compiles the regexes once — hoist it out of the per-asset loop. NameContains
matches the file name, PathContains and Regex match the full asset path, and Regex is always
case-insensitive. Applying a pivot also forces Sprite Alignment to Custom.
Visual Reference
Sprite Settings Applier with profile matching modes and import settings
Tools > Wallstop Studios > Unity Helpers > Texture Resizer
Scales PNGs up on disk. Reach for this when the source art is genuinely too small for the resolution you ship at and you want the bigger pixels baked into the file rather than paid for at runtime.
- Drag a folder into Texture Source Paths, or add textures to Textures.
- Pick Scaling Resize Algorithm:
Pointfor pixel art (no blur),Bilinearfor everything else. - Set Num Resizes — each pass grows the texture by
width / (Pixels Per Unit * Width Multiplier)(and the same for height), so several small passes scale more gently than one large one. - Tick Dry Run and click Resize — the console logs
[DryRun] Would resize <name> to [WxH]for every match. - Clear Dry Run and click Resize for real.
Before you run it:
- Only
.pngfiles are processed; anything else is counted as skipped. - With Output Folder empty this overwrites the originals in place and there is no undo. Set Output Folder to write copies instead.
- The stock multipliers (
0.54width,0.245height) grow a texture non-uniformly — a 128x128 becomes 130x133 in one pass. Set both to the same value if you want a square scale. - The final size is clamped to 16384 on each axis.
Visual Reference
Texture Resizer with bilinear/point algorithm selection and multiplier settings
Tools > Wallstop Studios > Unity Helpers > Fit Texture Size
Every texture in a fresh project imports at Max Size: 2048, whatever its real dimensions. A 64x64
icon wastes an import slot; a 4096-wide sky is silently halved. This reads each source file's actual
dimensions and sets Max Size to the power of two that fits.
-
Add
Assets/Spritesto the source list (the window pre-fills it if that folder exists). -
Choose a Fit Mode:
Mode Effect GrowAndShrinkSmallest power of two that fits the source. The usual choice. GrowOnlyRaise Max Sizewhen the source is bigger; never lower it.ShrinkOnlyLower Max Sizeto the tightest fit; never raise it.RoundToNearestNearest power of two to the source size, ties rounding up. -
Narrow the run if you want to: Only Current Selection, Only Sprites, Name Filter (substring, or a regex with Use Regex), Label Filter (CSV).
-
Set Min Allowed Size / Max Allowed Size to keep results inside a range (defaults
32and8192). -
Click Calculate Potential Changes. You get
N textures would be modified ... Grows: G, Shrinks: S, Unchanged: U. -
Click Run Fit Texture Size.
A 1920x1080 source under GrowAndShrink lands on 2048; a 64x64 source under ShrinkOnly lands on
64.
Import settings only, recorded as a Fit Texture Size undo step per asset, and cancellable from the
progress bar. Apply to Standalone / Android / iOS additionally writes a platform override with
the same size. Fit Mode is not persisted across a domain reload — re-select it after a
recompile.
Visual Reference
Fit Texture Size with GrowAndShrink/GrowOnly/ShrinkOnly mode selection
Tools > Wallstop Studios > Unity Helpers > Sprite Animation Editor
Unity's Animation window is built for curves, and reordering four sprite keyframes in it is more work than it should be. This opens a clip as a list of frames you can drag, with the animation playing next to it.
- Click Browse Clips (Multi)... and pick
PlayerWalk.anim(and any other clips you want open at the same time). - Click the clip in the left panel to make it active. The preview starts playing immediately.
- Drag a frame in the Frames panel to move it, or type a new position into its Order: field and press Enter.
- Set Preview FPS and click Apply Preview FPS to see the new speed.
- Click Save Active Clip.
Before you save: saving writes the preview FPS onto the clip and re-spaces every keyframe to match. That is usually what you want after changing the speed of a walk cycle, but it means you cannot save a reorder while leaving the original timing alone.
This is an editor for frame order and speed. Adding or removing frames is
Animation Creator's job; the X next to a loaded clip closes it in this window
rather than deleting anything. One clip previews at a time.
Visual Demo
Drag-and-drop frame reordering with real-time preview updates
Adjusting FPS and seeing immediate preview speed change
Tools > Wallstop Studios > Unity Helpers > Animation Creator
An artist hands you Player_Idle_0.png through Player_Attack_11.png — sixty files, eight
animations. Making those clips by hand is an hour of dragging, and Unity's default sort puts frame 10
before frame 2. This groups the sprites by name and writes the clips.
- Add
Assets/Sprites/Playeras a source folder. - Leave Sprite Name Regex at
.*, or narrow it (^Player_Attack) to build one clip. - Click Generate Auto-Parse Preview to see the groups it found before anything is created.
- Click Auto-Parse Matched Sprites into Animations. You get one entry per group under Animation Data.
- Set FPS and Loop per clip.
- Click Create Animations.
These naming patterns are detected without any configuration:
Player_Idle_0.png, Player_Idle_1.png -> Player_Idle, frames 0..N
slime-walk-01.png, slime-walk-02.png -> slime-walk, frames 1..N
Mage/Attack (0).png, Mage/Attack (1).png -> Attack, frames 0..N
@2x density suffixes are stripped before grouping.
If your files do not fit any of those, tick Enable Custom Group Regex and supply one with base
and index named groups. Use the Regex Tester box to check it against a real file name before
applying:
^(?<base>.*?)(?:_|\s|-)?(?<index>\d+)$ # base plus trailing digits
^Enemy_(?<base>Walk)_(?<index>\d+)$ # only Enemy_Walk_N
Where clips land: each clip is written next to the first sprite in its group, with a unique name.
There is no output folder picker — use Animation Copier to move a generated set
into Assets/Animations.
Also worth knowing:
-
Prefix Leaf Folder Name / Prefix Full Folder Path keep
Idlefrom four different characters from colliding, and Resolve Duplicate Animation Names (on by default) renames any that still do. - Frames are ordered by Unity's natural sort at creation time, so
2sorts before10. -
Framerate Mode is
Constant(one FPS, the default at12) orCurve, where anAnimationCurvedrives FPS across the clip — the Flat / Ease In / Ease Out / Sync buttons give you a starting shape. UseCurvefor an attack that snaps and then holds. - Preview plays a clip entry before you create anything.
-
Configuration Persistence saves the whole window state to
.animation-creator.jsonin a source folder, so the next person to import that folder gets your settings.
Visual Demo
One-click auto-parse: sprites grouped by naming pattern, clips generated instantly
Next: adjust the results in Sprite Animation Editor, or add events with Animation Event Editor.
Tools > Wallstop Studios > Unity Helpers > Animation Copier
Animation Creator leaves clips beside their sprites, but you keep clips in
Assets/Animations. Re-running it after an art update produces a mix of genuinely new clips,
genuinely changed clips, and dozens that are byte-for-byte what you already have. This tells the three
apart and moves only what matters.
- Set Source Path (defaults to
Assets/Sprites) and Destination Path (defaults toAssets/Animations). - Click Analyze Source & Destination.
- Read the counts: - New:, - Changed:, - Unchanged (Duplicates):.
- Expand New and Changed to review, using Filter (plus Regex) and Select All / Select None to pick what moves.
- Tick Dry Run (no changes) and run the copy once to see what it would do.
- Clear it, then click Copy New (N) or Copy Changed (N).
Copying a changed clip preserves its GUID, so every Animator that already references it keeps working.
"Changed" is decided by comparing clip contents field by field — frame rate, length, wrap mode, every curve key, every event and its parameters — not by an asset hash, so a re-import that produces an identical clip does not show up as a change.
Cleanup is where the destructive buttons live: Delete N Unchanged Source Duplicates removes the redundant copies left behind in the source folder, and Mirror Delete Destination Orphans (N) deletes destination clips with no source any more. Both honour Dry Run. Export Preview Report writes the analysis to a file if you would rather review it outside the editor.
Visual Reference
Animation Copier with new/changed/unchanged/orphan groups and copy actions
Tools > Wallstop Studios > Unity Helpers > Sprite Sheet Animation Creator
Your character is one hero.png sliced into 48 sprites in the Sprite Editor, and frames 0-7 are the
idle, 8-15 the run, 16-23 the attack. This lets you select those ranges visually and turn each into a
clip.
- Assign the sliced texture to Sprite Sheet, or click Load Sprites and pick the file.
- Drag across the thumbnails to select frames 0-7.
- Click Add Animation Definition. Name it
Hero_Idle. - Set Default FPS:, Looping: and Cycle Offset:, then hit Preview This and use ▶ Play to check it.
- Repeat for the run and attack ranges — the Start Idx: / End Idx: fields let you correct a selection by hand.
- Click Generate Animation Files and choose an output folder.
FPS Curve: takes an AnimationCurve instead of a flat rate, so an attack can hold on its impact
frame. The curve changes how far apart keyframes are placed; the generated clip's own frame rate is
always 60, which is what lets fractional timings land cleanly.
The texture must already be sliced (Sprite Mode: Multiple) — this window reads Unity's sprites, it
does not slice for you.
Visual Demo
Drag-select frame ranges on sprite sheet thumbnails with instant preview playback
Tools > Wallstop Studios > Unity Helpers > Sprite Sheet Extractor
The reverse of the tool above: take a packed sheet and write each sprite out as its own PNG. Needed whenever something downstream wants files rather than sub-assets — a third-party animation tool, or Sprite Cropper, which only handles single-sprite textures.
-
Add the folder holding your sheets to Input Directories.
-
Pick a Mode:
Mode Use when FromMetadataThe sheet is already sliced in Unity. Keeps names, rects, pivots and borders. GridBasedEven cells. Set Columns/Rows or leave Grid Size Mode on Auto.PaddedGridEven cells with gutters. Set Left/Right/Top/Bottom padding. AlphaDetectionSprites are scattered irregularly. Tune Alpha Threshold (default 0.01). -
Click Find Sprite Sheets, then Preview Slicing to see the detected rects drawn over the texture (Show Overlay).
-
Choose a Pivot Mode —
Center, the eight edge and corner presets, orCustomwith explicit X / Y. -
Set Output Directory, then click Extract N Sprite(s).
Auto-detection: with Grid Size Mode on Auto, the Algorithm dropdown picks how cell size
is inferred: AutoBest (tries each and stops once one reaches 90% confidence), UniformGrid,
BoundaryScoring, ClusterCentroid, DistanceTransform or RegionGrowing. Filling in
Expected Sprite Count dramatically improves the result, and Snap to Divisor keeps the cell
size an exact divisor of the texture.
Also worth knowing:
-
Dry Run turns the extract button into
Dry Run: Preview N Sprite(s)and writes nothing. - Per-sheet settings override the global ones; Apply Global to All pushes yours down, and
Save Config writes a
<texture>.spritesheet.jsonbeside the sheet so a re-extraction is reproducible. AConfig Stalebadge appears when the texture has changed since. - Preserve Import Settings (on by default) copies the source's importer settings to each output.
- The Danger Zone: Reference Replacement section points existing assets at the extracted sprites. Like the one in Sprite Cropper, it requires ticking "I understand the risks and want to proceed." and it is not undoable.
Tools > Wallstop Studios > Unity Helpers > AnimationEvent Editor
Putting a footstep sound on frame 4 of a run cycle in Unity's Animation window means finding the right time value and typing a method name from memory. This shows the sprite at each event, lists the methods that are actually callable, and edits the parameter with the right field type.
First, mark the methods you want to fire:
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public enum Stance { Idle, Crouched, Guarding }
public sealed class PlayerAnimationEvents : MonoBehaviour
{
[AnimationEvent]
public void PlayFootstep() { }
[AnimationEvent]
public void SpawnSlashVfx(string socketName) { }
[AnimationEvent]
public void EnableHitbox(int hitboxIndex) { }
[AnimationEvent]
public void SetStance(Stance stance) { }
}Then:
- Drag the GameObject holding the
Animatorinto Animator Object. - Pick the clip from Animation (use Animation Search to filter a long list).
- Type
4into FrameIndex and click Add Event. - Choose TypeName
PlayerAnimationEvents, then MethodNamePlayFootstep. - Click Save.
Method signatures Unity accepts — and therefore the only ones this window lists — return void
and take either no parameter or exactly one of: int, float, string, UnityEngine.Object, or an
enum. UnityEngine.Object means that exact type; a method taking GameObject or Sprite will not
appear.
Explicit Mode is on by default and lists only [AnimationEvent] methods, which is what keeps the
dropdown readable in a real project. Turn it off to see every signature-valid method on every
MonoBehaviour (private ones included) and use Type Search / Method Search to narrow.
By default an [AnimationEvent] method is offered on its declaring class only. Use
[AnimationEvent(ignoreDerived = false)] when subclasses should offer it too.
Also worth knowing:
- Control Frame Time off (the default) means you work in whole frames; on, you edit the raw time value.
- The sprite preview needs
Read/Write Enabledon the texture. When it is missing you get a Fix button that turns it on. - Move Up / Move Down swap events that sit at the same time; Re-Order sorts everything by time. Duplicate copies an event, and Reset reverts to the last saved state.
- The Save / Reset / Re-Order row only appears once you have unsaved changes; otherwise the window
says
No changes detected.... - Shortcuts:
Deleteremoves the focused event,Ctrl+Dduplicates it, arrow keys navigate. The duplicate shortcut isCtrlonly, including on macOS.
Tools > Wallstop Studios > Unity Helpers > Sprite Atlas Generator
A .spriteatlas asset holds a hand-maintained list of sprites, so every new sprite an artist adds is
one someone has to remember to drag in. This drives the atlas from a rule instead — a regex, an asset
label, or both — and rescans on demand.
-
Click Create New Config in 'Assets/Data'. That makes a
ScriptableSpriteAtlasasset (you can also useAssets > Create > Wallstop Studios > Unity Helpers > Scriptable Sprite Atlas Config). -
Set Output Sprite Atlas Directory and Output Sprite Atlas Name — the atlas is written to
<directory>/<name>.spriteatlas. -
Click Add New Source Folder Entry and point it at
Assets/Sprites/Characters. -
Choose how sprites are selected:
Selection Mode What it matches RegexEvery pattern in Regexes (AND logic) must match the asset path. LabelsAsset labels, combined by Label Selection Mode: All(every label) orAnyOf(any one).Regex | LabelsBoth, joined by Regex & Tags Logic ( And/Or). -
Click Scan Folders for ''. The window reports
To Add: N sprites.andTo Remove: N sprites.before anything changes. -
Click Sync List To Scan Result (N add, N remove).
-
Click Generate/Update '.spriteatlas' ONLY, then Pack All Generated Sprite Atlases — or Generate + Pack to do both.
A character atlas that picks up every new idle frame automatically:
Folder Path: Assets/Sprites/Characters
Selection Mode: Regex
Regexes (AND logic): ["player_", "_idle_"]
Max Texture Size: 2048
Padding: 4
Compression: CompressedHQ
A UI atlas driven by labels, so artists opt sprites in from the Inspector rather than by filename:
Folder Path: Assets/Sprites/UI
Selection Mode: Labels
Label Selection Mode: AnyOf
Labels: ["icon", "hud"]
Max Texture Size: 1024
Padding: 2
The Labels fields are dropdowns populated from every label in the project — see Sprite Label Processor for what keeps that list current.
Also worth knowing:
- Each source folder entry has an exclusion block — Exclude Regexes (OR logic), Exclude Labels and Exclude Path Prefixes — for keeping work-in-progress or reference art out of a shipped atlas.
- Platform Overrides on the config set per-platform max size and compression for Standalone, iPhone and Android independently.
- Force Uncompressed for N Source Sprites in '' sets the source sprites to uncompressed so the packer has full-quality input. It asks for confirmation first, and it changes those source assets.
- Regex matching is case-insensitive. A pattern that fails to compile is logged and matches nothing.
Visual Reference
Sprite Atlas Generator with regex-based sprite selection and packing settings
Scanning folders and previewing which sprites will be added to the atlas
Tools > Wallstop Studios > Unity Helpers > Asset Validation
A dockable window over your own project checks. Write an IValidationRule -- "every enemy prefab has
a spawn point", "no AudioClip is set to Decompress On Load" -- and this runs them across the whole
project a few milliseconds per editor tick, rather than freezing for thirty seconds.
- Click Validate Project. A counter beside the button shows progress; the button becomes Cancel.
- Findings are colored by severity. Click one to select and ping the asset.
- Narrow the list: the search box matches the rule, path, discriminator and message; At least cycles the severity floor through Info, Warning and Error; Show suppressed is on by default.
-
Suppress Selected appends the finding to
ValidationSuppressions.txt, the same file the headless run reads.
Tick Re-check on import and an import re-validates only the assets it touched. It is off by default and stored per user, because whether the cost is worth paying is a fact about a workstation rather than about a repository.
The summary line distinguishes nothing checked yet from checked, and clean -- an empty list alone would report a project as healthy on the strength of never having looked at it.
Writing rules, the headless -executeMethod run, and the suppression file format are covered in
Asset Validation.
Tools > Wallstop Studios > Unity Helpers > Prefab Checker
Someone deletes a script, and forty prefabs quietly acquire a "Missing (Mono Script)" slot that only shows up when a scene loads. Prefab Checker walks every prefab under a folder and logs the problems with clickable links.
- Click Add Folder and pick
Assets/Prefabs(already added for you if that folder exists). - Leave the default checks on and click Run Checks.
- Click a console line to select the offending prefab.
| Check | Reports | Default |
|---|---|---|
| Missing Scripts | Components whose script asset is gone | On |
| Nulls in Lists/Arrays |
null elements inside a serialized list or array |
On |
| Missing Required Components | A [RequireComponent] dependency that is not on the prefab |
On |
| Null Object References | Unassigned UnityEngine.Object fields |
On |
| Only if [ValidateAssignment] | Narrows the check above to annotated fields only | On |
| Disabled Root GameObject | Prefab roots saved inactive | On |
| Empty String Fields | Serialized string fields left empty |
Off |
| Disabled Components |
Behaviour components saved disabled |
Off |
Everything except Empty String Fields is logged as an error; empty strings are warnings.
Narrowing a run: Include Labels (comma) and Exclude Labels (comma) filter by asset label, and Deny Component Types (comma names) flags prefabs carrying a component you have banned (a debug-only behaviour, say).
Fixing and reporting: Fix Missing Scripts strips dead component slots, but it stays disabled until you tick Enable Auto-fix options — the gate is deliberate, because the fix deletes data. Export Report (JSON) and Export Report (CSV) write the same findings to a file for a build step or a review.
Annotate the fields you actually care about so the null check stays useful:
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public sealed class Turret : MonoBehaviour
{
[ValidateAssignment]
public Transform muzzle;
[ValidateAssignment]
public GameObject projectilePrefab;
// Not annotated: optional, and a null here is not a bug.
public AudioClip idleHum;
}Visual Reference
Prefab Checker with configurable validation checks and folder selection
Console output showing detected prefab issues with clickable links
Tools > Wallstop Studios > Unity Helpers > Unity Method Analyzer
A private void Start() in a subclass whose base class also has private void Start() compiles
cleanly, and Unity calls only one of them. This scans your C# source for that family of mistake.
- Add
Assets/Scriptsto the source directories. - Click Analyze Code.
- Double-click a result to jump to the line.
| It finds | Example |
|---|---|
A missing override
|
A derived method hiding the base one instead of overriding it |
| A wrong lifecycle signature |
OnCollisionEnter(Collider c) where Unity calls OnCollisionEnter(Collision)
|
| A shadowed lifecycle method | Base and derived both declare private void Start()
|
| A static lifecycle method |
static void Awake(), which Unity never calls |
Results group by file, severity or category, and export as JSON or Markdown for a CI gate.
Silence a deliberate case — a test fixture that exists precisely to be wrong — with
[SuppressAnalyzer]:
[SuppressAnalyzer("Test fixture for analyzer validation")]
public sealed class DeliberatelyShadowedStart : BaseBehaviour
{
private void Start() { }
}Full reference: Unity Method Analyzer Guide
Visual Demo
The analyzer scanning a project and displaying categorized issues
Tools > Wallstop Studios > Unity Helpers > Validate Serialized Fields In Selection
Unity declines to serialize some types and declines silently. Select the script and run the command; it names every field that will be empty after the next domain reload, and what to use instead.
public sealed class Loot : ScriptableObject
{
public Dictionary<string, int> drops; // gone on the next domain reload
public (int, float) weightedRoll; // gone, and it IS [Serializable]
}SerializedObject.FindProperty("drops") returns null, JsonUtility.ToJson omits the field, and
nothing is logged. Whatever a designer authored into it is gone, usually discovered from a build.
[Serializable] is not the discriminator, which is what makes the rule hard to work out from
outside: ValueTuple<int, float> carries it and is dropped anyway.
The console tells you the fix:
Loot.drops is declared as Dictionary<string, int>, which Unity does not serialize. Anything
authored into it is gone on the next domain reload. Use SerializableDictionary<string, int>
instead.
| Declared as | Use instead |
|---|---|
Dictionary<TKey, TValue> |
SerializableDictionary<TKey, TValue> |
SortedDictionary<TKey, TValue> |
SerializableSortedDictionary<TKey, TValue> |
HashSet<T> |
SerializableHashSet<T> |
SortedSet<T> |
SerializableSortedSet<T> |
Nullable<T> |
SerializableNullable<T> |
ValueTuple<...>, Tuple<...>
|
SerializableValueTuple<...> |
KeyValuePair<TKey, TValue> |
SerializableValueTuple<TKey, TValue> |
Queue<T>, Stack<T>, LinkedList<T>
|
List<T> |
How it decides: it constructs the type, wraps it in a SerializedObject, and asks which fields
arrived. That is Unity's own answer rather than a model of its rules, so it cannot misreport the
generic user types Unity has serialized since 2020. Every public or [SerializeField] field with
no SerializedProperty is reported, inherited ones included.
Silencing a field: mark it [NonSerialized]. That is the standard way to say "runtime only",
Unity honours it, and so does this.
Why the selection and not the whole project: validating a type means constructing one, and
constructing every type in a project runs the startup half of the project. Select what you just
wrote — a MonoScript, a prefab, a scene object or an asset. A prefab contributes every component on
it.
MatchColliderToSprite reshapes a PolygonCollider2D to the current sprite in OnValidate, which
does not fire when the sprite is swapped from code or by an animation. The inspector adds a
MatchColliderToSprite button that runs the same pass on demand, recorded as a
Match Collider To Sprite undo step.
Reach for it after changing a sprite at runtime, or whenever the collider and the sprite have drifted apart. See MatchColliderToSprite for the component itself.
An auto-generated PolygonCollider2D from a detailed sprite can carry hundreds of points, and Physics
2D pays for every one of them. This inspector shows a single Tolerance field and an Optimize
button that simplifies the outline in place.
Raise Tolerance until the silhouette starts to visibly change, then back off one step. 0.1–0.5
is the usual working range; above 2.0 you are trading shape for point count. Set Tolerance to
0 and click Optimize to restore the original outline — the component keeps it. Optimize is
also recorded as an Optimize Polygon Collider undo step.
See PolygonCollider2DOptimizer for the component.
EnhancedImage extends Unity's Image with an HDR tint and a shape mask, both of which need the
package's BackgroundMask material to do anything. The custom inspector is mostly there to notice
when that material is missing.
- If the component is still on Unity's Default UI Material, a yellow
Incorrect Material Detected - Try Fix? button appears. Clicking it finds and assigns
Shaders/Materials/BackgroundMask-Material.matas aFix EnhancedImage Materialundo step. -
HDR Color multiplies the image; push intensity above
1.0to make it bloom under post-processing. -
Shape Mask takes a
Texture2D. It only does something if the assigned material's shader exposes a_ShapeMasktexture property — the inspector says so in the tooltip rather than failing silently.
See EnhancedImage for the component and its runtime API.
These are the inspector attributes the tools above lean on most. The Inspector documentation covers the full set.
Tuning an ability means selecting the AbilityConfig asset, editing it, then selecting the character
again to see the result. [WInLineEditor] draws the referenced asset's own inspector underneath the
field so you never leave.
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public sealed class AbilityConfig : ScriptableObject { }
public sealed class AbilityLoadout : MonoBehaviour
{
// Inherits the project-wide default from Unity Helpers Settings.
[WInLineEditor]
public AbilityConfig primary;
// Always open, no object picker, taller body.
[WInLineEditor(WInLineEditorMode.AlwaysExpanded, inspectorHeight: 260f, drawObjectField: false)]
public AbilityConfig secondary;
// Collapsed by default, with the texture preview turned on.
[WInLineEditor(WInLineEditorMode.FoldoutCollapsed, drawPreview: true, previewHeight: 96f)]
public Texture2D icon;
}| Mode | Behaviour |
|---|---|
UseSettings |
Default. Follows the Inline Editors setting in Project Settings. |
AlwaysExpanded |
Inspector is always drawn. |
FoldoutExpanded |
Foldout, open on first draw. |
FoldoutCollapsed |
Foldout, closed on first draw. |
Constructor parameters, in positional order:
mode, inspectorHeight (default 200, floored at 160), drawPreview (false),
previewHeight (64, floored at 40), drawObjectField (true), drawHeader (true),
enableScrolling (true), minInspectorWidth (520; below this width a horizontal scrollbar
appears, 0 disables that). Prefer named arguments — the order is easy to get wrong.
Field-only. Unlike the other attributes here, [WInLineEditor] targets fields, so on an
auto-property you need [field: WInLineEditor].
It reuses Unity's own editor for the target, so custom inspectors, validation and undo all still work. Foldout animation speed lives in Inspector Settings.
Visual Reference
WInLineEditor with embedded inspector for a ScriptableObject reference with foldout and collapse transitions
Half the fields on a spawner only matter when it is set to burst mode, and showing them the rest of
the time is how designers set the wrong one. [WShowIf] hides a field until its condition holds.
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public sealed class EnemySpawner : MonoBehaviour
{
public enum SpawnMode
{
Continuous = 1,
Burst = 2,
}
public SpawnMode mode = SpawnMode.Continuous;
[WShowIf(nameof(mode), expectedValues = new object[] { SpawnMode.Burst })]
public int burstSize = 5;
[WShowIf(nameof(mode), inverse: true, expectedValues: new object[] { SpawnMode.Burst })]
public float spawnsPerSecond = 1f;
public bool useSpawnBudget;
[WShowIf(nameof(useSpawnBudget))]
public int maxAlive = 20;
[WShowIf(nameof(maxAlive), WShowIfComparison.GreaterThan, 50)]
public bool warnAboutPerformance;
public string overrideLayerName;
[WShowIf(nameof(overrideLayerName), WShowIfComparison.IsNotNullOrEmpty)]
public int sortingOrder;
}inverse and comparison are constructor arguments (inverse: true), not object-initializer
assignments — inverse = true will not compile. expectedValues accepts either form.
| Comparison | Use for |
|---|---|
Equal, NotEqual
|
Any equatable value; the default is Equal
|
GreaterThan, GreaterThanOrEqual
|
Numbers and any IComparable
|
LessThan, LessThanOrEqual
|
Numbers and any IComparable
|
IsNull, IsNotNull
|
Object references |
IsNullOrEmpty, IsNotNullOrEmpty
|
Strings and collections |
WShowIfComparison.Unknown exists only for backward compatibility and is marked obsolete.
The condition can be a field, a property (including a [field: SerializeField] auto-property), a
parameterless method, or a dotted path into a nested serialized type:
[WShowIf(nameof(damage) + "." + nameof(DamageProfile.isCritical))]
public float criticalMultiplier;Visual Reference
Field appears/disappears based on enum toggle state
A string field that has to match an animator state name or an asset label is a typo waiting to
happen. [StringInList] turns it into a dropdown of the values that are actually valid.
using System.Collections.Generic;
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
using WallstopStudios.UnityHelpers.Core.Helper;
public sealed class SpawnRule : MonoBehaviour
{
// Fixed set.
[StringInList("Idle", "Run", "Jump")]
public string startState = "Idle";
// Every asset label in the project, kept current by the Sprite Label Processor.
[StringInList(typeof(Helpers), nameof(Helpers.GetAllSpriteLabelNames))]
public List<string> requiredLabels = new();
// A provider on this same type.
[StringInList(nameof(GetPoolNames))]
public string poolName;
private IEnumerable<string> GetPoolNames()
{
yield return "Grunt";
yield return "Archer";
yield return "Brute";
}
}That second field is how the package itself populates the label pickers in Sprite Atlas Generator.
A provider method takes no parameters and returns string[] or IEnumerable<string>. It may be
private, and it may be static or an instance method. [StringInList(typeof(T), "Method")] looks for
a static method on T first, then an instance one; [StringInList("Method")] looks on the decorated
object's own type.
- On an
intfield the dropdown selects by index. - On an array or list you get a UI Toolkit list with a dropdown per element, plus add, remove and drag-to-reorder.
- Typing filters the list.
Tabaccepts the highlighted match,Enterjust fills the search box. - Long lists paginate. The page size is
Project Settings ▸ Wallstop Studios ▸ Unity Helpers ▸ StringInList Page Size (default
25), shared with theSerializableTypedrawer.
Visual Reference
StringInList dropdown showing search filtering and pagination
StringInList on a List field with per-element dropdowns and drag reordering
For an int that only has a handful of legal values, a free text field lets someone type 3000 into
a texture size. [IntDropDown] restricts it to the list.
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public sealed class AtlasSettings : MonoBehaviour
{
[IntDropDown(32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384)]
public int maxTextureSize = 2048;
[IntDropDown(0, 2, 4, 8, 16, 32)]
public int padding = 4;
}Those two fields are lifted from ScriptableSpriteAtlas, which is exactly how
Sprite Atlas Generator keeps its packing settings legal.
The attribute is spelled IntDropDown with a capital D. Like StringInList it also accepts a
provider: [IntDropDown(typeof(T), nameof(T.Method))] or [IntDropDown(nameof(Method))], returning
int[] or IEnumerable<int>.
Visual Reference
IntDropDown for texture sizes showing power-of-two options
StringInList and IntDropDown for everything else — floats, bools, enums, Unity structs, and your
own serializable types.
using System.Collections.Generic;
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public sealed class WeaponTuning : MonoBehaviour
{
[WValueDropDown(0.5f, 1.0f, 1.5f, 2.0f)]
public float damageMultiplier = 1.0f;
[WValueDropDown("Easy", "Normal", "Hard", "Insane")]
public string difficulty = "Normal";
// Instance provider: the options depend on this component's own state.
[WValueDropDown(nameof(GetMuzzleOffsets), typeof(Vector2))]
public Vector2 muzzleOffset;
public List<Vector2> configuredMuzzles = new();
private IEnumerable<Vector2> GetMuzzleOffsets()
{
return configuredMuzzles;
}
}There is a params overload for every primitive (bool, char, all the integer widths, float,
double, string). For anything else, use a provider:
-
[WValueDropDown(typeof(Library), nameof(Library.GetPresets))]— static provider, element type inferred from the return type. -
[WValueDropDown(nameof(GetOptions), typeof(Vector2))]— instance provider on the decorated type, value type stated. -
[WValueDropDown(typeof(Preset), presetA, presetB)]— an inline list of custom-typed values.
Providers follow the same rules as StringInList: parameterless, may be private, returning an array
or IEnumerable. Labels come from ToString(), so give a custom type a readable one.
Full constructor reference: Inspector Selection Attributes.
Visual Reference
WValueDropDown showing predefined integer, float, and string values
Shows a serialized value in the inspector without letting anyone edit it — useful for a number your code derives and a designer should only ever read.
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public sealed class Health : MonoBehaviour
{
public int baseHealth = 100;
public int equipmentBonus;
[WReadOnly]
public int totalHealth;
private void OnValidate()
{
totalHealth = baseHealth + equipmentBonus;
}
}No parameters and nothing to configure. It works on any serialized type and keeps the field's normal height and layout.
For attributes that reject a bad value rather than just displaying it, see Inspector Validation Attributes.
Visual Reference
WReadOnly field showing totalHealth as a non-editable calculated value
Runs automatically on editor load. No menu item.
ScriptableObjectSingleton<T> loads its asset from Resources, which means a new teammate's first
run of the game fails on a settings asset nobody committed. This watches for singleton types with no
asset and creates them, and relocates any that end up in the wrong folder.
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
using WallstopStudios.UnityHelpers.Utils;
public sealed class GameSettings : ScriptableObjectSingleton<GameSettings>
{
public float masterVolume = 1f;
public bool enableVSync = true;
}
[ScriptableSingletonPath("Settings/Audio")]
public sealed class MusicSettings : ScriptableObjectSingleton<MusicSettings>
{
public float musicVolume = 0.8f;
}Write those two files, let the editor reload, and you have:
Assets/
Resources/
GameSettings.asset # no [ScriptableSingletonPath]
Settings/
Audio/
MusicSettings.asset # [ScriptableSingletonPath("Settings/Audio")]
Then GameSettings.Instance.masterVolume works in play mode and in a build, with nothing to
remember.
Move GameSettings.asset somewhere else by hand and the next domain reload moves it back — the
attribute is the source of truth for where it lives.
See Singleton Utilities for the runtime base class, its lookup order and Odin compatibility.
Runs automatically on sprite import. No menu item.
Asset labels are a good way to say "this sprite belongs in the UI atlas", but there is no cheap way
to ask Unity for every label in the project — you would have to load every asset. This
AssetPostprocessor maintains the list as sprites are imported, so a dropdown can be populated
instantly.
That is what makes this one line work:
using System.Collections.Generic;
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
using WallstopStudios.UnityHelpers.Core.Helper;
public sealed class AtlasRule : MonoBehaviour
{
[StringInList(typeof(Helpers), nameof(Helpers.GetAllSpriteLabelNames))]
public List<string> labels = new();
}Helpers.GetAllSpriteLabelNames() returns the cached array; the
GetAllSpriteLabelNames(List<string> destination) overload fills a list you own instead of
allocating. Sprite Atlas Generator uses exactly this for its label
pickers.
Editor-only. The cache is built by an AssetPostprocessor, so both methods return empty in a
player build, in batch mode, and in CI. Do not build runtime behaviour on them.
Only .png, .jpg and .jpeg assets under Assets whose importer type is Sprite contribute
labels, and the result is sorted so a dropdown is stable between sessions.
Tools > Wallstop Studios > Unity Helpers > Request Script Compilation — Ctrl/Cmd + Alt + R
You generated a .cs file from outside Unity — a codegen step, a script pulled by a package tool —
and the editor has not noticed. Rather than touching a file to force a rebuild, press the shortcut.
It runs a forced synchronous AssetDatabase.Refresh (so the new file is imported first) and then
CompilationPipeline.RequestScriptCompilation(). If Unity is already compiling it logs
Script compilation already in progress; manual request skipped. and does nothing, so leaning on the
shortcut is harmless.
Rebind it under Edit > Shortcuts in Wallstop Studios ▸ Request Script Compilation.
Visual Reference
Edit > Project Settings > Wallstop Studios > Unity Helpers
One panel for the package's project-wide defaults: inspector pagination, inline editor behaviour, button and toggle colours, and the coroutine wait buffers.
Coroutine wait buffers. yield return new WaitForSeconds(0.25f) allocates every time it runs.
The package pools those instructions, and this panel controls the pool: a quantization step (how
finely wait times are bucketed), a cap on distinct cached entries, and whether the cap evicts
least-recently-used. Settings are written to
Assets/Resources/Wallstop Studios/Unity Helpers/UnityHelpersBufferSettings.asset and applied on
domain reload and player start, so they ship with the build.
Inspector pagination. StringInListPageSize (default 25) sets how many options a
StringInList dropdown shows per page; EnumToggleButtonsPageSize
(default 15) does the same for [WEnumToggleButtons] grids. Raise them if lists feel cramped,
lower them if a big enum makes the inspector sluggish. Individual fields can override both.
Full reference: Inspector Settings.
Visual Reference
Centralized configuration panel in Unity's Project Settings
Runs automatically on editor load and after every recompile. No menu item.
The Effects system and the
relational component attributes resolve fields
by reflection. Doing that on the first frame is a visible stall, and on IL2CPP some of it cannot be
done at all. This walks your types at edit time and bakes the answers into an
AttributeMetadataCache asset that ships with the build.
You do not call the generator. It runs on load, and the AttributeMetadataCache asset's inspector
has a Purge & Refresh Cache button for when you want to force it.
Read the baked data if you are building tooling of your own:
using System;
using UnityEngine;
using WallstopStudios.UnityHelpers.Tags;
public static class AttributeInspectorSupport
{
public static void Dump(Type componentType)
{
AttributeMetadataCache cache = AttributeMetadataCache.Instance;
// Every attribute name declared anywhere in the project.
string[] all = cache.AllAttributeNames;
if (cache.TryGetFieldNames(componentType, out string[] fieldNames))
{
Debug.Log($"{componentType.Name} declares {fieldNames.Length} of {all.Length} attributes.");
}
if (
cache.TryGetRelationalFields(
componentType,
out AttributeMetadataCache.RelationalFieldMetadata[] relational
)
)
{
foreach (AttributeMetadataCache.RelationalFieldMetadata field in relational)
{
Debug.Log($"{field.fieldName} is a {field.attributeKind} field.");
}
}
}
}What gets baked: the attribute fields on every AttributesComponent type, the
[ParentComponent] / [ChildComponent] / [SiblingComponent] metadata, assembly-qualified type
names so they resolve at runtime, whether each field is a single value, array, List or HashSet,
and whether its element type is an interface.
WallstopStudios.UnityHelpers.Editor.Utils.EditorUtilities
A wizard that creates an asset should create it where the user is looking, not in Assets/. Unity
does not expose the Project window's selected folder, so this does.
using UnityEditor;
using UnityEngine;
using WallstopStudios.UnityHelpers.Editor.Utils;
public static class CreateAbilityAsset
{
[MenuItem("Assets/Create/Game/Ability Config")]
private static void Create()
{
AbilityConfig asset = ScriptableObject.CreateInstance<AbilityConfig>();
string folder = EditorUtilities.GetCurrentPathOfProjectWindow();
string directory = string.IsNullOrEmpty(folder) ? "Assets" : folder;
AssetDatabase.CreateAsset(
asset,
AssetDatabase.GenerateUniqueAssetPath($"{directory}/NewAbilityConfig.asset")
);
AssetDatabase.SaveAssets();
Selection.activeObject = asset;
}
}GetCurrentPathOfProjectWindow() returns an asset-relative path such as Assets/Data/Abilities, or
an empty string when it cannot determine one — always have a fallback, as above. It reaches an
internal Unity API by reflection, so treat the empty-string case as normal rather than exceptional.
IndentLevelScope.Indent() and IndentLevelScope.AtLevel(level) change
EditorGUI.indentLevel without per-scope garbage after the shared owner has warmed to the maximum
concurrent nesting depth. Copies are safe to dispose more than once. Nested scopes also restore the
newest still-active level when copies are disposed out of order, rather than replaying a stale
global value over an inner drawer.
Tools > Wallstop Studios > Unity Helpers > Export Failed Tests / Clear Failed Tests
A flaky test that fails once in twenty runs is invisible if the only record is the Test Runner window
you already closed. Enable this in
Edit > Project Settings > Wallstop Studios > Unity Helpers and every failure — name, message, stack
trace — is captured and written to failed-tests-YYYY-MM-DD-HHmmss.txt in a folder you choose
(project root by default).
Disabled by default. Both menu items are greyed out until there are failures to act on.
Full setup and API: Failed Tests Exporter.
Tools > Wallstop Studios > Unity Helpers > Run EditMode Tests With Summary /
Run PlayMode Tests With Summary
Starts a test run and returns immediately, having first opened
<project>/Temp/unity-helpers-test-run-<mode>.txt with a running marker. When the run ends the
file is rewritten with one summary line, one line per assembly, and one line per failure carrying
its message and source location. A process driving an editor it does not own polls that file instead
of scraping the console, which can be cleared out from under it.
EditMode and PlayMode write different files, a second run is refused while one is in flight, and the callbacks are re-registered after the domain reload a PlayMode run causes.
Format, poller example and recovery from a lost run: Test Run Reporter.
MultiFileSelectorElement is the UI Toolkit control the tools above use for "pick several files or
folders". It is public, so your own editor windows can use it too.
In the editor it remembers selections through EditorPrefs and offers Reveal in Finder / Show in
Explorer. In a player build it falls back to PlayerPrefs and enumerates files under the
application's data root, dropping the editor-only affordances.
Persistence is opt-in per element, via a persistenceKey. Stored scopes are managed from
Tools > Wallstop Studios > Unity Helpers > Multi-File Selector Persistence, which can
Run Cleanup Now or drop scopes unused for more than Max age (days) (default 30) on editor
startup.
There is a runnable example in the UI Toolkit - MultiFile Selector (Editor) sample, importable from
the Package Manager.
Everything under Tools > Wallstop Studios > Unity Helpers:
| Menu item | Section |
|---|---|
| Animation Copier | Animation Copier |
| Animation Creator | Animation Creator |
| AnimationEvent Editor | Animation Event Editor |
| Clear Failed Tests | Failed Tests Exporter |
| Export Failed Tests | Failed Tests Exporter |
| Fit Texture Size | Fit Texture Size |
| Image Blur | Image Blur Tool |
| Multi-File Selector Persistence | MultiFile Selector |
| Prefab Checker | Prefab Checker |
| Proto Schema Exporter | Serialization |
| Request Script Compilation | Request Script Compilation |
| Run EditMode Tests With Summary | Test Run Reporter |
| Run PlayMode Tests With Summary | Test Run Reporter |
| Sprite Animation Editor | Sprite Animation Editor |
| Sprite Atlas Generator | Sprite Atlas Generator |
| Sprite Cropper | Sprite Cropper |
| Sprite Pivot Adjuster | Sprite Pivot Adjuster |
| Sprite Settings Applier | Sprite Settings Applier |
| Sprite Sheet Animation Creator | Sprite Sheet Animation Creator |
| Sprite Sheet Extractor | Sprite Sheet Extractor |
| Texture Resizer | Texture Resizer |
| Texture Settings Applier | Texture Settings Applier |
| Unity Method Analyzer | Unity Method Analyzer |
| Validate Serialized Fields In Selection | Serialized Field Validator |
Elsewhere:
-
Assets > Create > Wallstop Studios > Unity Helpers > Scriptable Sprite Atlas Config— Sprite Atlas Generator -
Edit > Project Settings > Wallstop Studios > Unity Helpers— Project Settings
Runs with no menu item: ScriptableObject Singleton Creator, Sprite Label Processor, Attribute Metadata Cache Generator, Asset Change Detection.
Shared across the windows: folder fields accept dragged Project-window folders, the folders you pick are remembered per tool and offered again next time, and long operations report progress in the console rather than blocking silently.
Most of these tools only change import settings, which Unity records as an undo step and which you
can revert by reverting the .meta file. These are the ones that write real files:
| Tool | Effect |
|---|---|
| Image Blur Tool | Writes new files; leaves sources on Read/Write + Uncompressed |
| Sprite Cropper | Writes PNGs; overwrites sources when Overwrite Originals is on |
| Texture Resizer | Overwrites source PNGs unless Output Folder is set |
| Sprite Sheet Extractor | Writes new PNGs; the Danger Zone rewrites referencing assets |
| Sprite Cropper Danger Zone | Rewrites .prefab, .unity, .asset, .mat, .anim, .overrideController
|
| Animation Copier | Copies and (in Cleanup) deletes .anim assets |
| Prefab Checker | Read-only unless you enable auto-fix and click Fix Missing Scripts |
Everything else — Texture Settings Applier, Sprite Settings Applier, Sprite Pivot Adjuster, Fit Texture Size — touches import settings only and records a named undo step.
None of the tools that rewrite image data have an undo. Commit before running them.
A folder of new character art:
- Sprite Sheet Extractor if it arrived as sheets.
- Sprite Cropper to trim the padding.
- Sprite Settings Applier for PPU and filter mode.
- Sprite Pivot Adjuster so the pivots agree.
- Animation Creator to build the clips.
- Animation Event Editor for footsteps and hitboxes.
- Sprite Atlas Generator to pack them.
Before you open a pull request:
- Prefab Checker over the prefab folders you touched.
-
Unity Method Analyzer over
Assets/Scripts. -
Serialized Field Validator on any new
MonoBehaviourorScriptableObject.
Trimming build size:
-
Fit Texture Size in
GrowAndShrinkmode acrossAssets/Sprites. - Sprite Cropper on anything still padded.
- Texture Settings Applier with crunch compression and per-platform max sizes.
| Symptom | Likely cause |
|---|---|
| A sprite tool skips files silently | It is a multi-sprite texture, or Read/Write Enabled is off. Cropper and Pivot Adjuster need Single sprites. |
| Scan Folders finds nothing | The regex does not match, or the folder path is outside Assets/. Invalid regexes are logged and match nothing. |
| An atlas looks worse than the source | Run Force Uncompressed for N Source Sprites before packing. |
| Clips landed in the wrong folder | Animation Creator writes beside the first sprite. Move them with Animation Copier. |
An [AnimationEvent] method is not listed |
It must return void and take zero or one int / float / string / UnityEngine.Object / enum parameter. |
| Prefab Checker reports nothing | The relevant checks may be off — Empty String Fields and Disabled Components are off by default. |
| Fix Missing Scripts is greyed out | Tick Enable Auto-fix options first. |
| A tool did nothing in a CI or batch run | Dialogs and folder pickers are suppressed in batch mode, so anything that needs one is skipped. |
- Inspector Attributes — the full attribute set
- Asset Change Detection — run code when assets change
- Unity Method Analyzer — the analyzer in detail
- Failed Tests Exporter — capturing test failures
- Test Run Reporter — starting a run and polling a summary file
-
Singleton Utilities —
ScriptableObjectSingleton<T> - Effects System — what the attribute metadata cache serves
📦 Unity Helpers | 📖 Documentation | 🐛 Issues | 📜 MIT License
- Inspector Button
- Inspector Conditional Display
- Inspector Grouping Attributes
- Inspector Inline Editor
- Inspector Overview
- Inspector Selection Attributes
- Inspector Settings
- Inspector Validation Attributes
- Utility Components
- Visual Components
- Data Structures
- Helper Utilities
- Math And Extensions
- Pooling Guide
- Random Generators
- Reflection Helpers
- Singletons
- Asset Change Detection
- Asset Validation
- Authored Asset Validation
- Editor Tools Guide
- Failed Tests Exporter
- Test Run Reporter
- Unity Method Analyzer


















