Skip to content

JSON Structure Guide

Stentorious edited this page Jun 23, 2026 · 31 revisions

MCM Extender JSON Structure Guide

This document provides a comprehensive guide to the JSON structure used by MCM Extender. For practical examples, refer to the MCMExtenderExample.json file included in the Example Menu downloads.

Table of Contents

Legend

Symbol Name Description
Required Element must be included.
🔀 Mutually Exclusive Include one of the mutually exclusive elements.
Optional Element can be optionally included.
Unsupported Element is not supported.

Metadata

The root of the JSON file must contain metadata to provide information about the mod the menu applies to.

Key Type Required Description
"modName" String A unique internal identifier for the mod.
"displayName" String The mod name displayed in the MCM sidebar.
"saveFile" String Path to the config file where settings are saved, relative to Data\config\.
"minMCMVersion" Float The minimum required MCM Extender version.
"requirements" Array Defines conditions for the menu to be displayed. See Requirements.
"submenus" Map Contains all submenus for the mod. See Submenus.

Requirements

  • "plugin": Check if a mod ESM or ESP is enabled via IsModLoaded
  • "file": Check if a file is exists via FileExists. Path is relative to the Data\ folder.
  • "folder": Check if a folder is exists via FileExists. Path is relative to the Data\ folder.
  • "dll": Check minimum xNVSE plugin version via GetPluginVersion. Requires numeric "version" element.
  • "nvse": Check minimum xNVSE version via GetNVSEVersionFull. Requires numeric "version" element.
"requirements": [
    { "type": "plugin", "file": "SomeMod.esp" },
    { "type": "file", "file": "Config/SomeMod.ini" },
    { "type": "folder", "file": "Menus/SomeMod" },
    { "type": "dll", "file": "JohnnyGuitarNVSE", "version": 510 },
    { "type": "nvse", "version": 6.40 }
]

You can also nest an array of requirements. This creates an "OR" block; the requirement is met if at least one of the conditions inside the nested array is true. This allows a single menu file to support multiple mod configurations.

"requirements": [
    [
        { "type": "plugin", "file": "SomeMod.esp" },
        { "type": "file", "file": "NVSE/plugins/scripts/ln_SomeMod.txt" }
    ]
]

You can use a combination of the regular requirements maps and nested arrays for more complex logic.

"requirements": [
    { "type": "plugin", "file": "SomeMod.esp" },
    [
        { "type": "plugin", "file": "SomeOtherMod.esp" },
        { "type": "file", "file": "NVSE/plugins/scripts/ln_SomeOtherMod.txt" }
    ]
]

Submenus

Each menu is populated with submenus objects, sorted by consecutive string integer keys (e.g., "1", "2").

ℹ️ Note: The MCM framework limits each menu to a maximum of 10 submenus (from key "1" to "10").

Submenu Objects

Submenu objects can include the following key-value pairs:

Key Name Value Type Required Description Extra Info
"columns" Int (1/2) Number of columns for the submenu page, columns are populated form left to right, top to bottom. --
"listTitle" String Title of the submenu shown in the list on the left. --
"pageTitle" String Title shown at the top of the submenu page. --
"options" Map Map containing all the individual options for this submenu. Submenu Options
"enable" Int (0/1) 🔀 Controls submenu visibility. Submenu Visibility
"state" Object 🔀 Controls submenu visibility. Submenu Visibility
"active" Int (0/1) Marks the submenu as the default page to open, defaulting to submenu in the map if not included. --
"requirements" Array Requirements array, submenu will only appear if requirements are met. Requirements

Submenu Visibility

Include either the "enable" or "state" element to control a submenus visibility state.

If both options are accidentally included the "state" element will always take priority.

  • "enable": Controls the submenus's visibility.
    • 0: Hidden. The submenus is not visible.
    • 1: Enabled. The submenus is visible and can be interacted with.
  • "state" Preforms an equality check with a Variable Object and numeric "value".
"enable": 1,
"state": { "form": "SomeQuest", "numVar": "SomeVariable", "value": 1 },

Single-Page Menu

To create a menu with a single page and no sidebar list, define only one submenu object using the key "0".

"submenus" : {
    "0": { ... }
}

Multi-Page Menu

To create a menu with multiple pages accessible from the sidebar, add submenu objects with consecutively numbered string keys (e.g., "1", "2", "3").

You can optionally include a submenu with the key "0" to serve as a main or landing page. This page is only shown on menu open and cannot be returned to after selecting another submenu from the sidebar.

"submenus" : {
    "0": { ... },
    "1": { ... },
    "2": { ... },
}

