PiRhoUtilities
A suite of UIElements based attributes, drawers, controls, and other helpers to expedite the creation of object inspectors without the need of additional custom editors
Install / Use
/learn @pirhosoft/PiRhoUtilitiesREADME
PiRhoUtilities
A suite of UIElements based attributes, drawers, controls, and other helpers to expedite the creation of inspectors without the need of additional custom editors.
Installation
- In your Unity project open the Package Manager ('Window -> Package Manager')
- Click on the 'Add' (+) button in the top left and choose "Add package from git URL..."
- Enter the URL, https://github.com/pirhosoft/PiRhoUtilities.git#upm in the popup box and click 'Add'
- To import samples into your project, find and select the installed package in the Package and click on 'Import into Project' next to the PiRho Utilities Samples listing. The samples project comes with a scene containing objects with an example of each attribute as well as a sample window (Window > PiRhoUtiilities > UI Samples) showing how to create controls through C# and UXML
Updating
- Once installed, open the Packages/manifest.json file in a text editor
- At the bottom in a property named "lock", remove the object entry titled "com.pirho.utilties"
- Save and return to Unity and it will automatically reimport the updated version from the repository
Known Issues
- https://github.com/pirhosoft/PiRhoUtilities/issues
- Working with [SerializedReference] and the [Reference] attribute is still experimental
Usage
Property Drawer Attributes
These attributes are added to serializable fields in editable classes (MonoBehaviours or ScriptableObjects) to enable custom drawing for the field. Most attributes can have their properties retrieved from another field, property, or method through reflection by specifying the associated string name. All attributes are in the PiRhoSoft.Utilities namespace.
List
Add this to a SerializedList or SerializedArray derived type to show a much more user friendly list editor than Unity's default with custom callbacks and constraints for adding, removing, and reordering. Any additional PropertyTraitAttributes will be applied to each item in the list individually.
[Serializable] public class TestList : SerializedList<int> { }
[Serializable] public class TestArray : SerializedArray<float> { public TestArray(int count) : base(count) { } }
[List(AllowAdd = nameof(ListCanAdd))]
public TestList List;
[List(AllowAdd = ListAttribute.Never, AllowRemove = ListAttribute.Never, AllowReorder = false)]
public TestArray Array = new TestArray(4);
private bool ListCanAdd()
{
return List.Count < 5;
}
| Property | Description | Default |
| ----------------- | ------------- | --------- |
| EmptyLabel | When the list is empty display this text - use an empty string to hide the label - null will show the default text, "The list is empty" | null |
| AllowAdd | The string name of a bool returning method (parameterless), field, or property, that enables/disables adding items to the list. If adding is not conditional, use ListAttribute.Always or ListAttribute.Never | Always |
| AllowRemove | The string name of a bool returning method (parameterless) or (int index), field, or property, that enables/disables removing items from the list. If removing is not conditional, use ListAttribute.Always or ListAttribute.Never | Always |
| AllowReorder | Enables/disables reording items in the list. | true |
| IsCollapsable | Whether or not the List is collapsible to save space | true |
| AddCallback | The string name of a method (parameterless) to call when an item has been added to the list | null |
| RemoveCallback | The string name of a method (parameterless) or (int index) to call when an item is about to be removed from the list | null |
| ReorderCallback | The string name of a method (parameterless) or (int to) or (int from, int to) to call when an item has been reordered in the list | null |
| ChangeCallback | The string name of a method (parameterless) to call when the list changes | null |

