About
Description
VM_Attributes is a powerful yet intuitive system that allows you to instantly organize and streamline your Unity Inspector. You no longer need to waste precious development time writing and maintaining cumbersome Custom Editor scripts. With our library, you can easily structure and visualize data in the Inspector exactly how you and your team need it for maximum convenience and workflow speed.
At the core of the system lies a robust, professionally designed architecture. The very first release already includes over 80 ready-to-use building-block attributes, and the library will be continuously updated with new tools in the future. Because the author of the library is an active game developer, this toolset was forged from real-world needs: it includes only the most useful, practical, and frequently used attributes in day-to-day development. Simply add the desired attribute to a variable in your code, and your Inspector interface will transform in a fraction of a second.
We made sure you can start using the library at 100% capacity from the very first minute by providing 3 convenient ways to access information about the attributes:
- Interactive Preview Window
- A dedicated Unity Editor window that you can open at any time for quick reference. It lists all available attributes alongside detailed parameter descriptions, interactive live examples (you can test each attribute in real time), and ready-to-use code blocks that you can easily copy directly into your project.
- Comprehensive Documentation
- Every single attribute comes with a detailed description and numerous code examples. We thoroughly explain all the nuances and parameter options, leaving no guesswork behind.
- Demonstration Scene
- All the examples found in the documentation and the Interactive Preview Window are taken directly from the included demo scene. You can open it to test each attribute in real time right in the Inspector and see how it reacts to changes.
Feature List
All attributes are divided into two main types:
1. Class-level Attributes
A compact set of tools for global script configuration:
- Visual Styling
- Defines preset settings for the overall visual appearance of the script's space in the Inspector, such as background color, custom headers, icons, and starting logos (VM_ScriptPreset).
- Context Menu
- Creates a global class-wide context menu for quickly triggering user-defined actions, like field initialization, calculations, etc. (VM_ScriptContextMenu).
2. Field & Method-level Attributes
The core arsenal of the library, designed to organize and visualize data comfortably. All attributes are divided into logical categories (see the list on the left).
Transparent Licensing
Unlike other popular solutions on the market, VM_Attributes is distributed under the Standard Unity Asset Store License. We firmly believe that the tools you purchase from us shouldn't tax your success. You buy the tool once and use it without limitations!
Using our library is:
- Completely independent of your revenue
- Whether your game makes $100 or $1,000,000, the terms remain exactly the same.
- Free of funding restrictions
- Perfectly suited for both indie startups and heavily funded studios.
- Free of corporate subscriptions
- No hidden conditions or forced upgrades to Enterprise tiers when you hit a certain revenue threshold.
Support & Feedback
For the fastest and most productive communication with our users, we have developed our own lightweight platforms for dedicated discussions:
- Bug Tracker
- For submitting bug reports as quickly as possible and tracking the progress of their resolution.
- Forum
- If you have a question for the developer or want to suggest a new feature, you are welcome here!
And most importantly! You communicate directly with the developer — no middlemen and no long wait times.
Acknowledgments
The initial concept and core reflection mechanics were inspired by "NaughtyAttributes" (created by dbrizov).
VM_Attributes takes these early ideas and completely reimagines them into a professional, highly optimized, and feature-rich toolset. With a newly engineered architecture designed for deep nesting and advanced functionality, it stands as a comprehensive solution for Unity developers. Thank you to the original author for the inspiration.
See Third-Party Notices.txt for full license details.
Quick Start
Quick Start
Make sure that Enable Overriding Inspector is checked in Tools → VM-Gamedev → VM_Attributes → Settings menu.
Once you have ensured that the above requirements are met, simply add the following namespace at the top of your C# file to start using attributes:
using VM_Attributes;💡 Tip: Use emojis in your labels to personalize the Inspector and make it more visual and intuitive. For easy emoji integration, check out our asset VM_Emoji.
Script Presets
Script Presets allow you to customize the appearance of your MonoBehaviour components in the Inspector — including header color, body color, custom icon, and logo:
- Key — unique identifier used in the attribute
- Header Color — component titlebar background color
- Body Color — component body background color
- Icon — custom icon for the component header (Texture2D)
- Logo — logo displayed at the top of the component body (Texture2D)
Step 1. Open Project Settings → VM_Attributes (or via Tools → VM-Gamedev → VM_Attributes → Settings). To create a ScriptableObject of the required type (VM_ScriptPresetDatabase), you can use the "Create new Asset" button in the Project-window or Right-click mouse.
Step 2. In the Script Presets section, click Add Preset.
Step 3. Configure the preset with the parameters listed above.
Step 4. Apply the preset to your class using the VM_ScriptPreset attribute and get the result shown below (see screenshots):
[VM_ScriptPreset("VM_Attributes-Mono")] public class MyComponent : MonoBehaviour { // your fields... }
Script Context Menu
Add class-wide context menu items to a script. Right-click on empty areas of the script body in the Inspector to invoke them.
Apply [VM_ScriptContextMenu(menuLabel, methodName, ...)] on the class (not on a field). Stack multiple attributes for multiple items. Parameters:
- string menuLabel — text displayed in the context menu (use '/' for submenus)
- string methodName — name of a method to invoke on click (pass null to insert a separator)
- eEnableMode enableMode — when item is enabled (Always, Editor, Playmode) (default: Always)
- string enableIf — name of bool field/property/method for item disabling (default: null)
Example:
[VM_ScriptContextMenu("Randomize all", nameof(RandomizeAll))] [VM_ScriptContextMenu("Clear all", nameof(ClearAll), enableIf: nameof(HasAnyValue))] [VM_ScriptContextMenu("", null)] [VM_ScriptContextMenu("Tools/Generate ID", nameof(GenerateId))] [VM_ScriptContextMenu("Tools/Copy ID", nameof(CopyId), enableMode: eEnableMode.Editor)] public class MyComponent : MonoBehaviour { // your fields and methods... }
Tailwind Color Table
A built-in color picker window providing the full Tailwind CSS palette (230 colors across 22 hues × 11 shades) available as named constants of the HexColor class (Name Color format).
The HexColor class is the recommended way to specify colors anywhere in the library — instead of remembering HEX codes, pick a color visually from the palette and use its semantic name (e.g. HexColor.Sky500, HexColor.Rose200).
Open via Tools → VM-Gamedev → VM_Attributes → Tailwind color table.
Click any swatch to copy its value to the clipboard. The format is chosen by the radio buttons in the status bar:
- Name Color — HexColor.Red200 — ready to paste into attributes and code
- Hex Color — #fecaca — can be used in attributes as a string
- RGB-int — (254, 202, 202) — for Color32 constructor
- RGB-float — (0.996f, 0.792f, 0.792f) — for Color constructor
Example:
// 1. As a HexColor constant in an attribute parameter (Name Color format) [VM_Label("Health")] [VM_ProgressBar(0, nameof(_maxLife), hexColorBar: HexColor.Blue600)] public int _health; // 2. As a runtime Color value (RGB-float format) renderer.material.color = new Color(0.039f, 0.624f, 0.969f);
Changelog
August 2026 - Initial Release
Features
- 80+ attributes, zero UI boilerplate — no custom editors required
- Editor-only rendering with zero runtime overhead in your builds
- Runtime on/off switch — disable the whole package without removing it
- Attributes Overview window — searchable catalog with live examples and copy-ready code
- Script Presets to scaffold pre-configured components in one click
Requirements
- Unity's Addressables and Localization packages (installed automatically on first setup)
- Only one custom Inspector override can be active at a time (disable or delete other overriding tools)
Known Issues
- Emoji in Inspector will render as solid black instead of full color since Unity 6.5 and newer when the Editor uses the Light theme (Unity Issue Tracker: UUM-147842). Because the bundled examples use emoji extensively, the effect is most noticeable there — switching the Editor to the Dark theme displays them correctly.
VM_Note
Description
Adds an explanatory note to any field or group.
Constructors
Parameters
- string text — note text to display (supports rich text tags)
- string beforeGroup — apply before entering specified group (default: null)
Preview
Example Code
[VM_Note("The \"Player\" tag must be set so that the object can interact with other objects.")] [VM_Label("🧙 Player tag")] [VM_Tag] public string _tagPlayer; [VM_Space(10)] [VM_Note("Health cannot go below 0.\nRegeneration starts after 3 seconds of no damage.")] [VM_Note("Tip: used <b>VM_Clamp</b> to enforce the valid range.")] [VM_Label("❤️ Health")] [VM_Suffix("HP")] [VM_Clamp(0, 1000)] public int _health = 100; [VM_Space(10)] [VM_Note("These messages support some rich text tags:\n" + "✅ <noparse><b>Noparse text</b></noparse> <noparse>(<noparse><b>Noparse text</b></noparse>)</noparse>\n" + "✅ <b>Bold text</b> <noparse>(<b>Bold text</b>)</noparse>\n" + "✅ <i>Italic text</i> (<noparse><i>Italic text</i></noparse>)\n" + "✅ <u>Underlined text</u> (<noparse><u>Underlined text</u></noparse>)\n" + "✅ <color=red>Colored</color> <color='#FF00FF'>text</color> (<noparse><color=red>Colored</color> <color='#FF00FF'>text</color></noparse>)\n" + "✅ <a href='https://vm-gamedev.com/'>Web link</a> (<noparse><a href='https://vm-gamedev.com/'>Web link</a></noparse>)")] [VM_Label("🏃 Speed")] [VM_Suffix("m/s")] public float _speed = 5f; [VM_Space(10, beforeGroup: "Visuals")] [VM_Note("Customizing a group of character appearance parameters.", beforeGroup: "Visuals")] [VM_VerticalGroup("Visuals", label: "🎨 Visuals")] [VM_Label("🖌️ Skin Color")] public Color _skinColor = Color.white; [VM_VerticalGroup("Visuals")] [VM_Note("This material is used in inventory!")] [VM_Label("🧱 Material")] public Material _material;
VM_Code
Description
Adds an explanatory code or documentation to any field or group.
Constructors
Parameters
- string text — code text to display (supports rich text tags)
- string beforeGroup — apply before entering specified group (default: null)
Preview
Example Code
[VM_Code("Bitmask formula:\n" + " mask = 1 << layer\n" + " Physics.Raycast(ray, hit, dist, mask)")] [VM_Label("📡 Raycast Mask")] public LayerMask _raycastMask; [VM_Space(10)] [VM_Code("These messages support some rich text tags:\n" + "✅ <noparse><b>Noparse text</b></noparse> <noparse>(<noparse><b>Noparse text</b></noparse>)</noparse>\n" + "✅ <b>Bold text</b> <noparse>(<b>Bold text</b>)</noparse>\n" + "✅ <i>Italic text</i> (<noparse><i>Italic text</i></noparse>)\n" + "✅ <u>Underlined text</u> (<noparse><u>Underlined text</u></noparse>)\n" + "✅ <color=red>Colored</color> <color='#FF00FF'>text</color> (<noparse><color=red>Colored</color> <color='#FF00FF'>text</color></noparse>)\n" + "✅ <a href='https://vm-gamedev.com/'>Web link</a> (<noparse><a href='https://vm-gamedev.com/'>Web link</a></noparse>)")] [VM_Code("In addition to Unity's standard rich text tags, <b>VM_Code</b> supported a custom tag:\n" + "✅ <b><noparse><hang>...</hang></noparse></b> — <hang>hanging indent. " + "When a line wraps, continuation lines align with the position where the tag was opened. " + "Useful for parameter lists, bullets, and any case where you want a clean visual hierarchy on wrap.</hang>")] [VM_Label("📝 Text Demo")] public string _richTextDemo = "some text"; [VM_Space(10, beforeGroup: "Visuals")] [VM_Code("Format: <b>class Inventory : IGridAccessor</b> (256 cells)", beforeGroup: "Visuals")] [VM_VerticalGroup("Visuals", label: "🎨 Visuals")] [VM_Label("🖌️ Skin Color")] public Color _skinColor = Color.white; [VM_VerticalGroup("Visuals")] [VM_Code("How to use: <b>Inventory.AttachMaterialToItem(Material material)</b>")] [VM_Label("🧱 Material")] public Material _material;
VM_Warning
Description
Alerts users about potential limitations or issues with a field or group.
Constructors
Parameters
- string text — warning text to display (supports rich text tags)
- string beforeGroup — apply before entering specified group (default: null)
Preview
Example Code
[VM_Warning("This reference must be assigned before entering Play Mode.")] [VM_Label("🎯 Required Target")] public GameObject _requiredTarget; [VM_Space(10)] [VM_Warning("Enabling debug mode reduces performance.")] [VM_Warning("Use only during development!")] [VM_Label("🐛 Debug Mode")] public bool _debugMode = false; [VM_Space(10)] [VM_Warning("These messages support some rich text tags:\n" + "✅ <noparse><b>Noparse text</b></noparse> <noparse>(<noparse><b>Noparse text</b></noparse>)</noparse>\n" + "✅ <b>Bold text</b> <noparse>(<b>Bold text</b>)</noparse>\n" + "✅ <i>Italic text</i> (<noparse><i>Italic text</i></noparse>)\n" + "✅ <u>Underlined text</u> (<noparse><u>Underlined text</u></noparse>)\n" + "✅ <color=red>Colored</color> <color='#FF00FF'>text</color> (<noparse><color=red>Colored</color> <color='#FF00FF'>text</color></noparse>)\n" + "✅ <a href='https://vm-gamedev.com/'>Web link</a> (<noparse><a href='https://vm-gamedev.com/'>Web link</a></noparse>)")] [VM_Label("🚀 Max Velocity")] [VM_Suffix("m/s")] [VM_Clamp(1, 500)] public float _maxVelocity = 50f; [VM_Space(10, beforeGroup: "Visuals")] [VM_Warning("Don't forget to customize a group of character appearance parameters!", beforeGroup: "Visuals")] [VM_VerticalGroup("Visuals", label: "🎨 Visuals")] [VM_Label("🖌️ Skin Color")] public Color _skinColor = Color.white; [VM_VerticalGroup("Visuals")] [VM_Warning("Don't forget to assign this material to an item in your inventory!")] [VM_Label("🧱 Material")] public Material _material;
VM_Title
Description
Organizes fields into sections, from large data groups to small subsections.
Constructors
Parameters
- string title — title text to display
- string hexColorTitle — title color in hex format (default: null)
- int fontSize — font size in pixels (default: 13)
- bool centeredTitle — center the title horizontally (default: false)
- string hexColorLine — line color in hex format (default: null)
- float thicknessLine — thickness of the underline (default: 1.5)
- bool fieldOnly — apply only to the following field (default: false)
- string beforeGroup — apply before entering specified group (default: null)
Preview
Example Code
[VM_Title("🏃 Movement", fontSize: 15, hexColorTitle: HexColor.Green600, align: eAlign.Center, thicknessLine: 0)] [VM_Label("🏃 Speed")] [VM_Suffix("m/s")] public float _speed = 5f; [VM_Label("🦘 Jump Height")] [VM_Suffix("m")] public float _jumpHeight = 2f; [VM_Title("⚔️ Combat Stats", align: eAlign.Center, hexColorTitle: HexColor.Indigo700, hexColorLine: HexColor.Indigo700, thicknessLine: 4)] [VM_Label("💥 Damage")] [VM_Suffix("HP")] public int _damage = 10; [VM_Label("⏱️ Attack Rate")] [VM_Suffix("sec")] public float _attackRate = 1.5f; [VM_Title("Visual Settings", align: eAlign.Right)] [VM_Label("🖌️ Tint Color")] public Color _tintColor = Color.white; [VM_Label("🧱 Material")] public Material _material; [VM_Title("🐛 Debug", fontSize: 11, fieldOnly: true, thicknessLine: 2)] [VM_Label("👁️ Show Gizmos")] public bool _showGizmos = false; [VM_Label("📋 Log Events")] public bool _logEvents = false;
VM_Separator
Description
Draws a horizontal line to visually separate fields.
Constructors
Parameters
- string hexColor — line color in hex format (default: null)
- float thickness — thickness of the line in pixels (default: 1.5)
- bool fieldOnly — apply only to the following field (default: false)
- string beforeGroup — apply before entering specified group (default: null)
Preview
Example Code
[VM_Label("🏃 Speed")] [VM_Suffix("m/s")] public float _speed = 5f; [VM_Label("🦘 Jump Height")] [VM_Suffix("m")] public float _jumpHeight = 2f; [VM_Separator(hexColor: HexColor.Indigo700, thickness: 6)] [VM_Label("❤️ Health")] [VM_Suffix("HP")] public int _health = 100; [VM_Label("🛡️ Armor")] [VM_Suffix("%")] public int _armor = 25; [VM_Separator(hexColor: HexColor.Green600, fieldOnly: true)] [VM_Label("🖌️ Tint Color")] public Color _tintColor = Color.white; [VM_Label("🧱 Material")] public Material _material; [VM_Separator(fieldOnly: true, thickness: 1)] [VM_Label("👁️ Show Gizmos")] [VM_Toggles] public bool _showGizmos = false; [VM_Label("📋 Log Events")] public bool _logEvents = false;
VM_Label
Description
Allows to set a custom label and tooltip, that support emojis to enhance visual feedback.
Tip: for easy emoji integration, check out our asset VM_Emoji.
Constructors
Parameters
- string label — custom label text to display
- string tooltip — tooltip text shown on hover (default: null)
- bool bold — display label text in bold (default: false)
- bool italic — display label text in italic (default: false)
- bool underline — display label text in underline (default: false)
- string hexColor — text color in hex format (default: null)
Preview
Example Code
[VM_LabelWidth(0.25f)] [VM_Label("🎥 Main Camera", tooltip: "reference to the camera in the scene")] public Camera _camera; [VM_Label("🧙 Unit", tooltip: "prefab model for the unit")] public GameObject _unit; [VM_Label("❤️ Life", tooltip: "current amount of Health Points", bold: true)] [VM_Min(0)] public int _life = 1; [VM_Label("🔮 Mana", tooltip: "current amount of Mana Points", hexColor: HexColor.Blue800)] [VM_Min(0)] public int _mana = 0; [VM_Label("👁️ Visibility", tooltip: "enemy visibility radius", italic: true)] [VM_Min(1f)] public float _visibility = 5f; [VM_Label("⚔️ Melee Skill", tooltip: "сlose combat parameters", bold: true)] [VM_NestedColor(hexColor: HexColor.Blue300)] public MeleeSkill _meleeSkill; [VM_Label("🏹 Ranged Skill", tooltip: "long-range attack parameters", underline: true, hexColor: HexColor.Green700)] public RangedSkill _rangedSkill; [System.Serializable] public class CriticalDamage { [VM_LabelWidth(0.4f)] [VM_Label("🚩 Applied", tooltip: "critical hit applying flag", bold: true, underline: true, hexColor: HexColor.Red600)] public bool _applied = false; [VM_Label("🎲 Probability", tooltip: "critical hit chance")] [VM_RangeSlider(1, 100)] public int _probability = 50; [VM_Label("✖️ Damage Multiplier", tooltip: "damage multiplier for critical hit")] [VM_RangeSlider(1f, 10f)] public float _multiplier = 2.5f; } [System.Serializable] public class MeleeSkill { [VM_LabelWidth(0.4f)] [VM_Label("💥 Damage", tooltip: "damage range")] [VM_Range] public Vector2Int _damage = new(0, 10); [VM_NestedAsGroup("☠️ Critical Hit", hexColor: HexColor.Red200)] public CriticalDamage _critical; } [System.Serializable] public class RangedSkill { [VM_LabelWidth(0.4f)] [VM_Label("💥 Shot damage", tooltip: "damage range")] [VM_Min(1)] public int _damage = 1; [VM_NestedAsGroup("☠️ Critical Hit")] public CriticalDamage _critical; [VM_Label("📏 Shot Distance", tooltip: "maximum shooting range")] [VM_Min(0f)] public float _rangeDistance = 40f; [VM_Label("🎯 Number of Arrows", tooltip: "number of available shots")] [VM_Min(0)] public int _numArrows = 1; }
VM_Suffix
Description
Specifies the unit of measurement (suffix) for the field.
✓ native Integer and Float fields
✓ VM_Range attribute
✓ VM_MinMaxSlider attribute
✓ VM_RangeSlider attribute
✓ VM_AnchoredSlider attribute
✓ VM_BonusSlider attribute
✓ VM_SegmentedBar attribute
Constructors
Parameters
- string text — text to display after the field
- string textCallback — callback name to override suffix text dynamically (default: null)
- bool showOutside — draw suffix outside of Integer and Float fields (default: false)
- float width — fixed width for outside suffix area (default: 0 = auto)
Preview
Example Code
[VM_LabelWidth(0.25f)] [VM_Label("🎥 Main Camera", tooltip: "reference to the camera in the scene")] [VM_Suffix("in scene", showOutside: true, width: 45)] public Camera _camera; [VM_Label("🧙 Unit", tooltip: "prefab model for the unit")] [VM_Suffix("prefab", showOutside: true, width: 45)] public GameObject _unit; [VM_Label("❤️ Life", tooltip: "current amount of Health Points")] [VM_Suffix("HP")] [VM_Min(0)] public int _life = 1; [VM_Label("🔮 Mana", tooltip: "current amount of Mana Points")] [VM_Suffix("MP")] [VM_Min(0)] public int _mana = 0; [VM_Label("👁️ Visibility", tooltip: "enemy visibility radius")] [VM_Suffix("m")] [VM_Min(1f)] public float _visibility = 5f; [VM_Label("⚔️ Melee Skill", tooltip: "сlose combat parameters")] public MeleeSkill _meleeSkill; [VM_Label("🏹 Ranged Skill", tooltip: "long-range attack parameters")] public RangedSkill _rangedSkill; [VM_List("❤️ Add Health")] [VM_RangeSlider(0, 100)] [VM_Suffix("HP")] public List<int> _fieldList = new(); [VM_Dictionary("🎯 Stat Caps")] [VM_RangeSlider(0, 100)] [VM_Suffix("%")] public SerializedDictionary<string, int> _statCaps = new(); [VM_Title("NonSerialized Fields")] [VM_ShowInInspector] [VM_Label("Private")] [VM_Suffix("chars")] private string _privateValue = "some text ..."; [VM_ShowInInspector] [VM_Label("Property (get/set)")] [VM_Suffix("symbols", showOutside: true)] public string PropertyValue { get; set; } = "some text ..."; [System.Serializable] public class MeleeSkill { [VM_LabelWidth(0.4f)] [VM_Label("💥 Damage", tooltip: "damage range")] [VM_Range] [VM_Suffix("HP")] public Vector2Int _damage = new(0, 10); [VM_NestedAsGroup("☠️ Critical Hit")] public CriticalDamage _critical; } [System.Serializable] public class RangedSkill { [VM_LabelWidth(0.4f)] [VM_Label("💥 Shot damage", tooltip: "damage range")] [VM_Suffix("HP", width: 30)] [VM_Min(1)] public int _damage = 1; [VM_NestedAsGroup("☠️ Critical Hit")] public CriticalDamage _critical; [VM_Label("📏 Shot Distance", tooltip: "maximum shooting range")] [VM_Suffix("m", width: 30)] [VM_Min(0f)] public float _rangeDistance = 40f; [VM_Label("🎯 Number of Arrows", tooltip: "number of available shots")] [VM_Suffix("pcs", width: 30)] [VM_Min(0)] public int _numArrows = 1; } [System.Serializable] public class CriticalDamage { [VM_LabelWidth(0.4f)] [VM_Label("🚩 Applied", tooltip: "critical hit applying flag")] [VM_Suffix("on|off", showOutside: true, width: 30)] public bool _applied = false; [VM_Label("🎲 Probability", tooltip: "critical hit chance")] [VM_Suffix("%")] [VM_RangeSlider(1, 100)] public int _probability = 50; [VM_Label("✖️ Damage Multiplier", tooltip: "damage multiplier for critical hit")] [VM_Suffix("coef", showOutside: true)] [VM_RangeSlider(1f, 10f)] public float _multiplier = 2.5f; }
VM_LabelWidth
Description
Allows you to set the ratio of the label width to the available width.
Constructors
Parameters
- float width — 0: reset to default, (0..1]: ratio, >1: pixels
- string beforeGroup — apply before entering specified group (default: null)Applies to the defining group and all its children. And upon exiting the group, the value reverts to the parent group's setting.Even on hidden fields, [VM_LabelWidth] is still applied and affects subsequent fields in the same group.
Preview
Example Code
[VM_LabelWidth(140)] [VM_Label("🎥 Main Camera", tooltip: "reference to the camera in the scene")] [VM_Suffix("in scene")] public Camera _camera; [VM_LabelWidth(60)] [VM_Label("🧙 Unit", tooltip: "prefab model for the unit")] [VM_Suffix("prefab")] public GameObject _unit; [VM_LabelWidth(0.35f)] [VM_Label("❤️ Life", tooltip: "current amount of Health Points")] [VM_Suffix("HP")] [VM_Min(0)] public int _life = 1; [VM_LabelWidth(0.2f)] [VM_Label("🔮 Mana", tooltip: "current amount of Mana Points")] [VM_Suffix("MP")] [VM_Min(0)] public int _mana = 0; [VM_Label("👁️ Visibility", tooltip: "enemy visibility radius")] [VM_Suffix("m")] [VM_Min(1f)] public float _visibility = 5f; [VM_Label("⚔️ Melee Skill", tooltip: "сlose combat parameters")] public MeleeSkill _meleeSkill; [VM_HideLabel(useLabelWidth: true)] public CriticalDamage _critical; [VM_LabelWidth(0)] [VM_Label("🏹 Ranged Skill", tooltip: "long-range attack parameters")] public RangedSkill _rangedSkill; [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_LabelWidth(0.4f)] [VM_ShowInInspector] private string _privateString = "private field"; [VM_Label("Property (get/set)")] [VM_LabelWidth(0.5f)] [VM_ShowInInspector] public string PropertyString { get; set; } = "Property (get/set)"; [System.Serializable] public class CriticalDamage { [VM_LabelWidth(0.1f)] [VM_Label("🚩", tooltip: "critical hit applying flag")] [VM_Suffix("on|off", width: 30)] public bool _applied = false; [VM_Label("🎲", tooltip: "critical hit chance")] [VM_Suffix("%", width: 30)] [VM_RangeSlider(1, 100)] public int _probability = 50; [VM_Label("✖️", tooltip: "damage multiplier for critical hit")] [VM_RangeSlider(1f, 10f)] public float _multiplier = 2.5f; } [System.Serializable] public class MeleeSkill { [VM_LabelWidth(0.25f)] [VM_Label("💥 Damage", tooltip: "damage range")] [VM_Suffix("HP", width: 30)] public Vector2Int _damage = new(0, 10); [VM_NestedAsGroup("☠️ Critical Hit")] public CriticalDamage _critical; } [System.Serializable] public class RangedSkill { [VM_LabelWidth(0.4f)] [VM_Label("💥 Shot damage", tooltip: "damage range")] [VM_Suffix("HP", width: 30)] [VM_Min(1)] public int _damage = 1; [VM_NestedAsGroup("☠️ Critical Hit")] public CriticalDamage _critical; [VM_Label("📏 Shot Distance", tooltip: "maximum shooting range")] [VM_Suffix("m", width: 30)] [VM_Min(0f)] public float _rangeDistance = 40f; [VM_Label("🎯 Number of Arrows", tooltip: "number of available shots")] [VM_Suffix("pcs", width: 30)] [VM_Min(0)] public int _numArrows = 1; }
VM_HideLabel
Description
Allows to hide the field label.
Constructors
Parameters
- bool useLabelWidth — if true, preserves label width spacing but makes label invisible (default: false)
Preview
Example Code
[VM_Label("🧩 Prefab to Spawn")] public GameObject _fieldPrefab0; [VM_HideLabel(useLabelWidth: true)] public GameObject _fieldPrefab1; [VM_Title("🎲 Spawn Settings:", fontSize: 12)] [VM_HideLabel] public SpawnData _spawnData; [System.Serializable] public class SpawnData { [VM_Label("✅ Enabled")] [VM_Toggles] public bool _enabled = false; [VM_Label("🎲 Probability")] [VM_Suffix("%")] [VM_Clamp(0, 100)] public int _probability = 50; } [VM_Title("🎥 Camera:", fontSize: 12)] [VM_HideLabel] public Camera _camera; [VM_Title("NonSerialized Fields")] [VM_HideLabel(useLabelWidth: true)] [VM_ShowInInspector] private string _privateString = "private field"; [VM_HideLabel] [VM_ShowInInspector] public string PropertyString { get; set; } = "Property (get/set)";
VM_Checkbox
Description
Standard Unity checkbox with an optional description text on the right.
Constructors
Parameters
- string desc — description text to the right of the checkbox (default: null)
- string tooltipDesc — tooltip of the description text (default: null)
- string hexColorDesc — hex color for the description text (default: null)
Preview
Example Code
[VM_Label("🔊 Sound Enabler")] public bool _sound = true; [VM_LabelWidth(50)] [VM_EnableIf(nameof(_sound))] [VM_HideLabel(useLabelWidth: true)] [VM_Checkbox(desc: "Use background music?", tooltipDesc: "Hover here to see this tooltip", hexColorDesc: HexColor.Red600)] public bool _music = true; [VM_EnableIf(nameof(_sound))] [VM_HideLabel(useLabelWidth: true)] [VM_Checkbox(desc: "Use sound effects?", tooltipDesc: "Hover here to see this tooltip", hexColorDesc: HexColor.Emerald700)] public bool _effects = true; [VM_EnableIf(nameof(_sound))] [VM_HideLabel(useLabelWidth: true)] [VM_Checkbox(desc: "Use actor voices?", tooltipDesc: "Hover here to see this tooltip", hexColorDesc: HexColor.Blue600)] public bool _voice = true; [VM_LabelWidth(0)] [VM_Label("🛡️ Defense")] [VM_NestedInline] public DefenseData _defense; [VM_HideLabel] [VM_Checkbox(desc: "It can be used as a left toggle !", tooltipDesc: "Hover here to see this tooltip")] public bool _leftToggle = false; [VM_List("🎯 Hit flags")] [VM_Checkbox(desc: "Apply the skill damage ?", tooltipDesc: "Hover here to see this tooltip")] public List<bool> _fieldList = new(); [VM_Dictionary("🎯 Hit flags")] [VM_Checkbox(desc: "Apply the skill damage ?", tooltipDesc: "Hover here to see this tooltip")] public SerializedDictionary<string, bool> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Checkbox(desc: "Toggle visibility ?", tooltipDesc: "Hover here to see this tooltip")] [VM_ShowInInspector] private bool _privateToggle = false; [VM_Label("Property (get/set)")] [VM_Checkbox(desc: "Toggle availability ?", tooltipDesc: "Hover here to see this tooltip", hexColorDesc: HexColor.Blue600)] [VM_ShowInInspector] public bool PropertyToggle { get; set; } = true; [System.Serializable] public class DefenseData { [VM_Width(40, gap: 30)] [VM_HideLabel] [VM_Checkbox] public bool _enable = false; [VM_Label("Armor")] [VM_EnableIf(nameof(_enable))] public int _armor = 50; [VM_Label("Block")] [VM_Suffix("%")] [VM_EnableIf(nameof(_enable))] public float _blockChance = 10f; }
VM_Toggle
Description
Displays a single toggle button with an optional description text on the right.
Constructors
Parameters
- string name — button text (default: "On")
- float width — button width, where 0: auto, (0..1]: ratio of zone, >1: pixels (default: 0)
- string desc — description text to the right of the button (default: null)
- string tooltipDesc — tooltip of the description text (default: null)
- string hexColorDesc — hex color for the description text (default: null)Only supported on Boolean fields.
Preview
Example Code
[VM_Label("🔊 Sound Enabler")] [VM_Toggle(width: 40)] public bool _sound = true; [VM_LabelWidth(20)] [VM_EnableIf(nameof(_sound))] [VM_HideLabel(useLabelWidth: true)] [VM_Toggle(name: "Music", desc: "Use background music?", tooltipDesc: "Hover here to see this tooltip", hexColorDesc: HexColor.Red600, width: 90)] public bool _music = true; [VM_EnableIf(nameof(_sound))] [VM_HideLabel(useLabelWidth: true)] [VM_Toggle(name: "Effects", desc: "Use sound effects?", tooltipDesc: "Hover here to see this tooltip", hexColorDesc: HexColor.Emerald700, width: 90)] public bool _effects = true; [VM_EnableIf(nameof(_sound))] [VM_HideLabel(useLabelWidth: true)] [VM_Toggle(name: "Voice", desc: "Use actor voices?", tooltipDesc: "Hover here to see this tooltip", hexColorDesc: HexColor.Blue600, width: 90)] public bool _voice = true; [VM_LabelWidth(0)] [VM_Label("⚡ Power")] [VM_Toggle(name: "Enable")] public bool _power = true; [VM_Label("🛡️ Shield")] [VM_Toggle(name: "Active", desc: "Absorbs incoming damage ?", tooltipDesc: "Hover here to see this tooltip")] public bool _shield = true; [VM_Label("🏃 Speed Boost")] [VM_Toggle(name: "Enable", width: 70, desc: "Increases movement by 50% ?", tooltipDesc: "Hover here to see this tooltip", hexColorDesc: HexColor.Red600)] public bool _speedBoost = true; [VM_Label("🛡️ Defense")] [VM_NestedInline] public DefenseData _defense; [VM_HideLabel] [VM_Toggle(width: 40, desc: "It can be used as a left toggle", tooltipDesc: "Hover here to see this tooltip")] public bool _leftToggle = false; [VM_HideLabel] [VM_Toggle(name: "🚩", width: 22, desc: "It can be used with emoji symbols", tooltipDesc: "Hover here to see this tooltip")] public bool _leftToggleEmoji = false; [VM_List("🎯 Hit flags")] [VM_Toggle(name: "Hit", desc: "Apply the skill damage ?", tooltipDesc: "Hover here to see this tooltip")] public List<bool> _fieldList = new(); [VM_Dictionary("🎯 Hit flags")] [VM_Toggle(name: "Hit", desc: "Apply the skill damage ?", tooltipDesc: "Hover here to see this tooltip")] public SerializedDictionary<string, bool> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Toggle(name: "Show", desc: "Toggle visibility ?", tooltipDesc: "Hover here to see this tooltip", width: 60)] [VM_ShowInInspector] private bool _privateToggle = false; [VM_Label("Property (get/set)")] [VM_Toggle(name: "Enable", desc: "Toggle availability ?", tooltipDesc: "Hover here to see this tooltip", hexColorDesc: HexColor.Blue600)] [VM_ShowInInspector] public bool PropertyToggle { get; set; } = true; [System.Serializable] public class DefenseData { [VM_Width(40, gap: 30)] [VM_HideLabel] [VM_Toggle] public bool _enable = false; [VM_Label("Armor")] [VM_EnableIf(nameof(_enable))] public int _armor = 50; [VM_Label("Block")] [VM_Suffix("%")] [VM_EnableIf(nameof(_enable))] public float _blockChance = 10f; }
VM_Toggles
Description
Displays the boolean field as a toggle button with customizable content.
Constructors
Parameters
- string nameTrue — text displayed when value is True (default: "True")
- string nameFalse — text displayed when value is False (default: "False")
- string tooltipTrue — tooltip shown when value is True (default: null)
- string tooltipFalse — tooltip shown when value is False (default: null)
Preview
Example Code
[VM_Label("🛡️ Invincible")] [VM_Toggles] public bool _toggleDefault = false; [VM_Label("🔊 Sound Effects")] [VM_Toggles(nameTrue: "On", nameFalse: "Off", tooltipTrue: "Switch On", tooltipFalse: "Switch Off")] public bool _toggleVariant1 = false; [VM_HideLabel(useLabelWidth: true)] [VM_Toggles(nameTrue: "Enable", nameFalse: "Disable")] public bool _toggleVariant2 = false; [VM_List("⚙️ Ability Toggles")] [VM_Toggles] public List<bool> _fieldListToggle = new(); [VM_Dictionary("⚙️ Ability Toggles")] [VM_Toggles] public SerializedDictionary<string, bool> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Toggles(nameTrue: "Visible", nameFalse: "Hidden", tooltipTrue: "Visible Option", tooltipFalse: "Hidden Option")] [VM_ShowInInspector] private bool _privateToggle = false; [VM_Label("Property (get/set)")] [VM_Toggles(nameTrue: "Available", nameFalse: "Unavailable", tooltipTrue: "Available Option", tooltipFalse: "Unavailable Option")] [VM_ShowInInspector] private bool PropertyToggle { get; set; } = false;
VM_Enum
Description
Displays enum values as a horizontal row of toggle buttons or dropdown popup.
Constructors
Parameters
- int limitPerLine — max number of buttons per line (default: 0 = all in one line)
- int numLines — maximum number of lines in dropdown (default: 12)
- object[] variants — selective enum values to display (default: null = all)
- bool showToggles — true: toggle buttons, false: dropdown popup (default: true)
Preview
Example Code
[VM_Label("🧭 Move Direction")] [VM_Enum] public eDirection _enumTogles; [VM_Label("🎯 Attack Cross Direction")] [VM_Enum(variants: new object[] { eDirection.Up, eDirection.Down, eDirection.Left, eDirection.Right })] public eDirection _enumCrossTogles; [VM_Label("🎯 Attack None Direction")] [VM_Enum(limitPerLine: 4)] public eDirection _enumToglesLimit; [VM_Label("⚔️ Combat Style")] [VM_Enum] public CombatContext _enumToglesLabel; [VM_List("📋 AI Patrol Directions")] [VM_Enum] public List<eDirection> _fieldListEnum = new(); [VM_List("📋 AI Patrol Directions (MultiLine)")] [VM_Enum(limitPerLine: 3)] public List<eDirection> _fieldListEnumMultiLine = new(); [VM_Dictionary("📋 AI Patrol Directions")] [VM_Enum] public SerializedDictionary<string, eDirection> _fieldDictEnum = new(); [VM_Dictionary("📋 AI Patrol Directions (MultiLine)")] [VM_Enum(limitPerLine: 3)] public SerializedDictionary<string, eDirection> _fieldDictEnumMultiLine = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Enum(showToggles: false)] [VM_ShowInInspector] private eDirection _privateEnum; [VM_Label("Property (get/set)")] [VM_Enum(showToggles: false, variants: new object[] { eDirection.Up, eDirection.Down, eDirection.Left, eDirection.Right })] [VM_ShowInInspector] public eDirection PropertyEnum { get; set; } public enum eDirection { Right, Left, Up, Down, UpLeft, UpRight, DownLeft, DownRight } public enum CombatContext { [VM_Label("Close quarters", tooltip: "Close-quarters combat")] Melee, [VM_Label("Targeting shooting", tooltip: "Ranged attack on a target")] Shooting, [VM_Label("Fire exchange", tooltip: "Ranged exchange of fire")] Firefight, }
VM_EnumBits
Description
Displays flags enum as a horizontal row of toggle buttons or dropdown options of toggleable checkboxes.
Constructors
Parameters
- int limitPerLine — max number of buttons per line (default: 0 = all in one line)
- int numLines — maximum number of lines in dropdown (default: 12)
- object[] variants — selective enum values to display (default: null = all)
- bool showToggles — true: toggle buttons, false: dropdown popup (default: true)
Preview
Example Code
[VM_Label("🧭 Allowed Directions")] [VM_EnumBits] public eDirectionBits _enumBits; [VM_Label("🎯 Shooting Cross Direction")] [VM_EnumBits(variants: new object[] { eDirectionBits.Up, eDirectionBits.Down, eDirectionBits.Left, eDirectionBits.Right })] public eDirectionBits _shootingCrossEnumBits; [VM_Label("🎯 Shooting None Directions")] [VM_EnumBits(limitPerLine: 4)] public eDirectionBits _shootingEnumBits; [VM_List("🗺️ Patrol Directions")] [VM_EnumBits] public List<eDirectionBits> _fieldList = new(); [VM_List("🗺️ Patrol Directions (limit = 4)")] [VM_EnumBits(limitPerLine: 4)] public List<eDirectionBits> _fieldListLimit = new(); [VM_Dictionary("🗺️ Patrol Directions")] [VM_EnumBits] public SerializedDictionary<string, eDirectionBits> _fieldDict = new(); [VM_Dictionary("🗺️ Patrol Directions (limit = 4)")] [VM_EnumBits(limitPerLine: 4)] public SerializedDictionary<string, eDirectionBits> _fieldDictLimit = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_EnumBits(showToggles: false)] [VM_ShowInInspector] private eDirectionBits _privateEnumBits; [VM_Label("Property (get/set)")] [VM_EnumBits(showToggles: false, variants: new object[] { eDirectionBits.Up, eDirectionBits.Down, eDirectionBits.Left, eDirectionBits.Right })] [VM_ShowInInspector] public eDirectionBits PropertyEnumBits { get; set; } public enum eDirectionBits { Right = 1 << 0, Left = 1 << 1, Up = 1 << 2, Down = 1 << 3, UpLeft = 1 << 4, UpRight = 1 << 5, DownLeft = 1 << 6, DownRight = 1 << 7, }
VM_Range
Description
Displays Vector2/Vector2Int as two fields with a separator.
Constructors
Parameters
- string separator — text between fields (default: "-")
- string suffix — suffix inside each field (default: null)
- string suffixCallback — callback to override suffix dynamically (default: null)
Preview
Example Code
[VM_Label("⚔️ Damage")] [VM_Range] public Vector2Int _damage = new(10, 25); [VM_Label("🌡️ Temperature")] [VM_Range(separator: "~", suffix: "°C")] [VM_Suffix("t")] public Vector2 _temperature = new(-10f, 35f); [VM_Label("📏 Distance")] [VM_Range(separator: "..")] [VM_Suffix("m")] public Vector2 _distance = new(0f, 100f); [VM_Label("⏱️ Duration")] [VM_Range] [VM_Suffix("sec")] public Vector2 _duration = new(0.5f, 3.0f); [VM_List("🎯 Ability Range")] [VM_Range(separator: "...")] [VM_Suffix("meter")] public List<Vector2Int> _fieldList = new(); [VM_Dictionary("🎯 Ability Range")] [VM_Range(separator: "...")] [VM_Suffix("meter")] public SerializedDictionary<string, Vector2Int> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_ShowInInspector] [VM_Label("Private")] [VM_Range(suffix: "HP")] private Vector2Int _privateRange = new(0, 100); [VM_Label("Property (get/set)")] [VM_Range(separator: "/")] [VM_Suffix("mana")] [VM_ShowInInspector] public Vector2 PropertyRange { get; set; } = new(1f, 10f);
VM_MinMaxSlider
Description
Displays a slider for selecting a range within defined limits.
Constructors
Parameters
- float minValue — minimum allowed value for the range
- float maxValue — maximum allowed value for the range
Preview
Example Code
[VM_Label("⚔️ Damage Range")] [VM_MinMaxSlider(0, 10)] [VM_Suffix("m")] public Vector2Int _fieldIntVector = Vector2Int.up * 5; [VM_Label("🎲 Spawn Distance")] [VM_MinMaxSlider(-1, 1, suffix: "m")] public Vector2 _fieldVector = Vector2.up; [VM_Label("❤️ Health Regen")] [VM_Suffix("[0,10]", showOutside: true)] [VM_MinMaxSlider(minValue: 0, maxValue: 10)] public Vector2Int _fieldIntVectorSuffix = Vector2Int.up * 5; [VM_List("📊 Loot Drop Ranges")] [VM_MinMaxSlider(0, 100)] [VM_Suffix("m")] public List<Vector2Int> _fieldList = new(); [VM_Dictionary("📊 Loot Drop Ranges")] [VM_MinMaxSlider(0, 100)] [VM_Suffix("m")] public SerializedDictionary<string, Vector2Int> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Suffix("K")] [VM_MinMaxSlider(-1, 1)] [VM_ShowInInspector] private Vector2 _privateMinMax = Vector2.up; [VM_Label("Property (get/set)")] [VM_Suffix("[-1,1]", showOutside: true)] [VM_MinMaxSlider(-1, 1)] [VM_ShowInInspector] public Vector2 PropertyMinMax { get; set; } = Vector2.up;
VM_RangeSlider
Description
Displays a slider to adjust the value within a defined range.
Constructors
VM_RangeSlider (float fromValue, string toCallback, ...)
VM_RangeSlider (string fromCallback, float toValue, ...)
VM_RangeSlider (string fromCallback, string toCallback, ...)
Parameters
- float fromValue — minimum value
- float toValue — maximum value
- string fromCallback — minimum callback name
- string toCallback — maximum callback name
- string fromHexColor — field background color at minimum (default: null)
- string toHexColor — field background color at maximum (default: null)
- string prefix — text added before the value inside the field (default: null)
- string suffix — text added after the value inside the field (default: null)
- float fieldWidth — width of the editable number field (default: 60)
Preview
Example Code
[VM_Label("Max Power")] [VM_Min(1)] public int _maxPower = 3; [VM_Label("⚔️ Attack Power")] [VM_RangeSlider(0, nameof(_maxPower))] public int _fieldInt = 2; [VM_Label("🎯 Accuracy")] [VM_RangeSlider(0, 100, toHexColor: HexColor.Red, suffix: "%")] public int _fieldAccuracy = 75; [VM_Label("💰 Price")] [VM_RangeSlider(0, 1000, prefix: "$")] public int _fieldPrice = 250; [VM_Label("🛡️ Defense Rating")] [VM_Suffix("%")] [VM_RangeSlider(0, 10)] public int _fieldIntSuffix = 2; [VM_Label("🏃 Evasion Chance")] [VM_Suffix("[1,-1]", showOutside: true, width: 30)] [VM_RangeSlider(1, -1)] public float _fieldFloatSuffix = 0.5f; [VM_List("📊 Skill Levels")] [VM_RangeSlider(0, 100, fromHexColor: HexColor.Red, toHexColor: HexColor.Green)] [VM_Suffix("%")] public List<int> _fieldList = new(); [VM_Dictionary("📊 Skill Levels")] [VM_RangeSlider(0, 100, fromHexColor: HexColor.Red, toHexColor: HexColor.Green)] [VM_Suffix("%")] public SerializedDictionary<string, int> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Suffix("MP")] [VM_RangeSlider(0, 10, fieldWidth: 95)] [VM_ShowInInspector] private float _privateRange = 0.5f; [VM_Label("Property (get/set)")] [VM_Suffix("[1,-1]", showOutside: true, width: 30)] [VM_RangeSlider(1, -1)] [VM_ShowInInspector] public float PropertyRange { get; set; } = 0.5f;
VM_AnchoredSlider
Description
Displays a slider that highlights values <color=#22AA44>above</color> and <color=red>below</color> the anchor point.
Constructors
VM_AnchoredSlider (float fromValue, string toCallback, ...)
VM_AnchoredSlider (string fromCallback, float toValue, ...)
VM_AnchoredSlider (string fromCallback, string toCallback, ...)
Parameters
- float fromValue — minimum value
- float toValue — maximum value
- string fromCallback — minimum callback name
- string toCallback — maximum callback name
- float anchorValue — anchor point for color highlighting (default: 0)
- string prefix — text added before the value inside the field (default: null)
- string suffix — text added after the value inside the field (default: null)
- bool flipColors — swap red↔green (default: false, above=red/below=green)
- float fieldWidth — width of the editable number field (default: 60)
Preview
Example Code
[VM_Label("🔊 Volume")] [VM_AnchoredSlider(0, 2, anchorValue: 1, fieldWidth: 80)] public float _volume = 1f; [VM_Label("⚖️ Weight Factor")] [VM_AnchoredSlider(0, 10, anchorValue: 5)] public int _weight = 5; [VM_Label("🌡️ Temperature")] [VM_AnchoredSlider(-20, 40, anchorValue: 20, flipColors: true)] [VM_Suffix("°C")] public int _temperature = 20; [VM_Label("💵 Balance")] [VM_AnchoredSlider(-1000, 1000, anchorValue: 0, prefix: "$")] public int _balance = 100; [VM_Label("⚠️ Hazard Level")] [VM_AnchoredSlider(0, 100, anchorValue: 50, suffix: "%", flipColors: true)] public int _hazard = 50; [VM_List("📊 List of weights")] [VM_AnchoredSlider(50, 150, anchorValue: 90, flipColors: true)] [VM_Suffix("kg")] public List<int> _fieldList = new(); [VM_Dictionary("📊 List of weights")] [VM_AnchoredSlider(50, 150, anchorValue: 90, flipColors: true)] [VM_Suffix("kg")] public SerializedDictionary<string, int> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_ShowInInspector] [VM_Label("Private")] [VM_AnchoredSlider(0, 100, anchorValue: 50)] [VM_Suffix("%")] private int _privateValue = 50; [VM_ShowInInspector] [VM_Label("Property (get/set)")] [VM_AnchoredSlider(0, 1, anchorValue: 0.5f)] public float PropertyValue { get; set; } = 0.5f;
VM_BonusSlider
Description
Displays a slider that highlights <color=#22AA44>+bonuses</color> and <color=red>-penalties</color> relative to Zero.
Constructors
VM_BonusSlider (float fromValue, string toCallback, ...)
VM_BonusSlider (string fromCallback, float toValue, ...)
VM_BonusSlider (string fromCallback, string toCallback, ...)
Parameters
- float fromValue — minimum value
- float toValue — maximum value
- string fromCallback — minimum callback name
- string toCallback — maximum callback name
- string suffix — text added after the value inside the field (default: null)
- bool flipColors — swap red↔green (default: false, positive = red / negative = green)
- float fieldWidth — width of the editable number field (default: 60)
Preview
Example Code
[VM_Label("🍀 Luck Modifier")] [VM_BonusSlider(0, 1)] [VM_Suffix("[0..1]", showOutside: true, width: 30)] public float _fieldFloat = 0; [VM_Label("🧊 Frost Resistance")] [VM_Suffix("[0..-1]", showOutside: true, width: 30)] [VM_BonusSlider(0, -1)] public float _fieldFloatInvert = 0.0f; [VM_Label("💀 Damage Taken")] [VM_BonusSlider(-10, 10, flipColors: true)] [VM_Suffix("HP")] public int _damageTaken = 0; [VM_Label("⚔️ Strength Buff")] [VM_BonusSlider(-10, 10)] [VM_Suffix("AP")] public int _fieldInt = 0; [VM_HideLabel(useLabelWidth: true)] [VM_Suffix("[10..-10]", showOutside: true)] [VM_BonusSlider(10, -10)] public int _fieldIntInvert = 0; [VM_List("📊 Stat Modifiers")] [VM_BonusSlider(-10, 10, fieldWidth: 80)] [VM_Suffix("AP")] public List<int> _fieldList = new(); [VM_Dictionary("📊 Stat Modifiers")] [VM_BonusSlider(-10, 10, fieldWidth: 80)] [VM_Suffix("AP")] public SerializedDictionary<string, int> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_BonusSlider(-1, 1, fieldWidth: 95)] [VM_Suffix("K")] [VM_ShowInInspector] private float _privateBonus = 0f; [VM_Label("Property (get/set)")] [VM_Suffix("[0..10]", showOutside: true, width: 30)] [VM_BonusSlider(0, 10)] [VM_ShowInInspector] public float PropertyBonus { get; set; } = 0f;
VM_ProgressBar
Description
Displays the value as a colored progress bar.
Constructors
VM_ProgressBar (float fromValue, string toCallback, ...)
VM_ProgressBar (string fromCallback, float toValue, ...)
VM_ProgressBar (string fromCallback, string toCallback, ...)
Parameters
- float fromValue — minimum value
- float toValue — maximum value
- string fromCallback — minimum callback name
- string toCallback — maximum callback name
- string hexColorBar — bar fill color (default: HexColor.Sky500)
- string hexColorBackground — background color (default: HexColor.Neutral400)
- string hexColorFrame — bar frame color (default: HexColor.Neutral500)
- string suffix — text suffix after the value (default: null)
- bool showFromValue — display min values (default: true)
- bool showToValue — display max values (default: true)
Preview
Example Code
[VM_Label("Max Life")] [VM_Suffix("HP")] [VM_Min(1)] public int _maxLife = 100; [VM_Label("Health")] [VM_ProgressBar(0, nameof(_maxLife), hexColorBar: HexColor.Orange500)] [VM_Suffix("HP")] public int _health = 50; [VM_Label("Mana")] [VM_ProgressBar(0, 100, suffix: " MP")] public int _mana = 80; [VM_Label("Stamina")] [VM_ProgressBar(0, 1, hexColorBar: HexColor.Green400, suffix: " SP", showFromValue: false)] public float _stamina = 0.25f; [VM_ProgressBar(0, 100, suffix: " %", hexColorBar: HexColor.Green, showFromValue: false, showToValue: false)] public int _attack = 50; [VM_List("📊 Skill Damage")] [VM_ProgressBar(0, 100)] [VM_Suffix("HP")] public List<int> _fieldList = new(); [VM_Dictionary("📊 Skill Damage")] [VM_ProgressBar(0, 100)] [VM_Suffix("HP")] public SerializedDictionary<string, int> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_ProgressBar(0, 1)] [VM_ShowInInspector] private float _privateBar = 0.15f; [VM_Label("Property (get/set)")] [VM_ProgressBar(0, 100, hexColorBar: HexColor.Red)] [VM_ShowInInspector] public int PropertyBar { get; set; } = 35;
VM_SegmentedBar
Description
Displays the value as a segmented colored progress bar.
Constructors
VM_SegmentedBar (string numSegmentsCallback, ...)
Parameters
- int numSegments — number of segments in the bar
- string numSegmentsCallback — callback name returning number of segments
- int stepSize — value step per segment (default: 1)
- string hexColorBar — segment fill color (default: HexColor.Sky500)
- string hexColorBackground — background color (default: HexColor.Neutral400)
- string hexColorFrame — segment frame color (default: HexColor.Neutral500)
- bool showValueInSegment — display value inside segments (default: true)
- bool showField — show editable field beside bar (default: true)
- float fieldWidth — width of the editable field (default: 50)
- string fieldListCallback — list name for named values of field (default: null)
- string prefix — text added before the value inside the field (default: null)
- string suffix — text added after the value inside the field (default: null)
Preview
Example Code
[VM_Label("Stat cap")] [VM_Suffix("lvl")] [VM_RangeSlider(2, 12)] public int _maxParam = 6; [VM_Label("Attack")] [VM_SegmentedBar(nameof(_maxParam), hexColorBar: HexColor.Lime200, showField: false)] [VM_Suffix("HP", showOutside: true)] public int _attack = 3; [VM_Label("Defense")] [VM_Suffix("%")] [VM_SegmentedBar(nameof(_maxParam), hexColorBar: HexColor.Green600)] public int _defense = 2; [VM_Label("Armor")] [VM_SegmentedBar(nameof(_maxParam), hexColorBar: HexColor.Yellow600, showValueInSegment: false)] public int _armour = 4; [VM_Label("Damage")] [VM_SegmentedBar(4, stepSize: 25, hexColorBar: HexColor.Fuchsia600, suffix: " HP")] public int _damage = 50; [VM_Label("Speed")] [VM_SegmentedBar(4, hexColorBar: HexColor.Yellow100, fieldWidth: 120, fieldListCallback: nameof(SpeedNameList))] public int _speed = 2; DropdownItems<int> SpeedNameList => new() { { "Very Slow", 0 }, { "Slow" , 1 }, { "Normal" , 2 }, { "Fast" , 3 }, { "Very Fast", 4 }, }; [VM_List("📊 Skill Levels")] [VM_SegmentedBar(10, fieldWidth: 70)] [VM_Suffix("Lvl")] public List<int> _fieldList = new(); [VM_Dictionary("📊 Skill Levels")] [VM_SegmentedBar(10, fieldWidth: 70)] [VM_Suffix("Lvl")] public SerializedDictionary<string, int> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_SegmentedBar(5, prefix: "x ")] [VM_ShowInInspector] private int _privateBar = 4; [VM_Label("Property (get/set)")] [VM_SegmentedBar(10, hexColorBar: HexColor.Red)] [VM_ShowInInspector] public int PropertyBar { get; set; } = 3;
VM_Multiline
Description
Displays the string field as a resizable multi-line text area.
Constructors
Preview
Example Code
[VM_Label("Unity string")] public string _unityDefault = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."; [VM_Label("📜 Multiline-string")] [VM_Multiline] public string _fieldString = string.Empty; [VM_HideLabel] [VM_Multiline] public string _fieldStringHide = string.Empty; [VM_List("📋 Multiline-string List")] [VM_Multiline] public List<string> _fieldList = new(); [VM_Dictionary("📋 Multiline-string Dictionary")] [VM_Multiline] public SerializedDictionary<string, string> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Multiline] [VM_ShowInInspector] private string _privateMultiLine = string.Empty; [VM_Label("Property (get/set)")] [VM_Multiline] [VM_ShowInInspector] public string PropertyMultiLine { get; set; } = string.Empty;
VM_Tag
Description
Displays a dropdown with Unity tags.
Constructors
Preview
Example Code
[VM_Label("🏷️ Enemy Tag")] [VM_Tag] public string _tagName; [VM_List("📋 Targetable Tags")] [VM_Tag] public List<string> _fieldList = new(); [VM_Dictionary("📋 Targetable Tags")] [VM_Tag] public SerializedDictionary<string, string> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Tag] [VM_ShowInInspector] private string _privateTag = ""; [VM_Label("Property (get/set)")] [VM_Tag] [VM_ShowInInspector] public string PropertyTag { get; set; } = "";
VM_Layer
Description
Displays a dropdown with Unity physics layers.
Constructors
Preview
Example Code
[VM_Label("🎯 Raycast Layer")] [VM_Layer] public string _layerName; [VM_Label("🛡️ Collision Layer")] [VM_Layer] public int _layerIndex = -1; [VM_List("📋 Interaction Layers")] [VM_Layer] public List<int> _fieldList = new(); [VM_Dictionary("📋 Interaction Layers")] [VM_Layer] public SerializedDictionary<string, string> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Layer] [VM_ShowInInspector] private string _privateLayer = ""; [VM_Label("Property (get/set)")] [VM_Layer] [VM_ShowInInspector] public string PropertyLayer { get; set; } = "";
VM_SortingLayer
Description
Displays a dropdown with Unity sorting layers.
Constructors
Preview
Example Code
[VM_Label("🎨 Sprite Layer")] [VM_SortingLayer] public string _layerName; [VM_Label("🖼️ UI Layer")] [VM_SortingLayer] public int _layerIndex = -1; [VM_List("📋 VFX Layers")] [VM_SortingLayer] public List<int> _fieldList = new(); [VM_Dictionary("📋 VFX Layers")] [VM_SortingLayer] public SerializedDictionary<string, string> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_SortingLayer] [VM_ShowInInspector] private string _privateLayer = ""; [VM_Label("Property (get/set)")] [VM_SortingLayer] [VM_ShowInInspector] public string PropertyLayer { get; set; } = "";
VM_AnimationCurve
Description
Customizes the AnimationCurve editor appearance.
Constructors
Parameters
- string hexColor — curve line color (default: null)
- float width — 0: auto, (0..1]: ratio of zone, >1: pixels (default: 0)Only supported on AnimationCurve fields.
Preview
Example Code
[VM_Label("📈 Damage Falloff")] [VM_AnimationCurve(width: 0.6f, maxX: 10, maxY: 10)] public AnimationCurve curve = AnimationCurve.EaseInOut(0, 0, 10, 10); [VM_List("🎯 Ability Scaling Curves", onAddMethod: nameof(OnListAddMethod))] [VM_AnimationCurve(hexColor: HexColor.Red)] public List<AnimationCurve> _fieldList = new(); void OnListAddMethod(int index) { _fieldList[index] = AnimationCurve.Linear(0, 0, 1, 1); } [VM_Dictionary("📋 Patrol Agents", onAddMethod: nameof(OnDictAddMethod))] [VM_AnimationCurve(hexColor: HexColor.Red)] public SerializedDictionary<string, AnimationCurve> _fieldDict = new(); void OnDictAddMethod(string key) { _fieldDict[key] = AnimationCurve.Linear(0, 0, 1, 1); } [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_AnimationCurve(hexColor: HexColor.Magenta, width: 120)] [VM_ShowInInspector] private AnimationCurve _privateCurve = AnimationCurve.Linear(0, 0, 1, 1); [VM_Label("Property (get/set)")] [VM_AnimationCurve(hexColor: HexColor.Blue600)] [VM_ShowInInspector] public AnimationCurve PropertyTag { get; set; } = AnimationCurve.Constant(0, 1, 0.5f);
VM_AnimatorParameter
Description
Displays a dropdown with animator parameters.
Constructors
VM_AnimatorParameter (string animatorControllerName, AnimatorControllerParameterType animatorParamType)
Parameters
- string animatorControllerName — name of field holding RuntimeAnimatorController
- AnimatorControllerParameterType animatorParamType — filter by parameter type (Bool, Int, Float, Trigger)
Preview
Example Code
[VM_Required] [VM_Label("🎬 Character Animator")] [VM_AssetObjectsOnly] public RuntimeAnimatorController _animatorController; [VM_Label("All Parameters")] [VM_AnimatorParameter(nameof(_animatorController))] public string _allParamName; [VM_Label("Boolean Only")] [VM_AnimatorParameter(nameof(_animatorController), AnimatorControllerParameterType.Bool)] public int _paramHashBool; [VM_Label("Integer Only")] [VM_AnimatorParameter(nameof(_animatorController), AnimatorControllerParameterType.Int)] public int _paramHashInt; [VM_Label("Float Only")] [VM_AnimatorParameter(nameof(_animatorController), AnimatorControllerParameterType.Float)] public int _paramHashFloat; [VM_Label("Trigger Only")] [VM_AnimatorParameter(nameof(_animatorController), AnimatorControllerParameterType.Trigger)] public int _paramHashTrigger; [VM_List("📋 List of Parameters")] [VM_AnimatorParameter(nameof(_animatorController))] public List<string> _fieldList = new(); [VM_Dictionary("📋 Dictionary of Parameters")] [VM_AnimatorParameter(nameof(_animatorController))] public SerializedDictionary<string, string> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_AnimatorParameter(nameof(_animatorController), AnimatorControllerParameterType.Trigger)] [VM_ShowInInspector] private int _privateParameterTrigger; [VM_Label("Property (get/set)")] [VM_AnimatorParameter(nameof(_animatorController), AnimatorControllerParameterType.Trigger)] [VM_ShowInInspector] public int PropertyParameter { get; set; }
VM_Scene
Description
The [VM_Scene] attribute displays a dropdown with scenes from Build Settings.
Constructors
Preview
Example Code
[VM_Title("Unity Scene", fontSize: 16, thicknessLine: 0, align: eAlign.Center)] [VM_Label("🏰 Dungeon Scene")] [VM_Scene] public string sceneName; [VM_Label("🌍 World Scene Index")] [VM_Scene] public int sceneIndex = -1; [VM_List("📜 Quest Scenes")] [VM_Scene] public List<int> _fieldList = new(); [VM_Dictionary("📜 Quest Scenes")] [VM_Scene] public SerializedDictionary<string, int> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Scene] [VM_ShowInInspector] private int _privateScene = -1; [VM_Label("Property (get/set)")] [VM_Space(0, after: 10)] [VM_Scene] [VM_ShowInInspector] public int PropertyScene { get; set; } = -1; [VM_Title("Addressable Scene", fontSize: 16, thicknessLine: 0, align: eAlign.Center)] [VM_Label("🗺️ Arena Scene")] [VM_Scene] public AssetReferenceScene _addressableScene; [VM_List("⚔️ Battle Scenes")] [VM_Scene] public List<AssetReferenceScene> _fieldListAddressableScenes = new(); [VM_Dictionary("⚔️ Battle Scenes")] [VM_Scene] public SerializedDictionary<string, AssetReferenceScene> _fieldDictAddressableScenes = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Scene] [VM_ShowInInspector] private AssetReferenceScene _privateAddressableScene; [VM_Label("Property (get/set)")] [VM_Scene] [VM_ShowInInspector] public AssetReferenceScene PropertyAddressableScene { get; set; } = null;
VM_Prefab
Description
Provides an interactive 3D preview (Rotate — mouse drag, Zoom — Ctrl/Cmd + mouse wheel) with mesh visibility control and Animator state machine support.AnimationTab
Constructors
Parameters
- int size — preview size in pixels (default: 256)
- bool stretchWidth — stretch the preview area to available width (default: true)
Preview
Example Code
[VM_TabGroup("AnimationTab", "Usage Prefab")] [VM_HideLabel] [VM_Prefab(onInit: nameof(OnInit), onChangedVisibleMeshes: nameof(OnChangedVisibleMeshes), onSetTrigger: nameof(OnSetTrigger), onAnimationEvent: nameof(OnAnimEvent))] public GameObject _assetPrefab; private List<string> OnInit(List<string> boneNames) { print("OnInit: " + string.Join(", ", boneNames)); BoneNames = boneNames; return _visibleMeshNames; } private void OnChangedVisibleMeshes() { print("OnChangedVisibleMeshes: " + string.Join(", ", _visibleMeshNames)); } private void OnSetTrigger(string triggerName, IPlayerFX player) { Debug.Log($"Trigger called: {triggerName}"); } void OnAnimEvent(string eventName, IPlayerFX player) { Debug.Log($"Animation event: {eventName}"); foreach (var data in _listEvents) { if (eventName == data._eventName) player.Add(data._scriptableFX, data._boneName, data._bindToBone); } } [VM_HideInInspector] public List<string> _visibleMeshNames = new(); static List<string> BoneNames = new(); [RuntimeInitializeOnLoadMethod] static void ResetStatics() { BoneNames ??= new(); } [System.Serializable] public class EventData { [VM_Label("🎬 Event Name")] public string _eventName; [VM_Label("🦴 Bone Attachment")] [VM_Dropdown(nameof(BoneNames), null)] public string _boneName; [VM_Label("📌 Binding Type")] [VM_Toggles(nameTrue: "To bone", nameFalse: "World")] public bool _bindToBone = false; [VM_Label("✨ Particle Effect")] [VM_Scriptable(assetsPathToCreate: "ScriptableObjects/FX/")] public VM_SimpleFX _scriptableFX; } [VM_TabGroup("AnimationTab")] [VM_List("⚡ Animation Events", nameRefHeaderNested: nameof(EventData._eventName))] public List<EventData> _listEvents = new(); [VM_TabGroup("RestrictedTab", "Prefab variants")] [VM_Label("🏗️ Without Animation")] [VM_Prefab(hideAnimatorGUI: true)] public GameObject _assetPrefabWithoutAnimation0; [VM_TabGroup("RestrictedTab")] [VM_Label("📦 Without Controls")] [VM_Prefab(hideMeshesGUI: true, hideAnimatorGUI: true, stretchWidth: false)] public GameObject _assetPrefabWithoutAnimation1; [VM_TabGroup("RestrictedTab")] [VM_Label("🌐 Addressable")] [VM_Prefab] public AssetReferencePrefab _assetAddressablePrefab; [VM_TabGroup("ArrayTab", "Prefab Into Array")] [VM_List("🗡️ Prefabs")] [VM_Prefab(size: 128)] public List<GameObject> _fielsList = new(); [VM_TabGroup("ArrayTab")] [VM_List("🛡️ Addressable Prefab")] [VM_Prefab(size: 128)] public List<AssetReferencePrefab> _fieldListAddressable = new(); [VM_TabGroup("ArrayTab")] [VM_Dictionary("🗡️ Prefabs")] [VM_Prefab(size: 128)] public SerializedDictionary<string, GameObject> _fieldDict = new(); [VM_TabGroup("ArrayTab")] [VM_Dictionary("🛡️ Addressable Prefab")] [VM_Prefab(size: 128)] public SerializedDictionary<string, AssetReferencePrefab> _fieldDictAddressable = new(); [VM_TabGroup("NonSerialized", "NonSerialized")] [VM_Label("Private")] [VM_Prefab] [VM_ShowInInspector] private GameObject _privatePrefab; [VM_TabGroup("NonSerialized")] [VM_Label("Property (get/set)")] [VM_Prefab(stretchWidth: false)] [VM_ShowInInspector] public GameObject PropertyPrefab { get; set; } = null;
VM_SimplePrefab
Description
Provides a simplified 3D prefab preview without mesh/animator controls.
Constructors
Parameters
- int size — preview size in pixels (default: 128)
- bool stretchWidth — stretch the preview area to available width (default: false)
- bool showGrid — display grid in preview (default: true)
- bool showAxes — display coordinate axes in preview (default: true)
Preview
Example Code
[VM_Label("🗡️ Weapon Model")] [VM_SimplePrefab] public GameObject _assetPrefabSimple; [VM_List("📋 Prop Models")] [VM_SimplePrefab(showGrid: false, showAxes: false, stretchWidth: true)] public List<GameObject> _fieldList; [VM_List("📋 Prop Models (Addressable)")] [VM_SimplePrefab(showGrid: false, showAxes: false, stretchWidth: true)] public List<AssetReferencePrefab> _fieldListAddressable; [VM_Dictionary("📋 Prop Models")] [VM_SimplePrefab(showGrid: false, showAxes: false, stretchWidth: true)] public SerializedDictionary<string, GameObject> _fieldDict = new(); [VM_Dictionary("📋 Prop Models (Addressable)")] [VM_SimplePrefab(showGrid: false, showAxes: false, stretchWidth: true)] public SerializedDictionary<string, AssetReferencePrefab> _fieldDictAddressable = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_SimplePrefab(size: 96, showGrid: false)] [VM_ShowInInspector] private GameObject _privatePrefab; [VM_Label("Property (get/set)")] [VM_SimplePrefab(stretchWidth: true)] [VM_ShowInInspector] public GameObject PropertyPrefab { get; set; } = null;
VM_Material
Description
Displays a thumbnail preview of the material.
Constructors
Parameters
- int size — preview thumbnail size in pixels (default: 128, minimum: 16)
Preview
Example Code
[VM_Label("🧱 Armor Material")] [VM_Material] public Material _assetMaterial; [VM_List("📋 Terrain Materials")] [VM_Material(size: 64, stretchWidth: true)] public List<Material> _fieldListMaterial = new(); [VM_Dictionary("📋 Terrain Materials")] [VM_Material(size: 64, stretchWidth: true)] public SerializedDictionary<string, Material> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Material(size: 32)] [VM_ShowInInspector] private Material _privateMaterial; [VM_Label("Property (get/set)")] [VM_Material(size: 96, stretchWidth: true)] [VM_ShowInInspector] public Material PropertyMaterial { get; set; } = null;
VM_Image
Description
Displays a thumbnail preview of Sprite or Texture.
Constructors
Parameters
- int size — preview thumbnail size (minimum: 32) in pixels (default: 128)
- bool stretchWidth — stretch the preview area to available width (default: false)
- bool fitSmallImage — upscale small images to fill the preview area (default: false)
- bool showSizeImage — display native image dimensions at the bottom of the preview (default: true)
- bool showOnChecker — show checkerboard pattern behind transparent areas (default: true)
- eAlign align — position of the preview square in the field (default: eAlign.Left)
Preview
Example Code
[VM_Label("🎨 Character Sprite")] [VM_Image] public Sprite _assetSprite; [VM_Label("🗺️ WorldMap Texture")] [VM_Image(size: 256, stretchWidth: true)] public Texture _assetTexture; [VM_List("🎒 Inventory Sprites")] [VM_Image(size: 48, stretchWidth: true, showSizeImage: false)] public List<Sprite> _fieldList = new(); [VM_Dictionary("🖼️ Loading Screen Textures")] [VM_Image(size: 64, align: eAlign.Center)] public SerializedDictionary<string, Texture> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Image(size: 64, fitSmallImage: true, showOnChecker: false, align: eAlign.Right)] [VM_ShowInInspector] private Texture _privateTexture; [VM_Label("Property (get/set)")] [VM_Image(size: 64, stretchWidth: true)] [VM_ShowInInspector] public Texture PropertyTexture { get; set; } = null;
VM_Audio
Description
Adds audio preview and playback controls to the field.
Constructors
Preview
Example Code
[VM_Label("🔊 Sword Swing SFX")] [VM_Audio] public AudioClip _fieldClip; [VM_List("📋 Footstep Sounds")] [VM_Audio] public List<AudioClip> _fieldList = new(); [VM_Dictionary("📋 Footstep Sounds")] [VM_Audio] public SerializedDictionary<string, AudioClip> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Audio] [VM_ShowInInspector] private AudioClip _privateAudioClip; [VM_Label("Property (get/set)")] [VM_Audio] [VM_ShowInInspector] public AudioClip PropertyAudioClip { get; set; } = null;
VM_Scriptable
Description
Enables inline creation and editing of ScriptableObjects.
Constructors
Parameters
- string assetsPathToCreate — relative path inside Assets folder (default: null)
- bool showCreate — show button to create a new SO asset (default: false)
Preview
Example Code
[VM_Label("📦 Game Config")] [VM_Scriptable] public ScriptableObject _fieldSO; [VM_Label("🧪 Potion Recipe")] [VM_Scriptable(assetsPathToCreate: "ScriptableObjects/", showCreate: true)] public SimpleSO _fieldSimpleSO; [VM_Label("⚔️ Weapon Stats")] [VM_Scriptable(assetsPathToCreate: "ScriptableObjects/", showCreate: true)] public ComplexSO _fieldComplexSO; [VM_List("📋 Loot Table Entries")] [VM_Scriptable] public List<ComplexSO> _fieldList = new(); [VM_Dictionary("📋 Loot Table Entries")] [VM_Scriptable] public SerializedDictionary<string, ComplexSO> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Scriptable] [VM_ShowInInspector] private SimpleSO _privateAddressableScene; [VM_Label("Property (get/set)")] [VM_Scriptable] [VM_ShowInInspector] public ComplexSO PropertyAddressableScene { get; set; } = null;
VM_LocalizedString
Description
Displays a LocalizedString with table/locale selection and multiline text preview.
Constructors
Parameters
- int numLinesTables — visible lines in the table dropdown (default: 10)
- int numLinesKeys — visible lines in the key dropdown (default: 16)
Preview
Example Code
[VM_Label("Dialogue")] [VM_LocalizedString] public LocalizedString _dialogue; [VM_Label("Item Name")] [VM_LocalizedString] public LocalizedString _itemName; [VM_List("Array of Description")] [VM_LocalizedString] public List<LocalizedString> _fieldList = new(); [VM_Dictionary("Dictionary of Description")] [VM_LocalizedString] public SerializedDictionary<string, LocalizedString> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_LocalizedString] [VM_ShowInInspector] private LocalizedString _privateLS; [VM_Label("Property (get/set)")] [VM_LocalizedString] [VM_ShowInInspector] public LocalizedString PropertyLS { get; set; }
VM_LocalizedAudio
Description
Displays a LocalizedAudioClip with table/key selection and audio playback preview.
Constructors
Parameters
- int numLinesTables — visible lines in the table dropdown (default: 10)
- int numLinesKeys — visible lines in the key dropdown (default: 16)
Preview
Example Code
[VM_Label("🔊 Voice Line")] [VM_LocalizedAudio] public LocalizedAudioClip _voiceLine; [VM_Label("🎵 Ambient Sound")] [VM_LocalizedAudio] public LocalizedAudioClip _ambientSound; [VM_List("📋 Sound Effects")] [VM_LocalizedAudio] public List<LocalizedAudioClip> _fieldList = new(); [VM_Dictionary("📋 Sound Effects")] [VM_LocalizedAudio] public SerializedDictionary<string, LocalizedAudioClip> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_LocalizedAudio] [VM_ShowInInspector] private LocalizedAudioClip _privateAudio; [VM_Label("Property (get/set)")] [VM_LocalizedAudio] [VM_ShowInInspector] public LocalizedAudioClip PropertyAudio { get; set; }
VM_LocalizedImage
Description
Displays a LocalizedSprite or LocalizedTexture with table/key selection and image preview.
Constructors
Parameters
- int numLinesTables — visible lines in the table dropdown (default: 10)
- int numLinesKeys — visible lines in the key dropdown (default: 16)
- int size — preview thumbnail size in pixels (default: 128)
- bool stretchWidth — stretch preview to available width (default: false)
- bool fitSmallImage — upscale small images to fill preview (default: false)
- bool showSizeImage — display native dimensions at bottom (default: true)
- bool showOnChecker — show checkerboard behind transparent areas (default: true)
Preview
Example Code
[VM_Label("🏳️ Localized sprite")] [VM_LocalizedImage(size: 64)] public LocalizedSprite _flag; [VM_Label("🗺️ Localized texture")] [VM_LocalizedImage(size: 96, stretchWidth: true)] public LocalizedTexture _mapTexture; [VM_List("🎨 Localized sprites")] [VM_LocalizedImage(size: 48, showSizeImage: false, stretchWidth: true)] public List<LocalizedSprite> _fieldList = new(); [VM_Dictionary("🎨 Localized sprites")] [VM_LocalizedImage(size: 48, showSizeImage: false, stretchWidth: true)] public SerializedDictionary<string, LocalizedSprite> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private sprite")] [VM_LocalizedImage(size: 32)] [VM_ShowInInspector] private LocalizedSprite _privateSprite; [VM_Label("Property texture (get/set)")] [VM_LocalizedImage(size: 64, stretchWidth: true)] [VM_ShowInInspector] public LocalizedTexture PropertyTexture { get; set; }
VM_NestedColor
Description
Sets the background color for a nested structure.
Constructors
Parameters
- string hexColor — background color of the nested structure
Preview
Example Code
[VM_Label("📊 Stats")] public StatsData _stats; [VM_Label("⚔️ Attack")] [VM_NestedColor(hexColor: HexColor.Red400)] public AttackData _attack; [VM_Label("🛡️ Defense")] [VM_NestedColor(hexColor: HexColor.Sky400)] public DefenseData _defense; [VM_List("📋 List of Parameters", showHeaderNested: false)] public List<AllStatsData> _fieldList = new(); [VM_Dictionary("📋 Dictionary of Parameters")] public SerializedDictionary<string, AllStatsData> _fieldDict = new(); [System.Serializable] public class AttackData { [VM_Label("🗡️ Damage")] public int _damage = 25; [VM_Label("⚡ Speed")] [VM_Suffix("atk/s")] public float _speed = 1.5f; } [System.Serializable] public class DefenseData { [VM_Label("🛡️ Armor")] public int _armor = 50; [VM_Label("❤️ Health")] [VM_Suffix("HP")] public int _health = 100; } [System.Serializable] public class StatsData { [VM_Label("⭐ Level")] public int _level = 10; [VM_Label("🎯 Experience")] [VM_Suffix("XP")] public int _xp = 500; } [System.Serializable] public class AllStatsData { [VM_Label("⚔️ Attack")] [VM_NestedColor(hexColor: HexColor.Red400)] public AttackData _attack; [VM_Label("🛡️ Defense")] [VM_NestedColor(hexColor: HexColor.Sky400)] public DefenseData _defense; }
VM_NestedAsGroup
Description
Controls how nested structures (classes/structs) are rendered.
Constructors
Parameters
- string label — header text, or null to use ToString() of the nested object
- bool hideHeader — hide header (default: false)
- eDrawer drawer — drawing (None, Box, Foldout) style (default: eDrawer.Box)
- string hexColor — background color of the group (default: null)
Preview
Example Code
[VM_Label("Nested as Field")] public CombatData _combatDefault; [VM_NestedAsGroup(null, hexColor: HexColor.Sky400)] public CombatData _combatStats; [VM_Separator] [VM_NestedAsGroup("🏃 Movement Stats", drawer: eDrawer.Foldout)] public MovementData _movementStats; [VM_Separator] [VM_NestedAsGroup(null)] public AudioData _audioSettings; [System.Serializable] public class CombatData { [VM_LabelWidth(0.2f)] [VM_Label("💥 Damage")] [VM_RangeSlider(0, 100)] public int _damage = 50; [VM_Label("⏱️ Attack Rate")] [VM_Suffix("sec")] [VM_Min(0.1f)] public float _attackRate = 1.5f; [VM_NestedAsGroup("🛡️ Defense", drawer: eDrawer.Foldout)] public DefenseData _defense; public override string ToString() => "⚔️ Combat Stats"; } [System.Serializable] public class MovementData { [VM_Label("🏃 Speed")] [VM_RangeSlider(0, 100, fieldWidth: 80)] [VM_Suffix("m/s")] public int _speed = 50; [VM_Label("🦘 Jump Height")] [VM_Suffix("m")] [VM_Min(1f)] public float _jumpHeight = 2.5f; [VM_HideLabel] public DefenseData _defense; } [System.Serializable] public class AudioData { [VM_LabelWidth(0.15f)] [VM_Label("🔊 Volume")] [VM_RangeSlider(0, 100)] [VM_Suffix("%")] public int _volume = 80; [VM_Label("🎵 Pitch")] [VM_Min(0.1f)] public float _pitch = 1.0f; [VM_NestedAsGroup(null, drawer: eDrawer.None)] public DefenseData _defense; } [System.Serializable] public class DefenseData { [VM_Label("🛡️ Armor")] [VM_Suffix("%")] public int _armorType = 12; [VM_Label("🚫 Block")] [VM_Toggles] public bool _canBlock = true; public override string ToString() => "⚔️ Defense Stats"; }
VM_NestedInline
Description
Displays nested structure fields in a single horizontal line.
Constructors
Parameters
- bool showBorder — show box border around fields (default: true)
- string hexColor — background color of the group (default: null)
Preview
Example Code
[VM_Label("Damage")] [VM_NestedInline(hexColor: HexColor.Sky400)] public DamageRange _damage; [VM_HideLabel(useLabelWidth: true)] [VM_NestedInline(showBorder: false)] public DamageRange _damageNoBorder; [VM_Label("Defense")] [VM_NestedInline] public DefenseData _defense; [VM_HideLabel(useLabelWidth: true)] [VM_NestedInline] public DefenseData _defenseNoLabel; [VM_Label("Position")] [VM_NestedInline(showBorder: false)] public PositionData _position; [VM_HideLabel] [VM_NestedInline(showBorder: false)] public PositionData _positionNoLabel; [System.Serializable] public class DamageRange { [VM_Label("Min")] [VM_Suffix("HP")] public int _min = 5; [VM_Label("Max")] [VM_Suffix("HP")] public int _max = 25; [VM_Label("Crit")] [VM_Suffix("%")] public float _critChance = 15f; } [System.Serializable] public class DefenseData { [VM_Width(40, gap: 30)] [VM_HideLabel] [VM_Toggle] public bool _enable = false; [VM_Label("Armor")] [VM_EnableIf(nameof(_enable))] public int _armor = 50; [VM_Label("Block")] [VM_Suffix("%")] [VM_EnableIf(nameof(_enable))] public float _blockChance = 10f; } [System.Serializable] public class PositionData { [VM_Width(0.2f)] [VM_HideLabel] [VM_Suffix("X")] public float _x = 0f; [VM_Width(0.2f)] [VM_HideLabel] [VM_Suffix("Y")] public float _y = 0f; [VM_Width(0.3f)] [VM_HideLabel] [VM_Suffix("Z")] public float _z = 0f; [VM_Width(0.3f)] [VM_HideLabel] [VM_Suffix("W")] public float _w = 0f; }
VM_DropdownList
Description
Displays a list-field as a multi-select dropdown with checkboxes.
Constructors
Parameters
- string onListInit — method returning DropdownItems<T> with available values
- string onSelectChanged — callback when selection changes (default: null)
- int numLines — maximum visible lines in dropdown (default: 12)
Preview
Example Code
[VM_Label("🎭 Character Model")] [VM_AssetObjectsOnly] public GameObject _assetPrefab; private bool IsPrefabValid => _assetPrefab != null; [VM_EnableIf(nameof(IsPrefabValid))] [VM_Label("👁️ Visible Meshes")] [VM_DropdownList(nameof(OnListInit), nameof(OnSelectChanged))] public List<Transform> _visibleMeshes = new(); private DropdownItems<Transform> OnListInit() { if (_assetPrefab == null) return new(); var result = new DropdownItems<Transform>(); var renderers = _assetPrefab.GetComponentsInChildren<Renderer>(true); foreach (var renderer in renderers) result.Add(renderer.gameObject.name, renderer.transform); return result; } private void OnSelectChanged() { Debug.Log($"Selection changed! Now {_visibleMeshes.Count} meshes selected."); } [VM_Label("🎯 All Types")] [VM_DropdownList(nameof(GetAvailableTypes))] public List<int> _selectedTypes = new(); private DropdownItems<int> GetAvailableTypes() { return new DropdownItems<int> { { "Obstacle", 0 }, { "Enemy on the ground", 1 }, { "Enemy in the air", 2 }, { "Neutral NPC", 3 }, { "Bonus for the player", 4 }, { "Trigger of the quest", 5 }, }; } [VM_Label("🎯 Target Types")] [VM_DropdownList(nameof(GetUnitTypes))] public List<int> _selectedTargets = new(); private DropdownItems<int> GetUnitTypes() { return new DropdownItems<int> { { "Enemy on the ground", 1 }, { "Enemy in the air", 2 }, { "Neutral NPC", 3 }, }; } [VM_Dictionary("📋 Dictionary of Types")] [VM_DropdownList(nameof(GetAvailableTypes))] public SerializedDictionary<string, List<int>> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_DropdownList(nameof(GetAvailableTypes))] [VM_ShowInInspector] private List<int> _privateTypes = new(); [VM_Label("Property (get/set)")] [VM_DropdownList(nameof(GetUnitTypes))] [VM_ShowInInspector] public List<int> PropertyTypes { get; set; } = new();
VM_EnumList
Description
Displays a list of toggleable enum values for multi-selection.
Constructors
Parameters
- int limitPerLine — max number of enum buttons per line (default: 0 = all in one line)
- object[] variants — selective enum values to display (default: null = all)
- bool toggles — true: toggle buttons, false: dropdown popup (default: true)
Preview
Example Code
[VM_Label("🧭 Patrol Route")] [VM_EnumList] public List<eDirection> _enumTogles = new(); [VM_Label("🎯 Attack Cross Direction")] [VM_EnumList(variants: new object[] { eDirection.Up, eDirection.Down, eDirection.Left, eDirection.Right })] public List<eDirection> _enumCrossTogles = new(); [VM_Label("🎯 Attack None Directions")] [VM_EnumList(limitPerLine: 4)] public List<eDirection> _enumToglesLimit = new(); [VM_HideLabel] [VM_EnumList] public List<eDirection> _enumToglesHide = new(); [VM_HideLabel] [VM_EnumList(limitPerLine: 4)] public List<eDirection> _enumToglesHideLimit = new(); [VM_Label("⚔️ Combat Styles")] [VM_EnumList] public List<CombatContext> _enumToglesLabel = new(); [VM_Dictionary("📋 Dictionary of Direction List")] [VM_EnumList(limitPerLine: 4)] public SerializedDictionary<string, List<eDirection>> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_EnumList(toggles: false)] [VM_ShowInInspector] private List<eDirection> _privateEnums = new(); [VM_Label("Property (get/set)")] [VM_EnumList(toggles: false, variants: new object[] { eDirection.Up, eDirection.Down, eDirection.Left, eDirection.Right })] [VM_ShowInInspector] public List<eDirection> PropertyEnums { get; set; } = new(); public enum eDirection { Right, Left, Up, Down, UpLeft, UpRight, DownLeft, DownRight } public enum CombatContext { [VM_Label("Close quarters", tooltip: "Close-quarters combat")] Melee, [VM_Label("Targeting shooting", tooltip: "Ranged attack on a target")] Shooting, [VM_Label("Fire exchange", tooltip: "Ranged exchange of fire")] Firefight, }
VM_List
Description
Displays an array or list with enhanced controls. Additional operations are available via the context menu.
Constructors
Parameters
- string label — header text of the array
- bool showHeaderNested — show/hide header for nested structure elements (default: true)
- bool foldoutHeaderNested — when header is shown, selects the style: Foldout or Box (default: true = Foldout)
- string nameRefHeaderNested — field name in element type to use as label in the header (default: null)
- bool inlineNested — layout nested structure fields horizontally in one row (default: false)
- bool hideIndex — hide element index (default: false)
- bool isDraggable — permission to move elements within an array (default: true)
- bool isContextMenu — enable context (Copy/Paste/Clear) menu (default: true)
- bool isReadOnlyItems — disable editing of element contents; Add/Del/Drag still work (default: false)
- int minNumElements — minimum number of elements, 0 = no limit (default: 0)
- int maxNumElements — maximum number of elements, 0 = no limit (default: 0)
- string onAddMethod — callback(int index) after element added (default: null)
- string onDelMethod — callback(int index) before element deleting (default: null)
- string onReorderMethod — callback(int oldIndex, int newIndex) on reorder (default: null)
- string onPasteMethod — callback on Paste method (default: null)
- string onClearMethod — callback on Clear method (default: null)
Preview
Example Code
[VM_Title("Simple data", thicknessLine: 2)] [VM_List("📋 Waypoints")] public List<float> _waypoints = new(); [VM_List("Quest Logs (Add: disabled)", hideAdd: true)] [VM_Multiline] public List<string> _fieldListString = new(); [VM_Button("Add a multiline string", hexColor: HexColor.Lime400)] void AddString() => _fieldListString.Add(string.Empty); [VM_List("Skill Levels (Del: disabled, Draggable: disabled)", hideDel: true, isDraggable: false)] [VM_RangeSlider(0, 100)] public List<float> _fieldListRange = new(); bool IsValidListRange => _fieldListRange.Count > 0; [VM_EnableIf(nameof(IsValidListRange))] [VM_Button("Delete last element", hexColor: HexColor.Amber500)] void DelLastElement() => _fieldListRange.RemoveAt(_fieldListRange.Count - 1); [VM_List("Target Priority (ContextMenu: disabled)", isContextMenu: false)] [VM_Dropdown(nameof(DropdownValues), -1)] public List<int> _fieldListDropdown = new(); static DropdownItems<int> DropdownValues => new() { { "Zero", 0 }, { "One", 1 }, { "Two", 2 }, { "Three", 3 }, { "Four", 4 }, { "Five", 5 }, }; [VM_List("Battle Sounds (Limited size)", minNumElements: 1, maxNumElements: 5)] [VM_Audio] public List<AudioClip> _fieldListClips = new() { null }; [VM_List("Sprite objects (Index: disabled)", hideIndex: true)] [VM_AssetObjectsOnly] public List<Sprite> _fieldListSprites = new(); [VM_Title("Nested data", thicknessLine: 2)] [VM_List("Ability Roster (Foldout)", nameRefHeaderNested: nameof(NestedData._name), onAddMethod: nameof(OnAdd), onDelMethod: nameof(OnDel), onReorderMethod: nameof(OnReorder), onPasteMethod: nameof(OnPaste), onClearMethod: nameof(OnClear))] public List<NestedData> _fieldFoldoutList = new(); void OnAdd(int index) => Debug.Log($"New element[{index}] was added."); void OnDel(int index) => Debug.Log($"The element[{index}] will be removed."); void OnReorder(int oldIndex, int newIndex) => Debug.Log($"The element[{oldIndex}] moved to index {newIndex}."); void OnPaste() => Debug.Log("Array pasted"); void OnClear() => Debug.Log("Array cleared"); [VM_List("Ability Roster (Box)", foldoutHeaderNested: false)] public List<NestedData> _fieldNoFoldoutList = new(); [VM_List("Ability Desc (No Header)", showHeaderNested: false)] public List<ChildNestedData> _fieldNoHeaderList = new(); [VM_List("Ability Desc (Inline variant)", showHeaderNested: false, inlineNested: true)] public List<InlineNestedData> _fieldInlineList = new(); [VM_Title("NonSerialized Fields")] [VM_List("Private (Del: disabled, ReadOnlyItems: enabled)", hideDel: true, isReadOnlyItems: true)] [VM_ShowInInspector] private List<NestedData> _privateList = new(); [VM_List("Property (get/set) (Index: disabled)", hideIndex: true)] [VM_ProgressBar(0, 100)] [VM_ShowInInspector] public List<int> PropertyList { get; set; } = new(); public enum eDirection { Right, Left, Up, Down, UpLeft, UpRight, DownLeft, DownRight } public enum eDirectionBits { None = 0, Right = 1 << 0, Left = 1 << 1, Up = 1 << 2, Down = 1 << 3, UpLeft = 1 << 4, UpRight = 1 << 5, DownLeft = 1 << 6, DownRight = 1 << 7, } [System.Serializable] public class NestedData { public override string ToString() => string.IsNullOrEmpty(_name) ? "Ability Name : unknown" : $"Ability Name : {_name}"; [VM_LabelWidth(0.2f)] [VM_Label("🏷️ Ability Name")] public string _name = ""; [VM_Label("⚡ Mana Cost")] [VM_ProgressBar(0, 100)] public int _intValue = 50; [VM_Label("⏱️ Cooldown")] [VM_RangeSlider(0, 100)] public float _floatValue = 10.5f; [VM_Label("🧭 Cast Direction")] [VM_Enum(limitPerLine: 4)] public eDirection _enumToglesLimit; [VM_Label("💥 Damage")] [VM_SegmentedBar(10)] public int _damage = 5; [VM_Label("🎯 Target Directions")] [VM_EnumList(limitPerLine: 4)] public List<eDirection> _enumToglesLabel = new(); [VM_TabGroup("Tab1")] [VM_NestedAsGroup("🧪 Unique Effect Data")] public ChildNestedData _childData; [VM_TabGroup("Tab2")] [VM_List("📋 Effect Variants")] public List<ChildNestedData> _fieldList = new(); } [System.Serializable] public class ChildNestedData { [VM_Label("📝 Description")] public string _stringValue = "some text"; [VM_Label("✅ Active")] [VM_Toggles] public bool _booleanValue = true; public override string ToString() => "🧪 Effect Data"; } [System.Serializable] public class InlineNestedData { [VM_Width(0.75f, gap: 10)] [VM_Label("📝 Description")] public string _stringValue = "some text"; [VM_HideLabel] [VM_Toggles] public bool _booleanValue = true; }
VM_Dictionary
Description
Displays a SerializedDictionary<K,V> as an editable list of pairs. Simple values (int/float/string/enum/VM-drawer types) are rendered as a [Key | Value] table; nested values (struct/class/List) use a foldout layout by default, switchable to table via tableviewNested.
Constructors
Parameters
- string label — header text of the array
- bool tableviewNested — for nested values (struct/class/List): switch foldout → table layout. Simple values always use table — flag is ignored. (default: false)
- float tableKeyWidth — Key column width in table layout: (0..1] = fraction of total, >1 = pixels (default: 0.25)
- bool inlineNested — layout nested structure value fields horizontally in one row (default: false)
- bool isContextMenu — enable context (Copy/Paste/Clear) menu (default: true)
- bool isReadOnlyItems — disable editing of element contents AND key; Add/Del still work (default: false)
- int minNumElements — minimum number of pairs, 0 = no limit (default: 0)
- int maxNumElements — maximum number of pairs, 0 = no limit (default: 0)
- string onAddMethod — callback(T key) after pair added (default: null)
- string onDelMethod — callback(T key) before pair deleting (default: null)
- string onPasteMethod — callback on Paste method (default: null)
- string onClearMethod — callback on Clear method (default: null)Supported key types: string, int, enum. Duplicate keys are highlighted in red; the runtime Dictionary keeps the last occurrence.[VM_Label] and [VM_HideLabel] are ignored on fields with this attribute.
Preview
Example Code
[VM_Title("Simple data", thicknessLine: 2)] [VM_Dictionary("🎯 Stat Caps (default)")] [VM_Multiline] public SerializedDictionary<int, string> _damagePerLevel = new(); [VM_Dictionary("⚡ Damage Per Level (key width = 0.35)", tableKeyWidth: 0.35f)] [VM_Suffix("%")] public SerializedDictionary<string, int> _statCaps = new(); [VM_Dictionary("🎚️ Multipliers (key width = 120px)", tableKeyWidth: 120f)] [VM_ProgressBar(0, 1, suffix: " SP")] public SerializedDictionary<string, float> _multipliers = new(); [VM_Dictionary("🧭 Bonuses")] [VM_SimplePrefab(stretchWidth: true)] public SerializedDictionary<eDirection, GameObject> _directionSpeeds = new(); [VM_Dictionary("❤️ Skill Mana (range slider + suffix)")] [VM_RangeSlider(0, 100)] [VM_Suffix("%")] public SerializedDictionary<string, int> _skillMana = new(); [VM_Dictionary("📊 Resistance % (limited size [1..6])", minNumElements: 1, maxNumElements: 6)] [VM_ProgressBar(0, 100, suffix: " HP")] [VM_Suffix("%")] public SerializedDictionary<int, int> _resistance = new() { { 0, default } }; [VM_Title("List<T>", thicknessLine: 2)] [VM_Dictionary("🎒 List via Unity")] public SerializedDictionary<eDirection, List<int>> _fieldDictUnity = new(); [VM_Dictionary("🎒 List via attributes", tableviewNested: true)] [VM_List("Int Array")] [VM_RangeSlider(0, 999)] [VM_Suffix("%")] public SerializedDictionary<eDirection, List<int>> _lootTables = new(); [VM_Title("Nested data", thicknessLine: 2)] [VM_Dictionary("🗡️ Nested data (default)", onAddMethod: nameof(OnAdd), onDelMethod: nameof(OnDel), onPasteMethod: nameof(OnPaste), onClearMethod: nameof(OnClear))] public SerializedDictionary<string, AbilityData> _abilities = new(); void OnAdd(string key) => Debug.Log($"New element[{key}] was added."); void OnDel(string key) => Debug.Log($"The element[{key}] will be removed."); void OnPaste() => Debug.Log("Dictionary pasted"); void OnClear() => Debug.Log("Dictionary cleared"); [VM_Dictionary("🗡️ Abilities inline (inlineNested = true)", inlineNested: true)] public SerializedDictionary<string, InlineNestedData> _abilitiesInline = new(); [VM_Dictionary("🗡️ Abilities table (tableviewNested = true)", tableviewNested: true)] public SerializedDictionary<string, AbilityData> _abilitiesTable = new(); [VM_Dictionary("🗡️ Abilities table inline (inlineNested = true)", tableviewNested: true, inlineNested: true)] public SerializedDictionary<string, InlineNestedData> _abilitiesInlineTable = new(); [VM_Title("NonSerialized Fields")] [VM_Dictionary("Private", hideAdd: true)] [VM_RangeSlider(0, 100)] [VM_Suffix("%")] [VM_ShowInInspector] private SerializedDictionary<string, int> _privateDict = new(); [VM_Button("Add a value", hexColor: HexColor.Lime400)] void AddValue() => _privateDict.Add(0); [VM_Dictionary("Property (get/set)")] [VM_ShowInInspector] public SerializedDictionary<string, AbilityData> _propertyDict { get; set; } = new(); public enum eDirection { North, East, South, West } [System.Serializable] public class AbilityData { [VM_Label("⚡ Mana Cost")] [VM_RangeSlider(0, 100)] public int _manaCost = 25; [VM_Label("⏱️ Cooldown")] [VM_Suffix("sec")] [VM_Min(0.1f)] public float _cooldown = 1.5f; [VM_Label("💥 Damage")] [VM_SegmentedBar(5)] public int _damage = 3; } [System.Serializable] public class InlineNestedData { [VM_Width(0.75f, gap: 10)] [VM_Label("📝 Desc")] [VM_LabelWidth(55)] public string _stringValue = "some text"; [VM_HideLabel] [VM_Toggles] public bool _booleanValue = true; }
VM_VerticalGroup
Description
Groups fields vertically with multiple drawing modes. Default is Foldout.Vert
Constructors
Parameters
- string hierarchy — full hierarchical path (e.g., "Position/Horiz/Left")
- string label — optional display label (default: null = uses last path segment)
- bool hideLabel — hide the group header (default: false)
- eDrawer drawer — drawing style (None, Box, Foldout) (default: eDrawer.Foldout)
- string hexColor — background color of the group (default: null)Vert
Preview
Example Code
[VM_VerticalGroup("Vert", label: "🎮 Player Settings")] [VM_VerticalGroup("Vert/Child", label: "Combat", drawer: eDrawer.Box, hexColor: HexColor.Sky400)] [VM_VerticalGroup("Vert/Child/InnerData", label: "💥 Damage", drawer: eDrawer.Foldout)] [VM_Label("🗡️ Weapon")] public string _weapon = "Iron Sword"; [VM_VerticalGroup("Vert/Child/InnerDict", label: "💥 Dictionary", drawer: eDrawer.Foldout)] [VM_Dictionary("📋 Waypoints")] [VM_RangeSlider(0, 100, fieldWidth: 80)] [VM_Suffix("%")] public SerializedDictionary<string, float> _fieldDict = new(); [VM_VerticalGroup("Vert")] [VM_List("📋 Waypoints")] [VM_RangeSlider(0, 100, fieldWidth: 80)] [VM_Suffix("%")] public List<float> _fieldList = new(); [VM_VerticalGroup("Vert/Child/InnerData")] [VM_Title("🛡️ Defense", align: eAlign.Center)] [VM_Label("Defense Stats")] [VM_NestedColor(hexColor: HexColor.Green300)] public DefenseData _defenseStats; [VM_Separator(beforeGroup: "VertWithoutHeader")] [VM_Note("Also you can hide the group header to simply frame the data.", beforeGroup: "VertWithoutHeader")] [VM_VerticalGroup("VertWithoutHeader", hideLabel: true)] [VM_Label("🎵 Music Volume")] [VM_Suffix("%")] public string _musicVolume = "80"; [VM_VerticalGroup("VertWithoutHeader")] [VM_Label("🔊 SFX Volume")] [VM_Suffix("%")] public float _sfxVolume = 0.75f; [System.Serializable] public class DefenseData { [VM_Label("🛡️ Armor")] [VM_RangeSlider(0, 100)] public int _armor = 50; [VM_Label("❤️ Max Health")] [VM_Suffix("HP")] [VM_Min(1f)] public float _maxHealth = 100f; [VM_NestedAsGroup("🧪 Resistances", hexColor: HexColor.Fuchsia300)] public ResistanceData _resistances; } [System.Serializable] public class ResistanceData { [VM_Label("🔥 Fire")] [VM_Suffix("%")] public string _fire = "25"; [VM_Label("❄️ Frost")] [VM_Toggles] public bool _frostImmune = true; }
VM_HorizontalGroup
Description
Groups fields side-by-side with multiple drawing modes. Default is Foldout.Horiz
Constructors
Parameters
- string hierarchy — full hierarchical path (e.g., "Position/Horiz")
- string label — optional display label (default: null = uses last path segment)
- bool hideLabel — hide the group header (default: false)
- eDrawer drawer — drawing style (None, Box, Foldout) (default: eDrawer.Foldout)
- string hexColor — background color of the group (default: null)Horiz
Preview
Example Code
[VM_HorizontalGroup("Horiz", label: "🎮 Character Setup")] [VM_VerticalGroup("Horiz/Left", label: "⚔️ Offense", hexColor: HexColor.Sky400)] [VM_Label("🗡️ Weapon")] [VM_LabelWidth(90, beforeGroup: "Horiz/Left")] public string _weapon = "Iron Sword"; [VM_VerticalGroup("Horiz/Left")] [VM_NestedAsGroup("💥 Attack Stats")] public AttackData _attackStats; [VM_VerticalGroup("Horiz/Right", label: "🛡️ Defense")] [VM_Label("🛡️ Armor Type")] public string _armorType = "Chainmail"; [VM_VerticalGroup("Horiz/Right", label: "🛡️ Defense")] [VM_LabelWidth(0.6f)] [VM_NestedAsGroup("❤️ Health Stats")] public HealthData _healthStats; [VM_Separator(beforeGroup: "HorizNone")] [VM_Note("Set the Drawer property to <b>None</b> to use the horizontal group as a simple container without a border.", beforeGroup: "HorizNone")] [VM_Note("Also you can assign width weights to elements (ensure the total sum does not exceed 1.0).", beforeGroup: "HorizNone")] [VM_Title("Invisible horizontal group (eDrawer.None)", beforeGroup: "HorizNone")] [VM_HorizontalGroup("HorizNone", drawer: eDrawer.None)] [VM_VerticalGroup("HorizNone/Left", label: "📍 Position")] [VM_Width(0.6f)] [VM_Label("🌍 Location")] public string _location = "Spawn Point"; [VM_VerticalGroup("HorizNone/Left")] [VM_NestedAsGroup("📐 Coordinates")] public CoordinateData _coordinates; [VM_Width(0.4f)] [VM_VerticalGroup("HorizNone/Right", label: "🎨 Appearance")] [VM_Label("👤 Skin")] public string _skin = "Default"; [VM_VerticalGroup("HorizNone/Right", label: "🎨 Appearance")] [VM_NestedAsGroup("🎨 Visual")] public VisualData _visual; [System.Serializable] public class AttackData { [VM_Label("💥 Damage")] [VM_RangeSlider(0, 100)] public int _damage = 50; [VM_Label("⏱️ Rate")] [VM_Suffix("sec")] [VM_Min(0.1f)] public float _attackRate = 1.5f; } [System.Serializable] public class HealthData { [VM_Label("❤️ Max HP")] [VM_Suffix("HP")] public string _maxHP = "100"; [VM_Label("🧪 Regen")] [VM_Toggles] public bool _regenEnabled = true; } [System.Serializable] public class CoordinateData { [VM_LabelWidth(35)] [VM_Label("📍 X")] [VM_RangeSlider(-100, 100)] public int _x = 0; [VM_Label("📍 Y")] [VM_Min(0f)] public float _y = 1.5f; } [System.Serializable] public class VisualData { [VM_Label("🎨 Color")] public string _tint = "White"; [VM_Label("✨ Glow")] [VM_Toggles] public bool _glowEnabled = true; }
VM_TabGroup
Description
Organizes fields into a tabbed interface for better organization.General
Constructors
Parameters
- string hierarchy — full hierarchical path (e.g., "Settings/Audio")
- string label — optional display label (default: null = uses last path segment)
- string hexColor — background color of the tab content area (default: null)General
Preview
Example Code
[VM_TabGroup("General", label: "⚙️ General")] [VM_Label("🏷️ Player Name")] public string _playerName = "Hero"; [VM_TabGroup("General")] [VM_Label("🎚️ Difficulty")] [VM_Suffix("level")] public float _difficulty = 0.5f; [VM_TabGroup("General")] [VM_List("📋 Waypoints")] [VM_RangeSlider(0, 100, fieldWidth: 80)] [VM_Suffix("%")] public List<float> _waypoints = new(); [VM_TabGroup("Combat", label: "⚔️ Combat", hexColor: HexColor.Red200)] [VM_Label("🗡️ Weapon")] public string _weapon = "Iron Sword"; [VM_TabGroup("Combat")] [VM_Label("💥 Base Damage")] [VM_Suffix("HP")] public float _baseDamage = 25f; [VM_HorizontalGroup("Combat/Horiz", label: "📊 Attributes")] [VM_VerticalGroup("Combat/Horiz/VertLeft", label: "⚔️ Offense")] [VM_Label("💪 Strength")] public string _strength = "10"; [VM_VerticalGroup("Combat/Horiz/VertLeft")] [VM_Label("🏹 Dexterity")] public float _dexterity = 8f; [VM_VerticalGroup("Combat/Horiz/VertRight", label: "🛡️ Defense")] [VM_Label("🛡️ Armor")] public string _armor = "Chainmail"; [VM_VerticalGroup("Combat/Horiz/VertRight")] [VM_Label("❤️ Vitality")] public float _vitality = 12f; [VM_TabGroup("Skills", label: "🧙 Skills", hexColor: HexColor.Sky200)] [VM_Label("🔮 Active Spell")] public string _activeSpell = "Fireball"; [VM_TabGroup("Skills")] [VM_Label("🧪 Mana Cost")] [VM_Suffix("MP")] public float _manaCost = 15f; [VM_TabGroup("Skills/Offensive", label: "⚔️ Offensive", hexColor: HexColor.Orange200)] [VM_Label("🔥 Fire Power")] public string _firePower = "Level 3"; [VM_TabGroup("Skills/Offensive")] [VM_Label("⚡ Lightning")] [VM_Suffix("dmg")] public float _lightningDmg = 45f; [VM_HorizontalGroup("Skills/Offensive/Horiz", drawer: eDrawer.None)] [VM_VerticalGroup("Skills/Offensive/Horiz/Fire", label: "🔥 Fire")] [VM_Label("💥 Damage")] public string _fireDmg = "30"; [VM_VerticalGroup("Skills/Offensive/Horiz/Fire")] [VM_Label("⏱️ Cooldown")] [VM_Suffix("sec")] public float _fireCooldown = 1.5f; [VM_VerticalGroup("Skills/Offensive/Horiz/Ice", label: "❄️ Ice")] [VM_Label("💥 Damage")] public string _iceDmg = "20"; [VM_VerticalGroup("Skills/Offensive/Horiz/Ice")] [VM_Label("⏱️ Cooldown")] [VM_Suffix("sec")] public float _iceCooldown = 2.0f; [VM_VerticalGroup("Skills/Offensive/Horiz/Shock", label: "⚡ Shock")] [VM_Label("💥 Damage")] public string _shockDmg = "45"; [VM_VerticalGroup("Skills/Offensive/Horiz/Shock")] [VM_Label("⏱️ Cooldown")] [VM_Suffix("sec")] public float _shockCooldown = 3.0f; [VM_TabGroup("Skills/Defensive", label: "🛡️ Defensive", hexColor: HexColor.Green200)] [VM_Label("🧪 Heal Amount")] [VM_Suffix("HP")] public string _healAmount = "50"; [VM_VerticalGroup("Skills/Defensive")] [VM_Label("⏱️ Heal Cooldown")] [VM_Suffix("sec")] public float _healCooldown = 5f; [VM_TabGroup("Skills/Defensive")] [VM_Label("🛡️ Shield")] public ShieldData _shield; [VM_Separator] [VM_Note("Fields without any group attributes default to the root group.")] [VM_Label("📝 Description")] public string _description = "A brave adventurer"; [VM_Label("⭐ Level")] public float _level = 1f; [System.Serializable] public class ShieldData { [VM_Label("🛡️ Duration")] [VM_Suffix("sec")] [VM_RangeSlider(0, 100)] public int _duration = 10; [VM_Label("💪 Strength")] public float _strength = 50f; [VM_Label("🧪 Absorption")] public AbsorptionData _absorption; } [System.Serializable] public class AbsorptionData { [VM_Label("🔥 Fire")] [VM_Suffix("%")] public string _fire = "50"; [VM_Label("❄️ Frost")] [VM_Toggles] public bool _frostImmune = true; }
VM_ReadOnly
Description
Makes the field read-only, preventing modification.
Constructors
Preview
Example Code
[VM_Label("🎯 Max Level")] [VM_ReadOnly] public int _fieldReadonlyInt = 20; [VM_Label("💀 Damage Taken")] [VM_ReadOnly] [VM_BonusSlider(-10, 10, flipColors: true)] [VM_Suffix("HP")] public int _damageTaken = 7; [VM_Label("👑 Is Legendary")] [VM_ReadOnly] [VM_Toggles] public bool _fieldReadonlyBoolean = true; [VM_Label("🎯 Attack None Direction")] [VM_ReadOnly] [VM_Enum(limitPerLine: 4)] public eDirection _enumToglesLimit = eDirection.DownLeft; public enum eDirection { Right, Left, Up, Down, UpLeft, UpRight, DownLeft, DownRight } [VM_Label("Health")] [VM_ReadOnly] [VM_ProgressBar(0, 100, hexColorBar: HexColor.Orange500)] [VM_Suffix("HP")] public int _health = 50; [VM_Label("Defense")] [VM_ReadOnly] [VM_Suffix("%")] [VM_SegmentedBar(6, hexColorBar: HexColor.Green600)] public int _defense = 2; [VM_Label("Nested Data")] [VM_ReadOnly] public SmallNestedData _nestedData; [VM_List("Array")] [VM_Toggles] [VM_ReadOnly] public List<bool> _fieldList = new() { true, true }; [VM_Dictionary("Dictionary")] [VM_Toggles] [VM_ReadOnly] public SerializedDictionary<string, bool> _fieldDict = new() { false, false }; [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_ReadOnly] [VM_ShowInInspector] private string _privateString = "some text"; [VM_Label("Property (get/set)")] [VM_ReadOnly] [VM_ShowInInspector] public string PropertyString { get; set; } = "some text"; [System.Serializable] public class SmallNestedData { [VM_Label("String")] [VM_Multiline] public string _stringValue = "some text"; [VM_Label("Boolean")] [VM_Toggles] public bool _booleanValue = true; }
VM_ShowAsString
Description
Displays a field value as a read-only string.
Constructors
Parameters
- string format — optional format string for IFormattable types (default: null)
Preview
Example Code
[VM_Label("Int")] [VM_ShowAsString] public int _intValue = 42; [VM_Label("Float")] [VM_ShowAsString(format: "0.##")] public float _floatValue = 3.14159f; [VM_Label("Formatted Float")] [VM_ShowAsString(format: "0.####")] public float _formattedFloat = 123.456789f; [VM_Label("Boolean")] [VM_ShowAsString] public bool _boolValue = true; [VM_Label("String")] [VM_ShowAsString] [VM_Multiline] public string _stringValue = "Hello World!\nYou are beautiful!"; [VM_Label("Vector3")] [VM_ShowAsString(format: "0.##")] public Vector3 _vectorValue = new Vector3(1.5f, 2f, 3.1f); [VM_Label("Color")] [VM_ShowAsString(format: "0.#")] public Color _colorValue = Color.black * 0.5f; [VM_Label("Nested Data")] public SmallNestedData _nested; [VM_List("Array")] [VM_ShowAsString] public List<bool> _fieldList = new() { true, true }; [VM_Dictionary("Dictionary")] [VM_ShowAsString] public SerializedDictionary<string, bool> _fieldDict = new() { false, false }; [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_ShowAsString] [VM_ShowInInspector] private string _privateString = "Hello World"; [VM_Label("Property (get/set)")] [VM_ShowAsString] [VM_ShowInInspector] public float PropertyFloat { get; set; } = 3.14159f; [System.Serializable] public class SmallNestedData { [VM_Label("String")] [VM_ShowAsString] public string _stringValue = "some text"; [VM_Label("Boolean")] [VM_ShowAsString] public bool _booleanValue = true; }
VM_ChildrenOnly
Description
Adds a dropdown button to select from children of a parent object.
Constructors
Parameters
- string parentRef — name of a field/property returning the parent GameObject or Component
- bool includeInactive — include disabled child GameObjects (default: true)
Preview
Example Code
[VM_Label("🏰 Root Object")] public GameObject _rootObject; [VM_Label("🎯 Select all Transform")] [VM_ChildrenOnly(nameof(_rootObject))] public Transform _selectedTransform; [VM_Label("🔲 Select all Collider")] [VM_ChildrenOnly(nameof(_rootObject))] public Collider _selectedCollider; [VM_Label("🎨 Select all Renderer")] [VM_ChildrenOnly(nameof(_rootObject))] public Renderer _selectedRenderer; [VM_Label("📦 Select child GameObject")] [VM_ChildrenOnly(nameof(_rootObject))] public GameObject _selectedChild; [VM_Label("🟢 Show active Only")] [VM_ChildrenOnly(nameof(_rootObject), includeInactive: false)] public GameObject _selectedActiveChild;
VM_AssetObjectsOnly
Description
Restricts the field to project assets only.
Constructors
Preview
Example Code
[VM_Label("🗡️ Weapon Prefab")] [VM_Suffix("asset")] [VM_AssetObjectsOnly] public GameObject _assetPrefab; [VM_Label("🧱 Armor Material")] [VM_Suffix("asset")] [VM_AssetObjectsOnly] public Material _assetMaterial; [VM_Label("🖼️ Ability Icon")] [VM_Suffix("asset")] [VM_AssetObjectsOnly] public Texture2D _assetTexture; [VM_List("Sprite objects")] [VM_AssetObjectsOnly] [VM_Suffix("asset")] public List<Sprite> _fieldList = new(); [VM_Dictionary("Sprite objects")] [VM_AssetObjectsOnly] [VM_Suffix("asset")] public SerializedDictionary<string, Sprite> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Suffix("asset")] [VM_AssetObjectsOnly] [VM_ShowInInspector] private GameObject _privateObject; [VM_Label("Property (get/set)")] [VM_Suffix("asset")] [VM_AssetObjectsOnly] [VM_ShowInInspector] public GameObject PropertyObject { get; set; } = null;
VM_SceneObjectsOnly
Description
Restricts the field to scene objects only.
Constructors
Preview
Example Code
[VM_Label("🎯 Target Object")] [VM_Suffix("in scene")] [VM_SceneObjectsOnly] public GameObject _sceneObject; [VM_Label("🎥 Battle Camera")] [VM_Suffix("in scene")] [VM_SceneObjectsOnly] public Camera _sceneCamera; [VM_Label("📍 Spawn Point")] [VM_Suffix("in scene")] [VM_SceneObjectsOnly] public Transform _sceneTransform; [VM_List("Camera objects")] [VM_SceneObjectsOnly] [VM_Suffix("in scene")] public List<Camera> _fieldList = new(); [VM_Dictionary("GameObject objects")] [VM_SceneObjectsOnly] [VM_Suffix("in scene")] public SerializedDictionary<string, GameObject> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Suffix("in scene")] [VM_SceneObjectsOnly] [VM_ShowInInspector] private GameObject _privateObject; [VM_Label("Property (get/set)")] [VM_Suffix("in scene")] [VM_SceneObjectsOnly] [VM_ShowInInspector] public GameObject PropertyObject { get; set; } = null;
VM_DisableInPlayMode
Description
Makes the field read-only during Play Mode. Editable only in Editor Mode.
Constructors
Preview
Example Code
[VM_Label("⚔️ Attack Power")] [VM_DisableInPlayMode] public int _fieldInt = 10; [VM_Label("📝 Hero Name")] [VM_DisableInPlayMode] public string _fieldString = "Knight"; [VM_Label("👑 Is Legendary")] [VM_Toggles] [VM_DisableInPlayMode] public bool _fieldBoolean = true; [VM_List("Array")] [VM_Toggles] [VM_DisableInPlayMode] public List<bool> _fieldList = new() { true, true }; [VM_Dictionary("Dictionary")] [VM_Toggles] [VM_DisableInPlayMode] public SerializedDictionary<string, bool> _fieldDict = new() { false, false }; [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_DisableInPlayMode] [VM_ShowInInspector] private string _privateString = "some text"; [VM_Label("Property (get/set)")] [VM_DisableInPlayMode] [VM_ShowInInspector] public string PropertyString { get; set; } = "some text";
VM_DisableInEditorMode
Description
Makes the field read-only in Editor Mode. Editable only during Play Mode.
Constructors
Preview
Example Code
[VM_Label("⚔️ Attack Power")] [VM_DisableInEditorMode] public int _fieldInt = 10; [VM_Label("📝 Hero Name")] [VM_DisableInEditorMode] public string _fieldString = "Knight"; [VM_Label("👑 Is Legendary")] [VM_Toggles] [VM_DisableInEditorMode] public bool _fieldBoolean = true; [VM_List("Array")] [VM_Toggles] [VM_DisableInEditorMode] public List<bool> _fieldList = new() { true, true }; [VM_Dictionary("Dictionary")] [VM_Toggles] [VM_DisableInEditorMode] public SerializedDictionary<string, bool> _fieldDict = new() { false, false }; [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_DisableInEditorMode] [VM_ShowInInspector] private string _privateString = "some text"; [VM_Label("Property (get/set)")] [VM_DisableInEditorMode] [VM_ShowInInspector] public string PropertyString { get; set; } = "some text";
VM_HideInPlayMode
Description
Hides the field during Play Mode. Visible only in Editor Mode.
Constructors
Preview
Example Code
[VM_Label("⚔️ Attack Power")] [VM_HideInPlayMode] public int _fieldInt = 10; [VM_Label("📝 Hero Name")] [VM_HideInPlayMode] public string _fieldString = "Knight"; [VM_Label("👑 Is Legendary")] [VM_Toggles] [VM_HideInPlayMode] public bool _fieldBoolean = true; [VM_List("Array")] [VM_Toggles] [VM_HideInPlayMode] public List<bool> _fieldList = new() { true, true }; [VM_Dictionary("Dictionary")] [VM_Toggles] [VM_HideInPlayMode] public SerializedDictionary<string, bool> _fieldDict = new() { false, false }; [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_HideInPlayMode] [VM_ShowInInspector] private string _privateString = "some text"; [VM_Label("Property (get/set)")] [VM_HideInPlayMode] [VM_ShowInInspector] public string PropertyString { get; set; } = "some text";
VM_HideInEditorMode
Description
Hides the field in Editor Mode. Visible only during Play Mode.
Constructors
Preview
Example Code
[VM_Label("⚔️ Attack Power")] public int _fieldInt = 10; [VM_Note("None other fields will be visible only in Play Mode.")] [VM_Label("📝 Hero Name")] public string _fieldString = "Knight"; [VM_Label("👑 Is Legendary")] [VM_Toggles] [VM_HideInEditorMode] public bool _fieldBoolean = true; [VM_List("Array")] [VM_Toggles] [VM_HideInEditorMode] public List<bool> _fieldList = new() { true, true }; [VM_Dictionary("Dictionary")] [VM_Toggles] [VM_HideInEditorMode] public SerializedDictionary<string, bool> _fieldDict = new() { false, false }; [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_HideInEditorMode] [VM_ShowInInspector] private string _privateString = "some text"; [VM_Label("Property (get/set)")] [VM_HideInEditorMode] [VM_ShowInInspector] public string PropertyString { get; set; } = "some text";
VM_ShowInInspector
Description
Exposes non-serializable fields and properties in the Inspector.
Constructors
Preview
Example Code
[VM_LabelWidth(0.4f)] [VM_Label("Public Field")] [VM_ProgressBar(0, 100)] public int _publicField = 50; [VM_Label("Private Field")] [VM_ShowInInspector] [VM_RangeSlider(0, 100)] private int _privateField = 50; [VM_Label("Protected Field")] [VM_ShowInInspector] [VM_SegmentedBar(10)] protected int _protectedField = 2; [VM_Label("Public Property (get/set)")] [VM_ShowInInspector] [VM_ProgressBar(0, 100)] public int PublicProperty { get; set; } = 73; [VM_Label("Private Property (get/set)")] [VM_ShowInInspector] [VM_RangeSlider(0, 100)] private int PrivateProperty { get; set; } = 40; [VM_Label("Protected Property (get/set)")] [VM_ShowInInspector] [VM_SegmentedBar(10)] protected int ProtectedProperty { get; set; } = 5; [VM_Label("Public Property (get only)")] [VM_ShowInInspector] public float GetterOnlyProperty => _publicField + _privateField + _protectedField + PublicProperty + PrivateProperty + ProtectedProperty; [VM_NestedAsGroup("Nested Data")] public NestedData _nestedData; [System.Serializable] public class NestedData { [VM_Label("Public Field")] [VM_ProgressBar(0, 100)] public int _publicField = 50; [VM_Label("Private Field")] [VM_ShowInInspector] [VM_RangeSlider(0, 100)] private int _privateField = 50; [VM_Label("Protected Field")] [VM_ShowInInspector] [VM_SegmentedBar(10)] protected int _protectedField = 2; [VM_Label("Public Property (get/set)")] [VM_ShowInInspector] [VM_ProgressBar(0, 100)] public int PublicProperty { get; set; } = 73; [VM_Label("Private Property (get/set)")] [VM_ShowInInspector] [VM_RangeSlider(0, 100)] private int PrivateProperty { get; set; } = 40; [VM_Label("Protected Property (get/set)")] [VM_ShowInInspector] [VM_SegmentedBar(10)] protected int ProtectedProperty { get; set; } = 5; [VM_Label("Public Property (get only)")] [VM_ShowInInspector] public float GetterOnlyProperty => _publicField + _privateField + _protectedField + PublicProperty + PrivateProperty + ProtectedProperty; }
VM_HideInInspector
Description
Hides serializable fields in the Inspector while keeping them serialized.
Constructors
Preview
Example Code
[VM_Label("Public Field")] [VM_ProgressBar(0, 100)] public int _visibleField = 50; [VM_Label("Public Field (you won't see this)")] [VM_HideInInspector] [VM_RangeSlider(0, 100)] public int _hiddenField = 50; [VM_Note("The field marked with <b>VM_HideInInspector</b> above is still serialized, " + "but it is not displayed in the Inspector.")] [VM_Label("Public Property (get only)")] [VM_ShowInInspector] public int SumOfFields => _visibleField + _hiddenField; [VM_NestedAsGroup("Nested Data")] public NestedData _nestedData; [System.Serializable] public class NestedData { [VM_LabelWidth(0.5f)] [VM_HideInInspector] public bool _useFlag = true; [VM_Label("Public Field")] [VM_ProgressBar(0, 100)] public int _visibleField = 50; [VM_Label("Public Field (you won't see this)")] [VM_HideInInspector] [VM_RangeSlider(0, 100)] public int _hiddenField = 50; [VM_Note("The field marked with <b>VM_HideInInspector</b> above is still serialized, " + "but it is not displayed in the Inspector.")] [VM_Label("Public Property (get only)")] [VM_ShowInInspector] public int SumOfFields => _visibleField + _hiddenField; }
VM_EnableIf
Description
Enables the field when the condition is true, otherwise disables it.
Constructors
VM_EnableIf (string boolCallback0, string boolCallback1, ...)
VM_EnableIf (string boolCallback0, .. , string boolCallback2, ...)
VM_EnableIf (string boolCallback0, .. , string boolCallback3, ...)
VM_EnableIf (string boolCallback0, .. , string boolCallback4, ...)
Parameters
- string boolCallback — name of bool field, property, or method
- eCondition boolOp — logical operator (AND/OR) for combining conditions (default: AND)
Preview
Example Code
public enum eConditionEnabled { All, Integer, Float, Segments } [VM_Label("Root Fields")] [VM_Toggles(nameTrue: "Enable", nameFalse: "Disable")] public bool _fieldToggle = true; [VM_EnableIf(nameof(_fieldToggle))] [VM_Label("Enable by Type")] [VM_Enum(limitPerLine: 4)] public eConditionEnabled _fieldEnumCondition = eConditionEnabled.All; [VM_EnableIf(nameof(_fieldToggle), nameof(IsEnumInt))] [VM_Label("⚔️ Attack Power")] [VM_RangeSlider(0, 100)] public int _intValue = 50; bool IsEnumInt => _fieldEnumCondition == eConditionEnabled.All || _fieldEnumCondition == eConditionEnabled.Integer; [VM_EnableIf(nameof(_fieldToggle), nameof(IsEnumFloat))] [VM_Label("🏃 Move Speed")] [VM_Min(1f)] public float _floatValue = 10.5f; bool IsEnumFloat => _fieldEnumCondition == eConditionEnabled.All || _fieldEnumCondition == eConditionEnabled.Float; [VM_EnableIf(nameof(_fieldToggle), nameof(IsEnumSegments))] [VM_Label("💎 Enchantment")] [VM_SegmentedBar(10)] public int _segmentValue = 5; bool IsEnumSegments => _fieldEnumCondition == eConditionEnabled.All || _fieldEnumCondition == eConditionEnabled.Segments; [VM_Separator] [VM_Label("Nested Data")] [VM_Toggles(nameTrue: "Enable", nameFalse: "Disable")] public bool _fieldToggleNested = true; [VM_EnableIf(nameof(_fieldToggleNested))] [VM_NestedAsGroup("📦 Nested Data")] public NestedData _fieldNested; [System.Serializable] public class NestedData { [VM_LabelWidth(0.2f)] [VM_Label("🏷️ Name")] public string _name = "Player"; [VM_Label("Tab-1")] [VM_Toggles(nameTrue: "Enable", nameFalse: "Disable")] public bool _fieldToggleTab1 = true; [VM_Label("Tab-2")] [VM_Toggles(nameTrue: "Enable", nameFalse: "Disable")] public bool _fieldToggleTab2 = true; [VM_Label("ChildNest Data")] [VM_Toggles(nameTrue: "Enable", nameFalse: "Disable")] public bool _fieldToggleChildNested = true; [VM_EnableIf(nameof(_fieldToggleTab1))] [VM_TabGroup("Tab-1")] [VM_List("📋 String List")] public List<string> _fieldListSimple = new(); [VM_EnableIf(nameof(_fieldToggleTab2))] [VM_TabGroup("Tab-2")] [VM_List("📋 Child List")] public List<ChildNestedData> _fieldList = new(); [VM_EnableIf(nameof(_fieldToggleChildNested))] [VM_Label("🧪 ChildNested Data")] public ChildNestedData _fieldChildNested; } [System.Serializable] public class ChildNestedData { [VM_Label("📝 Description")] public string _stringValue = "some text"; [VM_Label("✅ Active")] [VM_Toggles] public bool _booleanValue = true; }
VM_DisableIf
Description
Disables the field when the condition is true (inverse of EnableIf).
Constructors
VM_DisableIf (string boolCallback0, string boolCallback1, ...)
VM_DisableIf (string boolCallback0, .. , string boolCallback2, ...)
VM_DisableIf (string boolCallback0, .. , string boolCallback3, ...)
VM_DisableIf (string boolCallback0, .. , string boolCallback4, ...)
Parameters
- string boolCallback — name of bool field, property, or method
- eCondition boolOp — logical operator (AND/OR) for combining conditions (default: OR)
Preview
Example Code
public enum eConditionDisabled { None, Integer, Float, Segments } [VM_Label("Root Fields")] [VM_Toggles(nameTrue: "Disable", nameFalse: "Enable")] public bool _fieldToggle = false; [VM_DisableIf(nameof(_fieldToggle))] [VM_Label("Disable by Type")] [VM_Enum(limitPerLine: 4)] public eConditionDisabled _fieldEnumCondition = eConditionDisabled.None; [VM_DisableIf(nameof(_fieldToggle), nameof(IsEnumInt))] [VM_Label("⚔️ Attack Power")] [VM_RangeSlider(0, 100)] public int _intValue = 50; bool IsEnumInt => _fieldEnumCondition == eConditionDisabled.Integer; [VM_DisableIf(nameof(_fieldToggle), nameof(IsEnumFloat))] [VM_Label("🏃 Move Speed")] [VM_Min(1f)] public float _floatValue = 10.5f; bool IsEnumFloat => _fieldEnumCondition == eConditionDisabled.Float; [VM_DisableIf(nameof(_fieldToggle), nameof(IsEnumSegments))] [VM_Label("💎 Enchantment")] [VM_SegmentedBar(10)] public int _segmentValue = 5; bool IsEnumSegments => _fieldEnumCondition == eConditionDisabled.Segments; [VM_Separator] [VM_Label("Nested Data")] [VM_Toggles(nameTrue: "Disable", nameFalse: "Enable")] public bool _fieldToggleNested = false; [VM_DisableIf(nameof(_fieldToggleNested))] [VM_NestedAsGroup("📦 Nested Data")] public NestedData _fieldNested; [System.Serializable] public class NestedData { [VM_LabelWidth(0.2f)] [VM_Label("🏷️ Name")] public string _name = "Player"; [VM_Label("Tab-1")] [VM_Toggles(nameTrue: "Disable", nameFalse: "Enable")] public bool _fieldToggleTab1 = false; [VM_Label("Tab-2")] [VM_Toggles(nameTrue: "Disable", nameFalse: "Enable")] public bool _fieldToggleTab2 = false; [VM_Label("ChildNested Data")] [VM_Toggles(nameTrue: "Disable", nameFalse: "Enable")] public bool _fieldToggleChildNested = false; [VM_DisableIf(nameof(_fieldToggleTab1))] [VM_TabGroup("Tab-1")] [VM_List("📋 String List")] public List<string> _fieldListSimple = new(); [VM_DisableIf(nameof(_fieldToggleTab2))] [VM_TabGroup("Tab-2")] [VM_List("📋 Child List")] public List<ChildNestedData> _fieldList = new(); [VM_DisableIf(nameof(_fieldToggleChildNested))] [VM_Label("🧪 ChildNested Data")] public ChildNestedData _fieldChildNested; } [System.Serializable] public class ChildNestedData { [VM_Label("📝 Description")] public string _stringValue = "some text"; [VM_Label("✅ Active")] [VM_Toggles] public bool _booleanValue = true; }
VM_ShowIf
Description
Controls the visibility of the field based on a condition.
Constructors
VM_ShowIf (string boolCallback0, string boolCallback1, ...)
VM_ShowIf (string boolCallback0, .. , string boolCallback2, ...)
VM_ShowIf (string boolCallback0, .. , string boolCallback3, ...)
VM_ShowIf (string boolCallback0, .. , string boolCallback4, ...)
Parameters
- string boolCallback — name of bool field, property, or method
- eCondition boolOp — logical operator (AND/OR) for combining conditions (default: AND)
Preview
Example Code
public enum eConditionShown { All, Integer, Float, Segments } [VM_Label("Root Fields")] [VM_Toggles(nameTrue: "Show", nameFalse: "Hide")] public bool _fieldToggle = true; [VM_ShowIf(nameof(_fieldToggle))] [VM_Label("Show by Type")] [VM_Enum(limitPerLine: 4)] public eConditionShown _fieldEnumCondition = eConditionShown.All; [VM_ShowIf(nameof(_fieldToggle), nameof(IsEnumInt))] [VM_Label("⚔️ Attack Power")] [VM_RangeSlider(0, 100)] public int _intValue = 50; bool IsEnumInt => _fieldEnumCondition == eConditionShown.All || _fieldEnumCondition == eConditionShown.Integer; [VM_ShowIf(nameof(_fieldToggle), nameof(IsEnumFloat))] [VM_Label("🏃 Move Speed")] [VM_Min(1f)] public float _floatValue = 10.5f; bool IsEnumFloat => _fieldEnumCondition == eConditionShown.All || _fieldEnumCondition == eConditionShown.Float; [VM_ShowIf(nameof(_fieldToggle), nameof(IsEnumSegments))] [VM_Label("💎 Enchantment")] [VM_SegmentedBar(10)] public int _segmentValue = 5; bool IsEnumSegments => _fieldEnumCondition == eConditionShown.All || _fieldEnumCondition == eConditionShown.Segments; [VM_Separator] [VM_Label("Nested Data")] [VM_Toggles(nameTrue: "Show", nameFalse: "Hide")] public bool _fieldToggleNested = true; [VM_ShowIf(nameof(_fieldToggleNested))] [VM_NestedAsGroup("📦 Nested Data")] public NestedData _fieldNested; [System.Serializable] public class NestedData { [VM_LabelWidth(0.2f)] [VM_Label("🏷️ Name")] public string _name = "Player"; [VM_Label("Tab-1")] [VM_Toggles(nameTrue: "Show", nameFalse: "Hide")] public bool _fieldToggleTab1 = true; [VM_Label("Tab-2")] [VM_Toggles(nameTrue: "Show", nameFalse: "Hide")] public bool _fieldToggleTab2 = true; [VM_Label("ChildNest Data")] [VM_Toggles(nameTrue: "Show", nameFalse: "Hide")] public bool _fieldToggleChildNested = true; [VM_ShowIf(nameof(_fieldToggleTab1))] [VM_TabGroup("Tab-1")] [VM_List("📋 String List")] public List<string> _fieldListSimple = new(); [VM_ShowIf(nameof(_fieldToggleTab2))] [VM_TabGroup("Tab-2")] [VM_List("📋 Child List")] public List<ChildNestedData> _fieldList = new(); [VM_ShowIf(nameof(_fieldToggleChildNested))] [VM_Label("🧪 Child Fields")] public ChildNestedData _fieldChildNested; } [System.Serializable] public class ChildNestedData { [VM_Label("📝 Description")] public string _stringValue = "some text"; [VM_Label("✅ Active")] [VM_Toggles] public bool _booleanValue = true; }
VM_HideIf
Description
Hides the field when the condition is true (inverse of ShowIf).
Constructors
VM_HideIf (string boolCallback0, string boolCallback1, ...)
VM_HideIf (string boolCallback0, .. , string boolCallback2, ...)
VM_HideIf (string boolCallback0, .. , string boolCallback3, ...)
VM_HideIf (string boolCallback0, .. , string boolCallback4, ...)
Parameters
- string boolCallback — name of bool field, property, or method
- eCondition boolOp — logical operator (AND/OR) for combining conditions (default: OR)
Preview
Example Code
public enum eConditionHidden { None, Integer, Float, Segments } [VM_Label("Root Fields")] [VM_Toggles(nameTrue: "Hide", nameFalse: "Show")] public bool _fieldToggle = false; [VM_HideIf(nameof(_fieldToggle))] [VM_Label("Hide by Type")] [VM_Enum(limitPerLine: 4)] public eConditionHidden _fieldEnumCondition = eConditionHidden.None; [VM_HideIf(nameof(_fieldToggle), nameof(IsEnumInt))] [VM_Label("⚔️ Attack Power")] [VM_RangeSlider(0, 100)] public int _intValue = 50; bool IsEnumInt => _fieldEnumCondition == eConditionHidden.Integer; [VM_HideIf(nameof(_fieldToggle), nameof(IsEnumFloat))] [VM_Label("🏃 Move Speed")] [VM_Min(1f)] public float _floatValue = 10.5f; bool IsEnumFloat => _fieldEnumCondition == eConditionHidden.Float; [VM_HideIf(nameof(_fieldToggle), nameof(IsEnumSegments))] [VM_Label("💎 Enchantment")] [VM_SegmentedBar(10)] public int _segmentValue = 5; bool IsEnumSegments => _fieldEnumCondition == eConditionHidden.Segments; [VM_Separator] [VM_Label("Nested Data")] [VM_Toggles(nameTrue: "Hide", nameFalse: "Show")] public bool _fieldToggleNested = false; [VM_HideIf(nameof(_fieldToggleNested))] [VM_NestedAsGroup("📦 Nested Data")] public NestedData _fieldNested; [System.Serializable] public class NestedData { [VM_LabelWidth(0.2f)] [VM_Label("🏷️ Name")] public string _name = "Player"; [VM_Label("Tab-1")] [VM_Toggles(nameTrue: "Hide", nameFalse: "Show")] public bool _fieldToggleTab1 = false; [VM_Label("Tab-2")] [VM_Toggles(nameTrue: "Hide", nameFalse: "Show")] public bool _fieldToggleTab2 = false; [VM_Label("ChildNest Data")] [VM_Toggles(nameTrue: "Hide", nameFalse: "Show")] public bool _fieldToggleChildNested = false; [VM_HideIf(nameof(_fieldToggleTab1))] [VM_TabGroup("Tab-1")] [VM_List("📋 String List")] public List<string> _fieldListSimple = new(); [VM_HideIf(nameof(_fieldToggleTab2))] [VM_TabGroup("Tab-2")] [VM_List("📋 Child List")] public List<ChildNestedData> _fieldList = new(); [VM_HideIf(nameof(_fieldToggleChildNested))] [VM_Label("🧪 ChildNested Data")] public ChildNestedData _fieldChildNested; } [System.Serializable] public class ChildNestedData { [VM_Label("📝 Description")] public string _stringValue = "some text"; [VM_Label("✅ Active")] [VM_Toggles] public bool _booleanValue = true; }
VM_Min
Description
Sets the minimum allowed value (lower limit).
Constructors
Parameters
- float minValue — minimum allowed value
Preview
Example Code
[VM_Label("⚔️ Min Damage")] [VM_Suffix("[1,N]")] [VM_Min(1)] public int _fieldInt = 1; [VM_Label("🏃 Min Speed")] [VM_Suffix("[10,N]")] [VM_Min(10f)] public float _fieldFloat = 12.5f; [VM_Label("📍 Min Position")] [VM_Suffix("[0,N]")] [VM_Min(0f)] public Vector3 _fieldVector = Vector3.one * 5.5f; [VM_Label("🧱 Min Grid Cell")] [VM_Suffix("[0,N]")] [VM_Min(0)] public Vector3Int _fieldVectorInt = Vector3Int.one * 10; [VM_List("📊 Skill Damage")] [VM_Min(1)] [VM_Suffix("[1,N]")] public List<int> _fieldList = new(); [VM_Dictionary("📊 Skill Damage")] [VM_Min(1)] [VM_Suffix("[1,N]")] public SerializedDictionary<string, int> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Suffix("[-10,N]")] [VM_Min(-10)] [VM_ShowInInspector] private float _privateFloat = 1; [VM_Label("Property (get/set)")] [VM_Suffix("[0,N]")] [VM_Min(0f)] [VM_ShowInInspector] public float PropertyInt { get; set; } = 5.5f;
VM_Max
Description
Sets the maximum allowed value (upper limit).
Constructors
Parameters
- float maxValue — maximum allowed value
Preview
Example Code
[VM_Label("⚔️ Max Damage")] [VM_Suffix("[N,20]")] [VM_Max(20)] public int _fieldInt = 1; [VM_Label("🏃 Max Speed")] [VM_Suffix("[N,-10]")] [VM_Max(-10f)] public float _fieldFloat = -20.5f; [VM_Label("📍 Max Position")] [VM_Suffix("[N,20]")] [VM_Max(20f)] public Vector3 _fieldVector = Vector3.one * 5.5f; [VM_Label("🧱 Max Grid Cell")] [VM_Suffix("[N,20]")] [VM_Max(20)] public Vector3Int _fieldVectorInt = Vector3Int.one * 10; [VM_List("📊 Skill Damage")] [VM_Max(10)] [VM_Suffix("[N,10]")] public List<int> _fieldList = new(); [VM_Dictionary("📊 Skill Damage")] [VM_Max(10)] [VM_Suffix("[N,10]")] public SerializedDictionary<string, int> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Suffix("[N,1]")] [VM_Max(1)] [VM_ShowInInspector] private float _privateFloat = 1; [VM_Label("Property (get/set)")] [VM_Suffix("[N,20]")] [VM_Max(20f)] [VM_ShowInInspector] public float PropertyInt { get; set; } = 5.5f;
VM_Clamp
Description
Restricts the value to a defined range (min/max). It also supports wrapping, causing the value to loop between limits.
Constructors
Parameters
- float minValue — minimum allowed value
- float maxValue — maximum allowed value
- bool wrap — if true, value wraps around instead of clamping (default: false)
Preview
Example Code
[VM_Label("❤️ Health")] [VM_Suffix("[0,100]")] [VM_Clamp(0, 100)] public int _fieldInt = 1; [VM_Label("⚡ Mana")] [VM_Suffix("[0,1]")] [VM_Clamp(0, 1)] public float _fieldFloat = 0.5f; [VM_Label("📍 Patrol Area")] [VM_Suffix("[0,10]")] [VM_Clamp(0, 10)] public Vector3 _fieldVector = Vector3.one * 5.5f; [VM_Label("🧱 Dungeon Bounds")] [VM_Suffix("[0,100]")] [VM_Clamp(0, 100)] public Vector3Int _fieldVectorInt = Vector3Int.one * 10; [VM_Title("With Wraping", fieldOnly: true, align: eAlign.Center, fontSize: 11)] [VM_Label("🔄 Rotation Angle")] [VM_Suffix("[0,360]")] [VM_Clamp(0, 360, wrap: true)] public int _fieldIntWraping = 1; [VM_Label("🌀 Spin Speed")] [VM_Suffix("[0,1]")] [VM_Clamp(0, 1, wrap: true)] public float _fieldFloatWraping = 0.25f; [VM_Label("🧭 Wind Direction")] [VM_Suffix("[0,90]")] [VM_Clamp(0, 90, wrap: true)] public Vector3 _fieldVectorWraping = Vector3.one * 45.5f; [VM_Label("🗺️ Tile Coords")] [VM_Suffix("[0,50]")] [VM_Clamp(0, 50, wrap: true)] public Vector3Int _fieldVectorIntWraping = Vector3Int.one * 10; [VM_List("📊 Skill Damage")] [VM_Suffix("[1,10]")] [VM_Clamp(1, 10)] public List<int> _fieldList = new(); [VM_Dictionary("📊 Skill Damage")] [VM_Suffix("[1,10]")] [VM_Clamp(1, 10)] public SerializedDictionary<string, int> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Suffix("[0,1]")] [VM_Clamp(0, 1)] [VM_ShowInInspector] private float _privateFloat = 1; [VM_Label("Property (get/set)")] [VM_Suffix("[0,10]")] [VM_Clamp(0f, 10f)] [VM_ShowInInspector] public float PropertyInt { get; set; } = 5.5f;
VM_Required
Description
Marks a field as mandatory, displaying an error message if the field is empty.
Constructors
Parameters
- string message — custom error message to display when field is empty (default: null)
Preview
Example Code
[VM_Required("You need to set a <b>texture</b> for the material")] [VM_Label("🖼️ Character Skin")] [VM_Image] public Texture2D _assetTexture; [VM_Required] [VM_Label("🧱 Armor Surface")] [VM_Material] public Material _assetMaterial; [VM_Required("<b>Prefab</b> is required")] [VM_Label("🗡️ Weapon Model")] [VM_SimplePrefab] public GameObject _assetPrefab; [VM_List("📊 Item Model")] [VM_Required("<b>Prefab</b> is required")] [VM_SimplePrefab(stretchWidth: true)] public List<GameObject> _fieldList = new(); [VM_Dictionary("📊 Item Model")] [VM_Required("<b>Prefab</b> is required")] [VM_SimplePrefab(stretchWidth: true)] public SerializedDictionary<string, GameObject> _fieldDict = new(); [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Required] [VM_ShowInInspector] private Material _privateMaterial; [VM_Label("Property (get/set)")] [VM_Required] [VM_ShowInInspector] public GameObject PropertyObj { get; set; } = null;
VM_ValidateInput
Description
Validates the field value using a custom callback method or property that returns bool.
Constructors
Parameters
- string nameCallback — name of the method or property returning bool
- string message — custom error message to display when validation fails (default: null)
Preview
Example Code
[VM_ValidateInput(nameof(IsValidPrefab))] [VM_Label("🏰 Castle Prefab")] [VM_SimplePrefab] public GameObject _assetPrefab; bool IsValidPrefab => _assetPrefab != null; [VM_ValidateInput(nameof(IsNotNull))] [VM_Label("📍 Respawn Point")] [VM_SceneObjectsOnly] public Transform _fieldTransform; bool IsNotNull(Transform tr) => tr != null; [VM_ValidateInput(nameof(IsGreaterThanZero), "This <b>variable</b> must be <b>greater than zero</b>")] [VM_Label("💰 Starting Gold")] public int _fieldInt; bool IsGreaterThanZero(int value) => value > 0; [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_ValidateInput(nameof(IsLessThanZero), "This <b>variable</b> must be <b>less than zero</b>")] [VM_ShowInInspector] private float _privateFloat = 0f; bool IsLessThanZero(float value) => value < 0f; [VM_Label("Property (get/set)")] [VM_ValidateInput(nameof(IsValidObj))] [VM_ShowInInspector] public GameObject PropertyObj { get; set; } = null; bool IsValidObj => PropertyObj != null;
VM_Button
Description
Creates a clickable button that invokes the method.
Constructors
Parameters
- string text — button label text
- string textCallback — callback name to override label text dynamically (default: null)
- string groupName — group buttons with same name into a line (default: null)
- eButtonSize size — size of button (Normal, Medium, Large) (default: Normal)
- eEnableMode enableMode — when button is enabled (Always, Editor, Playmode) (default: Always)
- string hexColor — button background color (default: null)
- bool fieldOnly — button applies only to the group it's in (default: false)
Preview
Example Code
[VM_Label("⚔️ Strength (A)")] [VM_Clamp(0, 100)] public int _fieldIntegerA = 100; [VM_Button("Set (A) to Zero", fieldOnly: true, hexColor: HexColor.Orange400)] void SetZeroA() => _fieldIntegerA = 0; [VM_Label("🛡️ Defense (B)")] [VM_Clamp(0, 100)] public int _fieldIntegerB = 50; [VM_Button("Set (B) to Zero", size: eButtonSize.Large, fieldOnly: true, hexColor: HexColor.Orange400)] void SetZeroB() => _fieldIntegerB = 0; [VM_Button("Random (A)", groupName: "ButtonsLine", size: eButtonSize.Medium, fieldOnly: true, hexColor: HexColor.Green700)] void RandomA() => _fieldIntegerA = Random.Range(0, 101); [VM_Button("Random (B)", groupName: "ButtonsLine", fieldOnly: true, hexColor: HexColor.Blue600)] void RandomB() => _fieldIntegerB = Random.Range(0, 101); [VM_Label("📊 Result")] [VM_ReadOnly] public int _fieldIntegerRes = 0; [VM_Button("Calculate: A + B", groupName: "ButtonsLine_Res1")] void Calc_Sum() => _fieldIntegerRes = _fieldIntegerA + _fieldIntegerB; [VM_Button("Calculate: A - B", groupName: "ButtonsLine_Res1")] void Calc_Sub() => _fieldIntegerRes = _fieldIntegerA - _fieldIntegerB; [VM_Button("Calculate: A * B", groupName: "ButtonsLine_Res2")] void Calc_Mul() => _fieldIntegerRes = _fieldIntegerA * _fieldIntegerB; [VM_List("📝 Descriptions")] public List<NestedData> _fieldListClips = new(); [System.Serializable] public class NestedData { [VM_HideLabel] [VM_Multiline] public string _stringValue = "some text"; public bool IsValid => !string.IsNullOrEmpty(_stringValue); [VM_Button("Add some text", groupName: "OneLine", hexColor: HexColor.Green)] void AddSomeText() => _stringValue += " some text"; [VM_EnableIf(nameof(IsValid))] [VM_Button("Clear text", groupName: "OneLine", hexColor: HexColor.Red)] void ClearText() => _stringValue = string.Empty; }
VM_OnInspectorInit
Description
Triggers a callback when the Inspector is activated (object selected).
Constructors
Preview
Example Code
[VM_OnInspectorInit] void OnInitRoot() { Debug.Log("OnInitRoot"); } [VM_Label("⚔️ Attack Power")] public int _fieldInt = 5; [VM_Label("📝 Hero Name")] public string _fieldString = "Player"; [VM_Label("✅ Is Active")] [VM_Toggles] public bool _fieldBoolean = false; [VM_Label("📦 Stats")] public NestedData _nestedData; [System.Serializable] public class NestedData { [VM_OnInspectorInit] void OnInitNested() { Debug.Log("OnInitNested"); } [VM_Label("❤️ Health")] [VM_RangeSlider(0, 100)] public int _intValue; [VM_Label("🏃 Speed")] public float _floatValue; [VM_NestedAsGroup("🧪 Abilities")] public ChildNestedData _childData; } [System.Serializable] public class ChildNestedData { [VM_OnInspectorInit] void OnInitChildNested() { Debug.Log("OnInitChildNested"); } [VM_Label("📝 Description")] public string _stringValue = "some text"; [VM_Label("✅ Unlocked")] [VM_Toggles] public bool _booleanValue; }
VM_OnInspectorDispose
Description
Triggers a callback when the Inspector is deactivated (object deselected).
Constructors
Preview
Example Code
[VM_OnInspectorDispose] void OnDisposeRoot() { Debug.Log("OnDisposeRoot"); } [VM_Label("⚔️ Attack Power")] public int _fieldInt; [VM_Label("📝 Hero Name")] public string _fieldString; [VM_Label("✅ Is Active")] [VM_Toggles] public bool _fieldBoolean; [VM_Label("📦 Stats")] public NestedData _nestedData; [System.Serializable] public class NestedData { [VM_OnInspectorDispose] void OnDisposeNested() { Debug.Log("OnDisposeNested"); } [VM_Label("❤️ Health")] [VM_RangeSlider(0, 100)] public int _intValue; [VM_Label("🏃 Speed")] public float _floatValue; [VM_NestedAsGroup("🧪 Abilities")] public ChildNestedData _childData; } [System.Serializable] public class ChildNestedData { [VM_OnInspectorDispose] void OnDisposeChildNested() { Debug.Log("OnDisposeChildNested"); } [VM_Label("📝 Description")] public string _stringValue; [VM_Label("✅ Unlocked")] [VM_Toggles] public bool _booleanValue; }
VM_OnInspectorGUI
Description
Invokes a callback for custom GUI rendering.
Constructors
Parameters
- string nameCallback — method name for drawing a field (default: null = if applied to a method)
Preview
Example Code
[VM_OnInspectorGUI(nameof(DrawInt))] public int _fieldInt = 10; void DrawInt() { #if UNITY_EDITOR UnityEditor.EditorGUILayout.BeginHorizontal(GUIStyle.none); { UnityEditor.EditorGUILayout.LabelField(new GUIContent("Integer", "Tip for 'Integer'"), GUILayout.Width(UnityEditor.EditorGUIUtility.labelWidth)); UnityEditor.EditorGUI.BeginChangeCheck(); var value = UnityEditor.EditorGUILayout.IntField(_fieldInt); if (UnityEditor.EditorGUI.EndChangeCheck()) { _fieldInt = value; UnityEditor.EditorUtility.SetDirty(this); } } UnityEditor.EditorGUILayout.EndHorizontal(); #endif } [VM_OnInspectorGUI(nameof(DrawString))] public string _fieldString = "some text"; void DrawString() { #if UNITY_EDITOR UnityEditor.EditorGUILayout.BeginHorizontal(GUIStyle.none); { UnityEditor.EditorGUILayout.LabelField(new GUIContent("String", "Tip for 'String'"), GUILayout.Width(UnityEditor.EditorGUIUtility.labelWidth)); UnityEditor.EditorGUI.BeginChangeCheck(); var value = UnityEditor.EditorGUILayout.TextField(_fieldString); if (UnityEditor.EditorGUI.EndChangeCheck()) { _fieldString = value; UnityEditor.EditorUtility.SetDirty(this); } } UnityEditor.EditorGUILayout.EndHorizontal(); #endif } [VM_OnInspectorGUI(nameof(DrawBoolean))] public bool _fieldBoolean = true; void DrawBoolean() { #if UNITY_EDITOR UnityEditor.EditorGUILayout.BeginHorizontal(GUIStyle.none); { UnityEditor.EditorGUILayout.LabelField(new GUIContent("Boolean", "Tip for 'Boolean'"), GUILayout.Width(UnityEditor.EditorGUIUtility.labelWidth)); UnityEditor.EditorGUI.BeginChangeCheck(); var value = _fieldBoolean; bool newTrueValue = GUILayout.Toggle(value, new GUIContent("True", "Tip for 'True'"), GUI.skin.button); bool newFalseValue = GUILayout.Toggle(!value, new GUIContent("False", "Tip for 'False'"), GUI.skin.button); if (UnityEditor.EditorGUI.EndChangeCheck()) { if (newTrueValue && !value) _fieldBoolean = true; else if (newFalseValue && value) _fieldBoolean = false; UnityEditor.EditorUtility.SetDirty(this); } } UnityEditor.EditorGUILayout.EndHorizontal(); #endif } [VM_OnInspectorGUI] void DrawLogo() { #if UNITY_EDITOR UnityEditor.EditorGUILayout.BeginHorizontal(GUIStyle.none); { UnityEditor.EditorGUILayout.LabelField(UnityEditor.EditorGUIUtility.IconContent("UnityLogo"), GUIStyle.none, GUILayout.Height(40), GUILayout.Width(40)); UnityEditor.EditorGUILayout.HelpBox("The [VM_OnInspectorGUI] attribute enables custom GUI rendering directly from the method.", UnityEditor.MessageType.Info); } UnityEditor.EditorGUILayout.EndHorizontal(); #endif }
VM_Dropdown
Description
Displays the field as a dropdown options.
Note that the DropdownItems helper type simplifies defining the options.
Constructors
Parameters
- string optionsCallback — name of field/property/method returning dropdown options
- object noneValue — value representing "none" selection
- int numLines — maximum visible lines in dropdown (default: 12)
Preview
Example Code
[VM_Label("Magic School")] [VM_Dropdown(nameof(MagicNameList), -1)] [VM_OnValueChanged(nameof(MagicSchoolChanged))] public int _magicSchool = -1; bool IsValidMagicSchool => _magicSchool >= 0; DropdownItems<int> MagicNameList => new() { { "School of Fire", SchoolFire }, { "School of Frost", SchoolFrost }, { "School of Light", SchoolLight }, { "School of Darkness", SchoolDarkness }, { "School of Illusion", SchoolIllusion }, }; void MagicSchoolChanged() { _spellName = string.Empty; _spellLevel = -1; } const int SchoolFire = 0; const int SchoolFrost = 1; const int SchoolLight = 2; const int SchoolDarkness = 3; const int SchoolIllusion = 4; [VM_Label("Known Spell")] [VM_EnableIf(nameof(IsValidMagicSchool))] [VM_Dropdown(nameof(SelectorSpell), null, numLines: 8)] [VM_OnValueChanged(nameof(SpellReset))] public string _spellName; bool IsValidSpellName => !string.IsNullOrEmpty(_spellName); List<string> SelectorSpell() => _magicSchool switch { SchoolFire => SpellFireList, SchoolFrost => SpellFrostList, SchoolLight => SpellLightList, SchoolDarkness => SpellDarknessList, SchoolIllusion => SpellIllusionList, _ => new() }; List<string> SpellFireList => new() { "Fire Ball", "Flame Strike", "Lava Shield", "Combustion", "Meteor Fall", "Ash Cloud", "Phoenix Breath", "Searing Pain", "Ignite", "Heat Wave" }; List<string> SpellFrostList => new() { "Frost Bite", "Ice Wall", "Glacial Spike", "Blizzard", "Cold Snap", "Frozen Heart", "Snow Blind", "Icicle Rain", "Cryo Stasis", "Winter's Grasp" }; List<string> SpellLightList => new() { "Holy Light", "Sun Ray", "Divine Grace", "Purification", "Flash Bang", "Sacred Shield", "Healing Touch", "Radiance", "Blessed Weapon", "Exorcism" }; List<string> SpellDarknessList => new() { "Shadow Bolt", "Life Drain", "Dark Void", "Necrosis", "Curse of Agony", "Fear", "Black Hole", "Soul Reap", "Night Shade", "Unholy Power" }; List<string> SpellIllusionList => new() { "Mirror Image", "Invisibility", "Phantasm", "False Clone", "Mind Trick", "Disguise", "Blur", "Decoy", "Hypnosis", "Mirage" }; [VM_Label("Spell Level")] [VM_EnableIf(nameof(IsValidSpellName))] [VM_Dropdown(nameof(SpellLevelList), 0, numLines: 5)] public int _spellLevel = 0; int[] SpellLevelList = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; bool IsValidSpellLevel => _spellLevel > 0; void SpellReset() => _spellLevel = 0; [VM_EnableIf(nameof(IsValidMagicSchool), nameof(IsValidSpellName), nameof(IsValidSpellLevel))] [VM_Button("Add To Spell Book", hexColor: HexColor.Green)] private void OnAddToSpellBook() { BookSpell element = new() { _spell = _spellName, _magicSchool = MagicNameList.GetName(_magicSchool), _spellLevel = _spellLevel }; _listSpellBook.Add(element); } [System.Serializable] public class BookSpell { [VM_Label("Level")] [VM_LabelWidth(0.15f)] [VM_SegmentedBar(10, showField: false)] public int _spellLevel = 0; [VM_HideInInspector] public string _spell; [VM_Width(0.35f)] [VM_Label("School")] [VM_ReadOnly] public string _magicSchool; } [VM_List("Spell Book", nameRefHeaderNested: nameof(BookSpell._spell), hideAdd: true)] public List<BookSpell> _listSpellBook = new(); bool IsValidSpellBook => _listSpellBook.Count > 1; [VM_EnableIf(nameof(IsValidSpellBook))] [VM_Button("Sort By Level", groupName: "SortButtons", hexColor: HexColor.Sky500)] private void OnSortByLevel() { _listSpellBook.Sort((a, b) => a._spellLevel.CompareTo(b._spellLevel)); } [VM_EnableIf(nameof(IsValidSpellBook))] [VM_Button("Sort Level By School", groupName: "SortButtons", hexColor: HexColor.Purple500)] private void OnSortBySchool() { _listSpellBook.Sort((a, b) => { int schoolCompare = string.Compare(a._magicSchool, b._magicSchool, System.StringComparison.Ordinal); return schoolCompare != 0 ? schoolCompare : a._spellLevel.CompareTo(b._spellLevel); }); } [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_Dropdown(nameof(MagicNameList), -1)] [VM_ShowInInspector] private int _privateDropdown = -1; [VM_Label("Property (get/set)")] [VM_Dropdown(nameof(MagicNameList), -1)] [VM_ShowInInspector] public int PropertyDropdown { get; set; } = -1;
VM_DropdownNested
Description
Applied to an int field storing index into a list. -1 means None.
Below the dropdown — fields of the selected element (editing changes the original).
Constructors
Parameters
- string listCallback — field/property/method returning the source list (IList)
- string optionsCallback — name of field/property/method returning dropdown options
- bool readOnly — if true, all nested fields are disabled (default: false)
- int numLines — visible lines in the dropdown (default: 12)
- bool showInline — layout nested fields horizontally (default: false)
Preview
Example Code
[VM_Label("🎭 Selected Actor")] [VM_DropdownNested(nameof(_actorsDatabase), nameof(GetActorOptionsV0))] public int _selectedActor = -1; [VM_Title("🎭 Selected Actor (Inline)")] [VM_HideLabel] [VM_DropdownNested(nameof(_actorsDatabase), nameof(GetActorOptionsV1), showInline: true)] public int _selectedActorInline = -1; [VM_Title("🎭 Selected Actor (ReadOnly)")] [VM_DropdownNested(nameof(_actorsDatabase), nameof(GetActorOptionsV0), readOnly: true)] public int _selectedActorReadOnly = -1; [VM_HideInInspector] public List<ActorData> _actorsDatabase = new() { new ActorData { _name = "Knight", _health = 100, _speed = 5.3f }, new ActorData { _name = "Mage", _health = 60, _speed = 7.0f }, new ActorData { _name = "Rogue", _health = 75, _speed = 9.5f }, }; private DropdownItems<int> GetActorOptionsV0() => new(_actorsDatabase.Select((element, index) => new DropdownItem<int>($"[{index}] {element}", index))); private DropdownItems<int> GetActorOptionsV1() { var list = new DropdownItems<int>(); for (int i = 0; i < _actorsDatabase.Count; i++) list.Add($"[{i}] {_actorsDatabase[i]}", i); return list; } [System.Serializable] public class ActorData { [VM_LabelWidth(60)] [VM_Label("🏷️ Name")] public string _name; [VM_Label("❤️ Health")] [VM_RangeSlider(0, 200)] public int _health; [VM_Width(0.25f)] [VM_Label("🏃 Speed")] public float _speed; public override string ToString() => string.IsNullOrEmpty(_name) ? "???" : $"Name of nested: \"{_name}\""; }
VM_InlineButton
Description
Adds an inline button at the end of the field that calls a specified method.
Constructors
Parameters
- string methodName — name of the method to call
- string buttonText — text displayed on the button (default: null = methodName)
- float width — button width in pixels (default: 0 = auto)
- string hexColor — hex color for button background (default: null = system color)
- eEnableMode enableMode — when button is enabled (Always, Editor, Playmode) (default: Always)
- string enableIf — name of bool field/property/method for button disabling (default: null)
Preview
Example Code
[VM_Label("Enable reset?")] [VM_Toggles] public bool _useReset = false; [VM_Label("🏷️ Player Name")] [VM_InlineButton(nameof(RandomName), "Random name", width: 100, hexColor: HexColor.Blue400)] public string _playerName = "Hero"; [VM_Label("❤️ Health")] [VM_InlineButton(nameof(ResetHealth), "Reset", hexColor: HexColor.Red400, enableIf: nameof(_useReset))] [VM_RangeSlider(0, 100)] public int _health = 100; [VM_Label("⚔️ Damage")] [VM_InlineButton(nameof(DoubleDamage), "x2", hexColor: HexColor.Amber500)] [VM_InlineButton(nameof(ResetDamage), "Reset", enableIf: nameof(_useReset))] [VM_Suffix("dmg")] public float _damage = 25f; void RandomName() => _playerName = "Hero_" + Random.Range(1000, 9999); void ResetHealth() => _health = 100; void DoubleDamage() => _damage *= 2; void ResetDamage() => _damage = 25f; [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_InlineButton(nameof(RandomPrivateName), hexColor: HexColor.Blue400)] [VM_ShowInInspector] private string _privateName = "NPC"; [VM_Label("Property (get/set)")] [VM_InlineButton(nameof(ResetPropertyHealth), "Reset", hexColor: HexColor.Red400, enableIf: nameof(_useReset))] [VM_RangeSlider(0, 100)] [VM_ShowInInspector] public int PropertyHealth { get; set; } = 50; void RandomPrivateName() => _privateName = "NPC_" + Random.Range(1000, 9999); void ResetPropertyHealth() => PropertyHealth = 100;
VM_Space
Description
Inserts empty space before and/or after a field or group.
Constructors
Parameters
- float before — space in pixels before the field/group
- float after — space in pixels after the field/group (default: 0)
- string beforeGroup — apply to specified group instead of field (default: null)
Preview
Example Code
[VM_Label("⚔️ Attack Power")] public int _attackPower; [VM_Space(20)] [VM_Label("❤️ Max Health")] public int _maxHealth; [VM_Label("🏃 Move Speed")] public float _moveSpeed; [VM_Space(20, after: 20, beforeGroup: "Vert")] [VM_VerticalGroup("Vert")] [VM_Label("🛡️ Defense Stats")] public DefenseData _defenseStats; [VM_Label("🔊 SFX Volume")] public float _sfxVolume = 0.75f; [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_ShowInInspector] [VM_Space(0, after: 20)] private string _privateName = "Some text ..."; [VM_Label("Property (get/set)")] [VM_ShowInInspector] public string PropertyName { get; set; } = "Some text ..."; [System.Serializable] public class DefenseData { [VM_Label("🛡️ Armor")] [VM_RangeSlider(0, 100)] public int _armor = 50; [VM_Label("❤️ Max Health")] [VM_Suffix("HP")] [VM_Min(1f)] public float _maxHealth = 100f; [VM_Space(20)] [VM_NestedAsGroup("🧪 Resistances")] public ResistanceData _resistances; } [System.Serializable] public class ResistanceData { [VM_Label("🔥 Fire")] [VM_Suffix("%")] public string _fire = "25"; [VM_Label("❄️ Frost")] [VM_Toggles] public bool _frostImmune = true; }
VM_Width
Description
Controls the width of a field inside horizontal structures.
Constructors
Parameters
- float value — [0..1] ratio, >1 pixels, 0 hidden
- float gap — space after element: [0..1] ratio, >1 pixels (default: 0)
Preview
Example Code
[VM_Label("📊 Ratio Mode [0..1]")] [VM_NestedInline] public RatioData _ratioData; [VM_Label("📐 Pixel Mode [>1]")] [VM_NestedInline(hexColor: HexColor.Sky400)] public PixelData _pixelData; [VM_Label("🔲 Gap Demo")] [VM_NestedInline] public GapData _gapData; [VM_Label("📍 Auto (no VM_Width)")] [VM_NestedInline(showBorder: false)] public AutoData _autoData; [VM_Label("🎭 Mixed Mode")] [VM_NestedInline] public MixedData _mixedData; [VM_Separator(beforeGroup: "Horiz")] [VM_HorizontalGroup("Horiz", "🏷️ Hero Settings", drawer: eDrawer.Box)] [VM_Width(0.5f)] [VM_Label("Name")] [VM_LabelWidth(0.2f)] public string _name = "Hero"; [VM_HorizontalGroup("Horiz")] [VM_Width(0.3f)] [VM_Label("Class")] public string _class = "Warrior"; [VM_HorizontalGroup("Horiz")] [VM_Label("Lvl")] [VM_Suffix("⭐")] public int _level = 10; [System.Serializable] public class RatioData { [VM_LabelWidth(20)] [VM_Width(0.4f)] [VM_Label("❤️")] [VM_Suffix("HP")] public int _hp = 100; [VM_Width(0.4f)] [VM_Label("🔮")] [VM_Suffix("MP")] public int _mp = 50; [VM_Width(0.2f)] [VM_Label("⚡")] [VM_Suffix("SP")] public int _sp = 25; } [System.Serializable] public class PixelData { [VM_LabelWidth(20)] [VM_Width(80)] [VM_Label("🏷️")] public string _tag = "Player"; [VM_Width(50)] [VM_Label("⭐")] public int _level = 10; [VM_Label("📝")] public string _description = "auto width"; } [System.Serializable] public class GapData { [VM_LabelWidth(20)] [VM_Width(0.3f, gap: 10)] [VM_Label("A")] public int _a = 1; [VM_Width(0.3f, gap: 10)] [VM_Label("B")] public int _b = 2; [VM_Width(0.3f)] [VM_Label("C")] public int _c = 3; } [System.Serializable] public class AutoData { [VM_HideLabel] [VM_Suffix("X")] public float _x = 0f; [VM_HideLabel] [VM_Suffix("Y")] public float _y = 0f; [VM_HideLabel] [VM_Suffix("Z")] public float _z = 0f; } [System.Serializable] public class MixedData { [VM_LabelWidth(20)] [VM_Width(0.15f, gap: 0.05f)] [VM_HideLabel] [VM_Toggle] public bool _enable = true; [VM_Width(60)] [VM_Label("🔢")] public int _id = 42; [VM_Label("📝")] public string _name = "auto"; }
VM_OnValueChanged
Description
Triggers a callback when the field value changes in Inspector.
Constructors
Parameters
- string nameCallback — name of the method to call when value changes
- bool invokeOnInit — also invoke callback on inspector init (default: false)
Preview
Example Code
[VM_Label("⚔️ Attack Power")] [VM_OnValueChanged(nameof(OnIntChanged), invokeOnInit: true)] public int _fieldInt = 10; void OnIntChanged() { Debug.Log("Root: Call OnIntChanged()"); } [VM_Label("📝 Hero Name")] [VM_OnValueChanged(nameof(OnStringChanged))] public string _fieldString = "some text"; void OnStringChanged() { Debug.Log("Root: Call OnStringChanged()"); } [VM_Label("✅ Is Active")] [VM_Toggles] [VM_OnValueChanged(nameof(OnToggleChanged))] public bool _fieldBoolean = true; void OnToggleChanged() { Debug.Log("Root: Call OnToggleChanged()"); } [VM_Label("📦 Stats")] [VM_OnValueChanged(nameof(OnNestedChanged), invokeOnInit: true)] public NestedData _nestedData; void OnNestedChanged() { Debug.Log("Root: Call OnNestedChanged()"); } [System.Serializable] public class NestedData { [VM_Label("❤️ Health")] [VM_RangeSlider(0, 100)] [VM_OnValueChanged(nameof(OnIntChanged))] public int _intValue = 50; void OnIntChanged() { Debug.Log("NestedData: Call OnIntChanged()"); } [VM_Label("🏃 Speed")] [VM_OnValueChanged(nameof(OnFloatChanged))] public float _floatValue = 10.5f; void OnFloatChanged() { Debug.Log("NestedData: Call OnFloatChanged()"); } [VM_NestedAsGroup("🧪 Abilities")] [VM_OnValueChanged(nameof(OnChildNestedChanged), invokeOnInit: true)] public ChildNestedData _childData; void OnChildNestedChanged() { Debug.Log("NestedData: Call OnChildNestedChanged()"); } } [System.Serializable] public class ChildNestedData { [VM_Label("📝 Description")] [VM_OnValueChanged(nameof(OnStringChanged))] public string _stringValue = "child text"; void OnStringChanged() { Debug.Log("ChildNestedData: Call OnStringChanged()"); } [VM_Label("✅ Unlocked")] [VM_Toggles] [VM_OnValueChanged(nameof(OnToggleChanged))] public bool _booleanValue = true; void OnToggleChanged() { Debug.Log("ChildNestedData: Call OnToggleChanged()"); } }
VM_ContextMenu
Description
Adds custom context menu items to a field (right-click).
Constructors
Parameters
- string menuLabel — text displayed in the context menu (use '/' for submenus)
- string methodName — name of a method to invoke on click (pass null to insert a separator: menuLabel becomes the separator path — empty for top-level, 'Group/' for inside the submenu)
- eEnableMode enableMode — when item is enabled (Always, Editor, Playmode) (default: Always)
- string enableIf — name of bool field/property/method for item disabling (default: null)
Preview
Example Code
[VM_Label("🔑 Unique ID")] [VM_ReadOnly] [VM_ContextMenu("Generate New Guid", nameof(GenerateNewGuid))] [VM_ContextMenu("Reset to Empty", nameof(ResetGuid), enableIf: nameof(IsGuidNotEmpty))] public string _guid = System.Guid.NewGuid().ToString(); void GenerateNewGuid() => _guid = System.Guid.NewGuid().ToString(); void ResetGuid() => _guid = ""; bool IsGuidNotEmpty => !string.IsNullOrEmpty(_guid); [VM_Label("⚔️ Attack Power")] [VM_ContextMenu("Presets/Randomize", nameof(RandomizeAttack))] [VM_ContextMenu("Presets/Set to Max", nameof(MaxAttack))] [VM_ContextMenu("Presets/", null)] [VM_ContextMenu("Presets/Reset to Zero", nameof(ResetAttack), enableMode: eEnableMode.Editor)] [VM_RangeSlider(0, 100)] public int _attack = 50; void RandomizeAttack() => _attack = Random.Range(0, 101); void MaxAttack() => _attack = 100; void ResetAttack() => _attack = 0; [VM_Title("NonSerialized Fields")] [VM_Label("Private")] [VM_ReadOnly] [VM_ContextMenu("Generate New Guid", nameof(GeneratePrivateGuid))] [VM_ShowInInspector] private string _privateGuid = System.Guid.NewGuid().ToString(); void GeneratePrivateGuid() => _privateGuid = System.Guid.NewGuid().ToString(); [VM_Label("Property (get/set)")] [VM_ContextMenu("Toggle Value", nameof(ToggleProperty))] [VM_ShowInInspector] public bool PropertyValue { get; set; } = false; void ToggleProperty() => PropertyValue = !PropertyValue;
VM_Order
Description
Controls the drawing order of fields within a group.
Constructors
Parameters
- int value — absolute priority, where Lower means Earlier (default: 0)
Preview
Example Code
[VM_Label("Default (order: 0)")] public string _normal = "default"; [VM_Order(2)] [VM_Label("C (order: 2)")] public string _fieldC = "I'm last"; [VM_Note("Fields below are declared in order: C, A, B — but rendered as A, B, C thanks to VM_Order.")] [VM_Order(0)] [VM_Label("A (order: 0)")] public string _fieldA = "I'm first"; [VM_Order(1)] [VM_Label("B (order: 1)")] public string _fieldB = "I'm second"; [VM_Order(-1)] [VM_Label("Promoted (order: -1)")] public string _promoted = "drawn before Default";
VM_PlayerFX
Description
Provides SimpleFX (particle system + sound effects) preview with playback controls.
Constructors
Parameters
- string onPlay — callback method returning VM_SimpleFX to play
- int sizeView — preview size in pixels (default: 256, minimum: 64)
- bool showGrid — display grid in preview (default: true)
- bool showAxes — display coordinate axes in preview (default: true)
Preview
Example Code
[VM_PlayerFX(nameof(OnPlay), sizeView: 256)] int _previewFX; private VM_SimpleFX OnPlay() => _scriptableFX; [VM_Space(5)] [VM_Label("✨ Spell Effect")] [VM_Scriptable] public VM_SimpleFX _scriptableFX;