Options

Inside each submenu object, the "options" map lists all the individual setting controls. These are also sorted by string integer keys ("1", "2", etc.), which directly correspond to their display order in the MCM. You can skip numbers to create more complex layouts with empty spaces. These integer keys have a minimum value of "1".

ℹ️ Note: The MCM framework limits each submenu to a maximum of 36 options (from key "1" to "36").

Option Types

Each option object defines a single setting in the MCM. It has several possible elements depending on its type.

Type Name Description
0 Header/Image A non-interactive display element. By default, it displays the "title" string in a large font. You can override this to display a .dds image file instead by using the "image" object.
1 Dropdown List of selectable string options. Supports up to 10 list entries.
2 Integer Slider Slider for selecting a whole number within a defined range.
2.5 Float Slider Slider for selecting a floating-point number within a defined range.
3 Keybind Control that prompts the user to press a key, returning a DirectX scancode.
4 On/Off Toggle Toggle that switches between "On" and "Off" strings.
5 Checkbox Toggle that uses a checkmark box. It is functionally identical to Type 4.
6 String Toggle Toggle that switches between custom "textOn" and "textOff" strings.
7 Static Text Non-interactive text label that displays a string.
8 Multi-Slider Single option that opens a slider menu to configure 2 or 3 separate numerical values at once.
9 Color Picker Displays a color swatch and opens a HSV Color Picker to set three R, G, and B values from 0-255.

Option Objects

Option objects can include the following key-value pairs.

Key Name Value Type Option Type Required Var Support Description Extra Info
"type" Int/Float Any Option type Option Types
"title" String Any Display text --
"enable" Int (0/1/2) Any 🔀 Controls option interactivity Option Visibility
"state" Object Any 🔀 Controls option interactivity Option Visibility
"mouse" String Any Mouseover help text --
"refresh" Int (0/1) Any Forces the active menu to refresh Option Refresh
"indent" Float Any Indents option by float magnitude --
"brightnessMul" Float Any Apply text brightness multiplier --
"vars" Array 1, 2, 2.5, 3, 4, 5, 6, 8, 9 Array containing the variable objects the option will update Option Variables
"call" Object 1, 2, 2.5, 3, 4, 5, 6, 8, 9 Script function called whenever the option's value is changed. Option Scripts
"callOpen" Object 2, 2.5, 8, 9 Script function called when the scale menu is opened. Option Scale Scripts
"callClose" Object 2, 2.5, 8, 9 Script function called when the scale menu is closed. Option Scale Scripts
"callLoop" Object 2, 2.5, 8, 9 Script function callback loop when the scale menu is open. Option Scale Scripts
"scale" Map 2, 2.5, 8 Map defining the slider's range, increment, etc. Option Scale Map
"prefix" String 2, 2.5, 8 Prefix string before the value --
"suffix" String 2, 2.5, 8 Suffix string after the value --
"image" Map 0 Map defining the image's path, size, position, etc. Option Image Map
"strings" Array 1 Array of strings providing the text labels for option type 1 Option String Array
"stringsAlt" Array 1 Array of strings providing the text display labels for option type 1 Option String Array
"string" String 7 String value to display --
"textOn" String 6 Custom text for toggle "On" state. --
"textOff" String 6 Custom text for toggle "Off" state. --

Option Element Variable Support

Variable Objects can be used to dynamically set the text or value of several option elements. When a Variable Object is used in place of a standard value (String, Int, or Float), the MCM Extender will read the specified variable and use it to populate that element's value. This feature is particularly useful for creating dynamic menu elements.

ℹ️ Note: See the Var Support column in the Option Objects table for a complete list of supported elements. When used for display purposes, Variable Objects do not require the configINI and default elements.

Example: You want to display a dynamic title string from a JIP Auxiliary-Variable:

"title": { "form": "Goo1", "auxVar": "*_MyAuxVar", "key": 0 }

Example: You want to dynamically adjust an option's text brightness from a JIP Auxiliary-Variable:

"brightnessMul": { "form": "Goo1", "auxVar": "*_MyAuxVar", "key": 0 }

Option Visibility

Include either the "enable" or "state" element to control a option's visibility state.

ℹ️ Note: If both options are included, the "state" element will always take priority.

  • "enable": Controls the option's interactivity.
    • 0: Hidden. The option is not visible.
    • 1: Enabled. The option is visible and can be interacted with.
    • 2: Disabled. The option is visible but greyed out and cannot be selected.
  • "state" Preforms an equality check with a Variable Object and numeric "value".
    • To make the option disabled (visible but greyed out) instead of hidden, add "disable": 1 to the state object.