Dictionary
Add this to a SerializedDictionary derived type to show a dictionary editor (by default dictionary editing is unsupported by Unity). This has similar features/functionality as ListAttribute.
[Serializable] public class TestDictionary : SerializedDictionary<string, string> { }
[Dictionary(AddCallback = nameof(DictionaryItemAdded), RemoveCallback = nameof(DictionaryItemRemoved))]
public TestDictionary Dictionary;
private void DictionaryItemAdded(string key)
{
Debug.Log($"'{key}' added", this);
}
private void DictionaryItemRemoved(string key)
{
Debug.Log($"'{key}' removed", this);
}
| Property | Description | Default |
| ----------------- | ------------- | --------- |
| EmptyLabel | When the dictionary is empty display this text - use an empty string to hide the label - null will show the default text, "The dictionary is empty" | null |
| AddPlaceholder | The string to display in the add area | null |
| AllowAdd | The string name of a bool returning method (parameterless) or (string key), field, or property, that enables/disables adding items to the dictionary. If adding is not conditional, use DictionaryAttribute.Always or DictionaryAttribute.Never | Always |
| AllowRemove | The string name of a bool returning method (parameterless) or (string key), field, or property, that enables/disables removing items from the dictionary. If removing is not conditional, use DictionaryAttribute.Always or DictionaryAttribute.Never | Always |
| AllowReorder | Enables/disables reording items in the list. | true |
| IsCollapsable | Whether or not the List is collapsible to save space | true |
| AddCallback | The string name of a method (parameterless) or (string key) to call when an item has been added to the dictionary | null |
| RemoveCallback | The string name of a method (parameterless) or (string key) to call when an item is about to be removed from the dictionary | null |
| ReorderCallback | The string name of a method (parameterless) or (string key) to call when an item has been reordered in the dictionary | null |
NOTE: Normally dictionaries don't have defined ordering, however, serializing dictionaries requires the key/value pairs to be stored in lists and are thus ordered.

ComboBox
Add this to a string field to display a ComboBox control in which you can select from dropdown list of values or enter your own custom value.
[ComboBox(new string[] { "One Fish", "Two Fish", "Red Fish", "Blue Fish" })]
public string ComboBox;
| Property | Description | Default |
| ----------------- | ------------- | --------- |
| Options | A predefined list of options to show in the dropdown | null |
| OptionsSource | The string name of a List<string> returning method (parameterless), field, or property, that defines the list of options | null |
| AutoUpdate | Whether the options should automatically update if the values change (may affect performance) | true |

EnumButtons
Apply to an Enum field to show selectable buttons instead of a dropdown list. An optional bool can be specified to override the default behavior of the enum being selectable as flags or not (the default is based on whether the [Flags] attribute is set on the declared enum type).
public enum TestEnum
{
Zero = 0x0,
One = 0x1,
Two = 0x2,
Four = 0x4,
Eight = 0x8
}
[EnumButtons]
public TestEnum Buttons;
[EnumButtons(true)]
public TestEnum Flags;
| Parameter | Description | Default |
| ------------- | ------------- | --------- |
| Flags | Whether multiple options can be selected as a flags enum | true if enum class has the Flags attribute, false otherwise |

Euler
A simple attribute to apply to a Quaternion field to display and assign the Quaternion in Euler angles (like the default Transform inspector does).
[Euler]
public Quaternion Euler;
Frame
Add this to a class or struct type with a Serializable attribute to show the fields of the class in a collapsible frame style which looks much better than Unity's default.
[Serializable]
public class Subclass
{
public bool Bool;
public int Int;
public float Float;
public string String;
}
[Frame]
public Subclass Frame;
| Parameter | Description | Default |
| ------------- | ------------- | --------- |
| IsCollapsable | Whether the frame can be collapsed or not | true |

Group
Add this attribute to any number of fields to display them together as a group with the header label specified in the constructor despite being defined out of order in the class.
[Group("Group One")] public int Int1;
[Group("Group One")] public float Float1;
[Group("Group Two")] [Maximum(100)] public float Float2;
[Group("Group One")] public bool Bool1;
[Group("Group Two")] public bool Bool2;
[Group("Group Two")] public int Int2;

Inline
Add this to a class or struct type with a Serializable attribute to show the fields of the class or struct inline rather than in the default foldout. Member labels can be optionally shown which is useful if the class has one value field.
[Serializable]
public class WrapperClass
{
public int Value;
}
[Inline]
public WrapperClass Wrapper;
| Parameter | Description | Default |
| ------------- | ------------- | --------- |
| ShowMemberLabels | Whether the label of the owning field should be used rather than the label for each of the fields in the class or struct (useful for wrapper classes with a single field) | true |
ObjectPicker
Add this to a UnityEngine.Object derived field to show a searchable popup listing (like the AddComponent window) of the available objects of the correct type instead of the default object picker.
Related Skills
next
A beautifully designed, floating Pomodoro timer that respects your workspace.
product-manager-skills
26PM skill for Claude Code, Codex, Cursor, and Windsurf: diagnose SaaS metrics, critique PRDs, plan roadmaps, run discovery, and coach PM career transitions.
devplan-mcp-server
3MCP server for generating development plans, project roadmaps, and task breakdowns for Claude Code. Turn project ideas into paint-by-numbers implementation plans.
