The Menu System
The menu system has been completely re-written in 3ds Max 2025, and many previous APIs have been deprecated. See Menu System topic in the 3ds Max Developer Help for a more complete overview of this new system.
There are three types of menus you can create and manage using MAXScript:
- Standard menus, such as menus on the 3ds Max main menu.
- Quad menus, which are accessed by right-clicking in the UI.
- Dynamic menus, which are a special type of menu that is created or updated dynamically based on a plug-in's state, using a callback.
Creating Standard Menus in MAXScript
A plug-in can add menus to 3ds Max by either loading a menu definition file (.mnx or .qmnx file), or programmatically with C++ or MAXScript. In either case, menus are loaded at startup. Menus created with MAXScript must be run from a script located in the startup Plug-in directory, or specified as "pre-startup scripts parts" in the plug-in's Package.xml file. See the Packaging Plugins topic in the 3ds Max Developer Help for more information about the package file format.
An example that creates menus using all three methods, menu definition files, C++ and MAXScript, can be found in the 3ds Max SDK under howto/ui/menudemo.
To create a menu in your plug-in using MAXScript:
- Register a callback for the
#cuiRegisterMenus
event. - This event contains the active CuiMenuManager as its notification parameter. Use this to obtain the main menu bar or other 3ds Max menus you wish to add your menu to.
- Use the various
CreateSubMenu()
,CreateSeparator()
, andCreateAction()
methods exposed by the CuiMenu, CuiActionMenu and CuiMenuItem classes to build your menu.
Here is a full example:
function menuCallback =
(
print "menuCallback"
local menuMgr = callbacks.notificationParam()
local mainMenuBar = menuMgr.mainMenuBar
-- Id of "Help" menu in main menu bar. Can be found in Menu editor -> right click on menu item -> copy item id
local helpMenuId = "cee8f758-2199-411b-81e7-d3ff4a80d143"
local newSubMenu = mainMenuBar.CreateSubMenu "F8FFB827-741C-4A81-8C89-BBF856DCF56D" "Demo Menu MXS" beforeId:helpMenuId
local separatorId = "96FB49D4-6263-4D8E-AC95-6D304673327B"
newSubMenu.CreateSeparator separatorId
-- Add existing actions from autobackup action table
local autobackupTableId = -889262067
newSubMenu.CreateAction "FD48D7BC-6CBB-4B05-985F-EBAC6CF29546" autobackupTableId "0" beforeId:separatorId
newSubMenu.CreateAction "6C18B511-BA95-422F-AA10-A2E5229759D2" autobackupTableId "1" beforeId:separatorId
newSubMenu.CreateAction "CC351EB5-E95C-4694-A68A-1A34BF32FA84" autobackupTableId "2" beforeId:separatorId
newSubMenu.CreateAction "6AC5FDFE-2AF7-4069-8493-D8A1462F4E7F" autobackupTableId "3" beforeId:separatorId title:"Custom Title"
-- Insert dynamic menu defined in mxsDynamicMenuExample.ms
newSubMenu.CreateAction "0C4D0C3D-D870-476A-9CDD-B6ED35A580C0" 647394 "MXS_Demo_Action_Item`Menu Demo Category"
)
callbacks.removeScripts id:#menuDemo
callbacks.addScript #cuiRegisterMenus menuCallback id:#menuDemo
Creating Quad Menus in MAXScript
Just like regular menus, quad menus can only be added at startup.
To create a quad menu in your plug-in using MAXScript:
- Register a callback for the
#cuiRegisterQuadMenus
event. - This event contains the active CuiQuadMenuManager as its notification parameter. Use this to obtain the main menu bar or other 3ds Max menus you wish to add your menu to.
- Use the various
CreateSubMenu()
,CreateSeparator()
, andCreateAction()
methods exposed by the CuiMenu, CuiActionMenu and CuiMenuItem classes to build your menu.
Here is a full example:
function quadMenuCallback =
(
function populateMenuWithManyItems menu =
(
-- Add existing actions from autobackup action table
local autobackupTableId = -889262067
-- Menu item ids need to be consistent at all times. Other menu customizations might rely on these ids.
-- However, since this is a demo plugin plugin and we just want some filler content, just generate random ids on every run.
-- This is not recommended for production code.
menu.CreateAction (genGUID()) autobackupTableId "0"
menu.CreateAction (genGUID()) autobackupTableId "1"
menu.CreateAction (genGUID()) autobackupTableId "2"
menu.CreateAction (genGUID()) autobackupTableId "3" title:"Custom Title"
menu.CreateSeparator (genGUID())
-- Insert dynamic menu defined in mxsDynamicMenuExample.ms
menu.CreateAction (genGUID()) 647394 "MXS_Demo_Action_Item`Menu Demo Category"
)
print "quadMenuCallback"
local quadMenuMgr = callbacks.notificationParam()
local viewportContextId = "ac7c70f8-3f86-4ff5-a510-e4fd6a9c368e" -- from ICuiQuadMenuManager.h
local viewportContext = quadMenuMgr.GetContextById viewportContextId
local mxsQuad = viewportContext.CreateQuadMenu "7A021F1D-3AEC-4398-9C84-60E48EE81F83" "Demo Quad Menu MXS"
-- This will override the existing viewport quad assigned to this right click modifier
viewportContext.SetRightClickModifiers mxsQuad #shiftAndControlPressed
local topRightMenu = mxsQuad.CreateMenu "2B5DCB81-E4D5-49B6-B693-2213E594B557" "MXS Top Right Quad" #TopRight
local bottomLeftMenu = mxsQuad.CreateMenu "EC6FBB46-E450-4F8F-AB13-A4A48A92FAF6" "MXS Bottom Left Quad" #BottomLeft
PopulateMenuWithManyItems topRightMenu
PopulateMenuWithManyItems bottomLeftMenu
)
callbacks.removeScripts id:#quadMenuDemo
callbacks.addScript #cuiRegisterQuadMenus quadMenuCallback id:#quadMenuDemo
Creating Dynamic Menus in MAXScript
Unlike menus and quad menus, dynamic menus can be created on the fly at any time. They are programmatically injected into the menu system in response to current conditions. To create a dynamic menu, create a macroscript with two event handlers: populateDynamicMenu
and dynamicMenuItemSelected
. For example, the sample below can be assigned to a button or menu item, and it will dynamically create a set of menus.
The populateDynamicMenu handler syntax looks like this:
on populateDynamicMenu <CuiDynamicMenu> [<hwnd> [<Point2>]] do
The first argument is the menu or quad menu calling the handler. If invoked from a menu, the last two arguments are 0 [0,0]
. If invoked from a quad menu, they are the hwnd of the quad menu's viewport, and the coordinates of the quad in that viewport.
macroscript MXS_Demo_Action_Item category:"Menu Demo Category" buttonText:"MXS Demo Action Item"
(
-- Defining these two event handlers tells the system that this macroscript should produce a dynamic menu
on populateDynamicMenu menuRoot do
(
-- Generate some custom menu items. Each item has a unique id.
-- Id is passed to dynamicMenuItemSelected when user clicks on menu item.
-- These ids are not visible to the rest of the menu system. They only matter for this specific dynamic menu.
menuRoot.AddItem 1234 "Say Hello in listener"
menuRoot.AddItem 2345 "Say Goodbye in listener"
menuRoot.addSeparator()
subMenu = menuRoot.addSubMenu "Sub-Menu"
subMenu.AddItem 3456 "Say 3ds Max in listener"
menuRoot.addSeparator()
-- Add existing actions from autobackup action table
local autobackupTableId = -889262067
menuRoot.AddAction autobackupTableId "0"
menuRoot.AddAction autobackupTableId "1"
menuRoot.AddAction autobackupTableId "2"
menuRoot.AddAction autobackupTableId "3" title:"Custom Title"
)
on dynamicMenuItemSelected id do
(
case id of
(
1234: print "Hello"
2345: print "Goodbye"
3456: print "3ds Max"
)
)
)
ADSK_3DSMAX_CUI_PRE_USER_CONFIG_%MAJOR_VERSION%
3ds Max 2026 adds a possibility to load the new cui config files directly before the final user configuration gets loaded. This is implemented by looking for a new 3ds Max environment variable ADSK_3DSMAX_CUI_PRE_USER_CONFIG_%MAJOR_VERSION%
, so e.g. ADSK_3DSMAX_CUI_PRE_USER_CONFIG_2026
. The new environment variable allows a list of cui files separated as usual for envVars by a semicolon ';'. Order of evaluation will be as specified in the list.
You can dynamically load menus and hotkeys within a session using Maxscript like this.
systemTools.setEnvVariable "ADSK_3DSMAX_CUI_PRE_USER_CONFIG_2027" @"C:\YourFolder\csStudio.mnx"
(maxops.GetICuiMenuMgr()).LoadConfiguration((maxops.GetICuiMenuMgr()).GetCurrentConfiguration())