"enable": 1,
"state": { "form": "SomeQuest", "numVar": "SomeVariable", "value": 1, "disable": 1 },

Option Refresh

The "refresh" element forces the active MCM menu to refresh itself.

At the moment it only has one possible value:

  • 1: Forces all submenus to revalidate their "state" element

ℹ️ Note: This can be useful if you want an option to control a submenu's visibility state.

Option Scripts

The "call" object takes 2 keys and calls a specified script function whenever the option's value is changed. This is useful for scripted changes that are not handled by other variable types.

"type" "value" Example Extra Info
"udf" UDF EditorID "call": { "type": "udf", "value": "YourOptionUDF" } Call
"file" CompileScript path "call": { "type": "file", "value": "Folder/YourOptionUDF.gek" } CompileScript
"event" Event name "call": { "type": "event", "value": "MyCustomEvent" } DispatchEventAlt
"snippet" Formatted script string "call": { "type": "snippet", "value": "Player.AddItem Stimpak" } RunScriptSnippet
"console" Formatted console string "call": { "type": "console", "value": "TGM" } Console

For udf, file, and event types, the function is passed the new value and contextual information:

Begin Function { float fValue, int iMenu, int iSubmenu, int iOption, array_var aMenuMap }
    ...
End

Option Scale Scripts

The special "callOpen", "callClose", and "callLoop" objects are variants of the standard "call" object. They are used to trigger a specified script function based on the state of the selected option's scale menu:

  • "callOpen": Executes the script function once when the scale menu is first opened.
  • "callClose": Executes the script function once when the scale menu is closed.
  • "callLoop": Executes the script function continuously while the scale menu is active.

For udf, file, and event types, the function is passed the scale menu values and contextual information:

Begin Function { int iSubmenu, int iOption, array_var aValues }
    ...
End

Option Image Map

Option type 1 can optionally be used to display an image instead of a string header.

Specify the image properties by adding following key-value pairs to the image object:

Key Name Value Type Required Description
"filename" String Path to the .dds image file to be displayed
"width" Int Display width of the image in pixels
"height" Int Display height of the image in pixels
"systemcolor" Int Systemcolor tint applied to the image. See Systemcolor Indexes
"offsetX" Int X offset from the center of the MCM options window
"offsetY" Int Y offset from the center of the MCM options window

Example: You want to display your mod's custom logo:

"image": {
    "filename": "Interface/YourCustomLogo.dds",
    "width": "700",
    "height": "350",
    "systemcolor": 5,
    "offsetX": 0,
    "offsetY": -30
}

Systemcolor Indexes

Systemcolor is the color tint that will be applied to your image.

The index corresponds to the tint of a specific interface component:

Index Color
0 None
1 HUD
2 HUD Alt (Red)
3 Terminal (Green)
4 Pip-Boy
5 Pause Menu

Option String Array

This array provides the text labels for option type 1. The array index correspond to the variable's value, starting at 0.

"strings": [ "String 0", "String 1", "String 3" ]

You can optionally include a stringsAlt array to override the string displayed for the selected option type 1 value on the menu page.

When provided, the string at the corresponding index in stringsAlt is displayed next to the option title, while the strings in strings are still used for the actual dropdown list. This is useful for displaying a shorter or less descriptive string in the main menu for brevity.

"strings": [ "List String 0", "List String 1", "List String 2" ],
"stringsAlt": [ "Display String 0", "Display String 1", "Display String 2" ]

Option Scale Map

A scale object defines the appearance and parameters of the Scale Menu used by option types 2, 2.5, and 8.

A scale object can include the following key-value pairs:

Key Name Value Type Option Type Required Description
"title" String Any Title shown in the scale menu (defaults to the option title if omitted)
"suffix" String 2, 2.5 Text appended after the displayed value
"valueDecimal" Int 2, 2.5 Number of decimal places to display
"valueIncrement" Int/Float 2, 2.5 Step size for each scale menu increment
"valueMin" Int/Float 2, 2.5 Minimum selectable value in the scale menu
"valueMax" Int/Float 2, 2.5 Maximum selectable value in the scale menu
"setting1.." String 8 Strings labeling each variable
"value1Decimal..." Int 8 Number of decimal places to display
"value1Increment..." Int/Float 8 Step size for each scale menu increment
"value1Min..." Int/Float 8 Minimum selectable value in the scale menu
"value1Max..." Int/Float 8 Maximum selectable value in the scale menu

For option type 8, the required elements depend on the number of Variable Objects in the vars array.

