A powerful Unity Editor extension that provides a circular button interface for quick access to custom actions. Activate with Ctrl+Q
hotkey to display a radial menu of available actions at your mouse position.
Ctrl+Q
to instantly open the action menuYou can import the Quick Action package into your Unity project using one of the following methods:
For VRChat developers: Add to VCC via VPM Listing
https://github.com/Yueby/QuickAction.git
Packages
folderCreate a new script and add a simple action:
using UnityEngine;
using UnityEditor;
using Yueby.QuickActions; // Don't forget to import the namespace
public class MyActions
{
[QuickAction("Tools/Hello World", "Display a greeting message")]
public static void HelloWorld()
{
Debug.Log("Hello from Quick Action!");
}
[QuickAction("Tools/Create Cube", "Create a cube in the scene", Priority = -100)]
public static void CreateCube()
{
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.name = "Quick Action Cube";
Selection.activeGameObject = cube;
}
}
Ctrl+Q
in the Unity EditorCtrl+Q
to automatically execute the selected actionCtrl+Q
to open the menuThe QuickActionAttribute
is used to mark methods as quick actions:
[QuickAction(path, description, Priority = priority, ValidateFunction = nameof(ValidationMethod))]
Parameters:
path
(required): Action path using forward slashes (e.g., “Tools/My Action”)description
(optional): Action description for tooltipsPriority
(optional): Display priority (lower numbers appear first)ValidateFunction
(optional): Method name for conditional enablingAction methods must be:
static
public
or private
void
Validation functions must be:
static
public
or private
bool
Validation functions can also control action visibility and checked state using:
QuickAction.SetVisible(path, bool)
: Show/hide actionsQuickAction.SetChecked(path, bool)
: Set checked state (shows checkmark)QuickAction.GetVisible(path)
: Get visibility stateQuickAction.GetChecked(path)
: Get checked stateDynamic actions allow you to register actions programmatically at runtime, perfect for context-aware functionality:
// Register a dynamic action
QuickAction.RegisterDynamicAction(
"Selection/Component/Copy",
() => CopyComponent(),
"Copy selected component",
-100
);
Dynamic Action Features:
Usage:
// Register event (during class initialization)
[InitializeOnLoadMethod]
private static void RegisterDynamicActions()
{
QuickAction.OnBeforeOpen += OnQuickActionOpen;
}
// Register dynamic actions in the event
private static void OnQuickActionOpen()
{
QuickAction.RegisterDynamicAction(
"path/action_name",
() => { /* action logic */ },
"action description",
priority
);
}
// Dynamic action with validation
QuickAction.RegisterDynamicAction(
"path/action_name",
() => { /* action logic */ },
"action description",
priority,
() => { /* validation logic, return bool */ }
);
using UnityEngine;
using UnityEditor;
using Yueby.QuickActions;
public class BasicActions
{
[QuickAction("Debug/Hello World", "Display a greeting message")]
public static void HelloWorld()
{
Debug.Log("Hello from Quick Action!");
}
[QuickAction("GameObject/Create Cube", "Create a cube in the scene")]
public static void CreateCube()
{
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.name = "Quick Action Cube";
Selection.activeGameObject = cube;
}
}
using UnityEngine;
using UnityEditor;
using Yueby.QuickActions;
public class ConditionalActions
{
[QuickAction("Selection/Delete Selected", "Delete selected GameObjects", ValidateFunction = "HasSelection")]
public static void DeleteSelected()
{
if (Selection.gameObjects.Length > 0)
{
foreach (var go in Selection.gameObjects)
{
Undo.DestroyObjectImmediate(go);
}
}
}
private static bool HasSelection()
{
bool hasSelection = Selection.gameObjects.Length > 0;
// Only show this action when objects are selected
QuickAction.SetVisible("Selection/Delete Selected", hasSelection);
return hasSelection;
}
[QuickAction("Play Mode/Stop Play", "Stop play mode", ValidateFunction = "IsPlaying")]
public static void StopPlay()
{
EditorApplication.isPlaying = false;
}
private static bool IsPlaying()
{
return EditorApplication.isPlaying;
}
}
using UnityEngine;
using UnityEditor;
using Yueby.QuickActions;
public class StateActions
{
private static bool _featureEnabled = false;
[QuickAction("Settings/Toggle Feature", "Enable/disable a feature", ValidateFunction = "ValidateFeature")]
public static void ToggleFeature()
{
_featureEnabled = !_featureEnabled;
Debug.Log($"Feature {(_featureEnabled ? "enabled" : "disabled")}");
}
private static bool ValidateFeature()
{
// Show checkmark when feature is enabled
QuickAction.SetChecked("Settings/Toggle Feature", _featureEnabled);
return true;
}
[QuickAction("Tools/Debug Mode", "Toggle debug mode", ValidateFunction = "ValidateDebugMode")]
public static void ToggleDebugMode()
{
Debug.unityLogger.logEnabled = !Debug.unityLogger.logEnabled;
}
private static bool ValidateDebugMode()
{
// Show current debug mode state
QuickAction.SetChecked("Tools/Debug Mode", Debug.unityLogger.logEnabled);
return true;
}
}
using UnityEngine;
using UnityEditor;
using Yueby.QuickActions;
public class HierarchicalActions
{
[QuickAction("Tools/Utilities/Screenshot", "Take a screenshot")]
public static void TakeScreenshot()
{
ScreenCapture.CaptureScreenshot("screenshot.png");
Debug.Log("Screenshot saved as screenshot.png");
}
[QuickAction("Tools/Utilities/Open Persistent Data", "Open persistent data path")]
public static void OpenPersistentData()
{
EditorUtility.RevealInFinder(Application.persistentDataPath);
}
[QuickAction("Tools/Scene/Save Scene", "Save current scene")]
public static void SaveScene()
{
EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
}
}
Dynamic actions are perfect for context-aware operations like component management:
using UnityEngine;
using UnityEditor;
using Yueby.QuickActions;
public class ComponentActions
{
[InitializeOnLoadMethod]
private static void RegisterDynamicActions()
{
QuickAction.OnBeforeOpen += OnQuickActionOpen;
}
private static void OnQuickActionOpen()
{
if (Selection.activeGameObject != null)
{
var components = Selection.activeGameObject.GetComponents<Component>();
foreach (var component in components)
{
if (component == null) continue;
var componentName = component.GetType().Name;
var componentKey = $"{componentName}_{component.GetInstanceID()}";
// Register copy and remove actions for each component
QuickAction.RegisterDynamicAction(
$"Selection/Component/{componentName}/Copy",
() => CopyComponent(componentKey),
$"Copy {componentName} component",
-850
);
QuickAction.RegisterDynamicAction(
$"Selection/Component/{componentName}/Remove",
() => RemoveComponent(componentKey),
$"Remove {componentName} component",
-849
);
}
}
}
private static void CopyComponent(string componentKey)
{
// Implementation for copying component
Debug.Log($"Copied component: {componentKey}");
}
private static void RemoveComponent(string componentKey)
{
// Implementation for removing component
Debug.Log($"Removed component: {componentKey}");
}
}
Key Benefits:
Quick Action provides specialized SceneView integration features, including:
"Tools/Build/Build Player"
instead of "Build"
"GameObject/Primitives/Create Cube"
Undo
operations for reversible actions[QuickAction(string path, string description = null)]
Path
: Action path (required)Description
: Action description (optional)Priority
: Display priority (optional, default: 0)ValidateFunction
: Validation method name (optional)Development Note: This project was developed with assistance from Cursor.
yueby.tools.quick-action
未設定
1.1.0
2022.3.22f1 以降
なし
なし
なし
未設定
Yueby