Example: if the array includes two Variable Objects, the scale object might look like this:

"scale": {
    "title": "Health Threshold",
    "setting1": "Var1",
    "setting2": "Var2",
    "value1Decimal": 0,
    "value2Decimal": 0,
    "value1Increment": 10,
    "value2Increment": 5,
    "value1Min": 10,
    "value2Min": 0,
    "value1Max": 100,
    "value2Max": 50
}

Option Variables

The vars array contains one or more Variable Objects. Some option types accept a flexible number of Variable Objects, while others require a fixed amount. The table below shows how many Variable Objects each option type requires.

Option Type Variable Objects
0 0
1 > 0
2 > 0
3 > 0
4 > 0
5 > 0
6 > 0
7 0
8 2-3
9 3

Variable Objects

Variable Objects define which variables and INI config settings MCM Extender updates automatically when an option changes.

The simplest Variable Object is a key–value pair that saves the option value to your mod’s INI file.

Key Name Value Type Required Description
"default" Int/Float The default value of the variable
"configINI" String The section:key for the value in the config INI file
{ "configINI": "General:iYourOption", "default": 1 }

You can include a Variable Type in a Variable Object to have MCM Extender update it along with your config file.

To update a Variable Type without saving it to your config, omit the configINI element.

See Variable Type below for examples of all supported data types.

Variable Types

⚠️ Important: When entering the Player reference in a form element, you must use the string "PlayerRef". Using "Player" will incorrectly point to the player's BaseForm.

Value of the numeric variable specified by name for the calling reference or specified scriptable object / quest.

  • "form": BaseForm or Reference containing the script (Editor ID String)
  • "numVar": int/float variable name (String)
{ "form": "YourQuest", "numVar": "YourQuestInt", "configINI": "General:iYourOption", "default": 1 }

Value of an array variable index specified by name for the calling reference or specified scriptable object / quest.

  • "form": BaseForm or Reference containing the script (Editor ID String)
  • "arrVar": array_var variable name (String)
  • "key": Array/Map key (Int or String)
{ "form": "YourQuest", "arrVar": "YourQuestArray", "key": 1, "configINI": "General:iYourOption", "default": 1 }
  • "form": Reference containing the token (Editor ID String)
  • "token": Token form (Editor ID String)
{ "form": "SunnyREF", "token": "ModToken", "configINI": "General:iYourOption", "default": 1 }

⚠️ Important: Ensure the specified Auxiliary-Variable index has been initialized.

  • "form": BaseForm or Reference Auxiliary variable owner (Editor ID String)
  • "auxVar": Auxiliary variable name (String)
  • "key": Index (Int)
{ "form": "Goo1", "auxVar": "*_MyAuxVar", "key": 0, "configINI": "General:iYourOption", "default": 1 }
  • "form": BaseForm or Reference key
  • "refMap": Ref map name (String)
{ "refMap": "*_MyRefMap", "form": "SunnyRef", "configINI": "General:iYourOption", "default": 1 }

Showoff Auxiliary String Maps (Undocumented)

  • "auxStringMap": Auxiliary string map name (String)
  • "key": Map key (String)
{ "auxStringMap": "*_MyStringMap", "key": "MyStringMapKey", "configINI": "General:iYourOption", "default": 1 }
  • "configINI": The section:key for the value in the INI file.
  • "iniPath": (Optional) A filepath relative to Data\config\. Overrides the global "saveFile" from the metadata for this variable only.
{ "configINI": "General:iYourOption", "iniPath": "MyFolder/MyFile.ini", "default": 1 }
  • "gameINI": The key:section for the value in the INI file.
{ "gameINI": "fBlurRadiusPipboy:Pipboy", "configINI": "General:iYourOption", "default": 1 }
  • "gameSetting": GameSetting name
{ "gameSetting": "iXPRewardPickLockEasy", "configINI": "General:iYourOption", "default": 1 }
  • "global": Global Variable (Editor ID String)
{ "global": "TrapXPRewardEasy", "configINI": "General:iYourOption", "default": 1 }
  • "uiTrait": UI trait name as defined in the XML hierarchy for the desired menu.
{ "uiTrait": "HUDMainMenu/YourUITile/_YourUITrait", "configINI": "General:iYourOption", "default": 1 }

Scripting Integration and Events

While MCM Extender can directly modify variables and INI files, your mod's scripts may need to react to these changes in real-time (e.g., to update visuals or running processes).

When the user closes the MCM menu, MCM Extender dispatches a MCMExtUpdate event. This event is passed an array of modNames that have been updated. Your scripts can listen for this event to know when to re-read settings and apply changes.

SetEventHandler "MCMExtUpdate" MyMCMMenuUpdateHandler
scn MyMCMMenuUpdateHandler

Begin Function { array_var aUpdatedMods }

    ; Check if your mod's modName is in the array and run update logic
    if eval (Ar_Find "YourNodName" aUpdatedMods) != Ar_BadNumericIndex
        ; Run update logic here
    endif

    aUpdatedMods = ar_Null

End

When the user switches submenu, mod menu, or toggles the MCM window off, MCM Extender dispatches a MCMExtMenuState event.

This event is passed the active modName and submenu if selecting an MCM Extender supported menu. Otherwise it is passed an empty string and 0 if selecting a legacy MCM menu, or -1 if closing the MCM window.

SetEventHandler "MCMExtMenuState" MyMCMMenuStateHandler
scn MyMCMMenuStateHandler

Begin Function { string_var sModName, int iSubmenu }

    ; Check if your mod's submenu 1 has been selected
    if eval sModName == "YourModName" && iSubmenu == 1
        ; Run update logic here
    endif

    sv_Destruct sModName

End

Translations and Localization

MCM Extender supports localization, allowing you to provide translations for any string in your menu. This is handled by pairing specially formatted JSON strings with a corresponding translation file.

The process involves two steps:

1. Mark Strings for Translation in JSON

To mark a string value in your JSON file as translatable, prefix it with a dollar sign ($). This can be used for any string value, such as a mod's display name, a submenu title, or an option's mouseover text.

Example: You want to translate your mod's display name:

"modName": "MyAmazingMod",
"displayName": "$MyModName",

2. Create the Translation File

Next, you must provide a file containing the translated text.

  • Location: This file must be placed in the Data\MCM\translations\ directory.

  • Filename: The name of this file must exactly match the modName you specified in your JSON metadata, with an .ini extension. For example, if your modName is "MyAmazingMod", your translation file must be named MyAmazingMod.ini.

  • Format: Inside this file, create a section called [Translations]. Under this section, define each translation key from your JSON file (including the $) and set its value to the desired text.

Translation File Example

Based on the JSON example above, the corresponding MyAmazingMod.ini might look like this:

[Translations]
$MyModName = Mod Name
$Submenu1List = Submenu List Name
$Submenu1Page = Submenu Page Name
$Option1Name = Option Name
$Option1Mouse = Option mouseover description.

When the menu is loaded, MCM Extender will find any string value starting with $ and replace it with the corresponding text from your translation file.

Best Practices & Common Pitfalls

To ensure your MCM Extender JSON is valid and works as expected, keep the following points in mind:

  • Numeric Keys are Strings: All keys in the submenus and options maps must be strings, even if they are numbers (e.g., use "1":, not 1:).
  • Case Sensitivity: The JSON parser is case-sensitive. Always match the casing shown in this guide.
  • Player Reference: When a variable requires a reference to the Player, always use "PlayerRef". Using "Player" points to the Player's BaseForm.
  • Path Separators: When defining file paths in keys like "saveFile" or for requirements, it is safest to use forward slashes (/) (e.g., "Config/MyMod.ini"). While backslashes (\) may work, forward slashes are more universally compatible.

ℹ️ Hotloading JSON: To quickly apply changes to your JSON file while in-game, you can hotload the updated file by simply closing and re-opening the pause menu. This forces the MCM Extender to re-read the configuration.

Complete Minimal Example

Here is a complete example of a minimal, valid JSON file for a single-page MCM. This demonstrates how the metadata, requirements, and a single submenu with two options are structured together.

{
    "modName": "MyAmazingMod",
    "displayName": "My Amazing Mod",
    "description": "UNUSED",
    "saveFile": "MyAmazingMod/settings.ini",
    "minMCMVersion": 1.0,
    "minModVersion": 1.0,
    "requirements": [
        { "type": "plugin", "file": "MyAmazingMod.esp" }
    ],
    "submenus": {
        "0": {
            "columns": 1,
            "listTitle": "Main",
            "pageTitle": "My Amazing Mod Settings",
            "options": {
                "1": {
                    "type": 0,
                    "enable": 1,
                    "title": "General Settings"
                },
                "2": {
                    "type": 4,
                    "enable": 1,
                    "title": "Enable Awesome Feature",
                    "mouse": "Toggles the main feature of the mod on or off.",
                    "vars": [
                        { "configINI": "General:bAwesomeFeatureEnabled", "default": 1 }
                    ]
                }
            }
        }
    }
}