RMenu 1.2.0

dotnet add package RMenu --version 1.2.0
                    
NuGet\Install-Package RMenu -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RMenu" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RMenu" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="RMenu" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RMenu --version 1.2.0
                    
#r "nuget: RMenu, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RMenu@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RMenu&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=RMenu&version=1.2.0
                    
Install as a Cake Tool

RMenu

A rich, feature-packed HTML center-menu library for CounterStrikeSharp plugins.


Massive, Enormous, Colossal Shoutout to oscar-wos

This library would not exist without oscar-wos.

Every single piece of the core architecture, the rendering pipeline, the HTML engine, the input hooking system, the rainbow/strobe colour system, the menu threading model, the trim logic, the selector and cursor system all of it was built by oscar-wos from the ground up.

We are standing on the shoulders of his work. We forked this project and added a handful of quality-of-life features to suit our own needs.

If you use this library, go star his repo. He earned it.


Overview

RMenu is the EdgeGamers standard menu library for CounterStrikeSharp plugins. It provides a fully-featured, highly customisable HTML-rendered center-screen menu system driven by player button inputs no chat commands required.

Installation

NuGet

dotnet add package RMenu

Or add it directly to your .csproj:

<PackageReference Include="RMenu" Version="*" />

Quick Start

using RMenu;
using RMenu.Enums;

// Display a basic menu to a player
MenuBase menu = new(new MenuValue("My Menu"), new MenuValue("footer"));
menu.Items.Add(new MenuItem(MenuItemType.BUTTON, new MenuValue("Option 1")));
menu.Items.Add(new MenuItem(MenuItemType.BUTTON, new MenuValue("Option 2")));

Menu.Display(player, menu, callback: (m, action) => {
if (action == MenuAction.SELECT)
player.PrintToChat($"You selected item {m.SelectedItem?.Index + 1}");

    if (action == MenuAction.EXIT)
        player.PrintToChat("Menu closed");
});

Core Concepts

The root menu object. Holds header, footer, items, options, and the player it is displayed to.

MenuBase menu = new(
header:  new MenuValue("Header Text"),
footer:  new MenuValue("Footer Text"),
options: new MenuOptions { BlockMovement = true },
data:    someOptionalData
);

A MenuValue is a piece of displayable text, made up of one or more MenuObject segments — each with their own colour and style.

// Simple value
MenuValue simple = new("Hello World");

// Styled value
MenuValue styled = new("Warning!", new MenuFormat(Color.Red, MenuStyle.BOLD));

// Multi-segment value (implicit from List<MenuObject>)
MenuValue multipart = [
new("Hello ", new MenuFormat(Color.Green)),
new("World",  new MenuFormat(Color.Blue, MenuStyle.BOLD))
];

Controls the appearance of a MenuObject.

new MenuFormat(
color:        Color.Cyan,
style:        MenuStyle.BOLD,   // NONE | BOLD | ITALIC | MONO
canHighlight: true              // Whether the selection highlight overrides this format
)

Colour Effects

Use the RMenu.Extensions colour extensions for animated effects:

using RMenu.Extensions;

// Animated rainbow cycle
new MenuFormat(new Color().Rainbow())

// Strobe between two colours
new MenuFormat(new Color().Strobe(Color.Red, Color.Orange))

// Reversed strobe
new MenuFormat(new Color().StrobeReversed(Color.Blue, Color.Purple))

Add items to menu.Items using MenuItem:

new MenuItem(
type:     MenuItemType.BUTTON,
head:     new MenuValue("Label "),
values:   null,                         // scrollable values (CHOICE / multi-BUTTON)
tail:     new MenuValue(" suffix"),
options:  new MenuItemOptions(),
data:     someData,
callback: (menu, item, action) => { }   // per-item callback
)

Item Types

Type Description
BUTTON A selectable button. Add values to make it a scrollable picker.
CHOICE A standalone scrollable value picker.
INPUT A text input field — activates chat input mode on select.
TEXT Non-selectable display text.
SPACER A blank line separator.
new MenuItemOptions {
Pinwheel  = true,          // Whether the value list wraps around at the ends
Trim      = MenuTrim.HEAD, // NONE | HEAD | TAIL — truncate overflow from head or tail
Continuous = new MenuContinuous<MenuButton> {
[MenuButton.LEFT]  = 100,  // ms hold-repeat delay for LEFT on this item
[MenuButton.RIGHT] = 100
}
}

MenuOptions controls the look and behaviour of an entire menu.

MenuOptions options = new() {
BlockMovement        = true,                 // Freeze player movement
Exitable             = true,                 // Allow EXIT button to close menu
DisplayItemsInHeader = true,                 // Show "2/5 ⇦" counter in header
Priority             = 0,                    // Higher priority menus insert at front
HeaderFontSize       = MenuFontSize.L,
ItemFontSize         = MenuFontSize.SM,
FooterFontSize       = MenuFontSize.S,
Highlight            = new MenuFormat(Color.Green, MenuStyle.BOLD),
Cursor               = [
new MenuObject("► ", new MenuFormat(Color.Yellow)),
new MenuObject(" ◄", new MenuFormat(Color.Yellow))
],
Selector             = [new MenuObject("[ "), new MenuObject(" ]")],
Input                = new MenuValue("________"),  // Placeholder for INPUT items
};

// Remap buttons
options.Buttons[MenuButton.SELECT] = PlayerButtons.Use | PlayerButtons.Jump;

// Set continuous hold delay globally
options.Continuous[MenuButton.UP]   = 150;
options.Continuous[MenuButton.DOWN] = 150;

Font Sizes

MenuFontSize: XS S SM M ML L XL XXL XXXL


Callbacks receive a MenuAction value:

Action Description
START Menu was just displayed to the player
SELECT Player confirmed the current selection
CHOOSE Player moved the cursor to a different item
UPDATE Player changed a scrollable value (LEFT/RIGHT)
EXIT Player exited the menu via BACK or EXIT
ASSIST Player pressed the ASSIST button
INPUT Player submitted text via chat (INPUT items)

Static Menu API

// Display a menu to a player
Menu.Display(player, menu, subMenu: false, callback: (m, a) => { });

// Get the currently active menu for a player
MenuBase? current = Menu.Get(player);

// Close the top sub-menu and return to the previous
Menu.Close(player);

// Clear all menus for a player
Menu.Clear(player);

// Force-clear even non-exitable menus
Menu.Clear(player, force: true);

Pass subMenu: true to push a menu on top of the existing stack. The sub-menu inherits the parent's options (with overrides merged in) and shows the back indicator in the header.

csharp
Menu.Display(player, subMenu: true, menu: childMenu, callback: (m, action) => {
if (action == MenuAction.EXIT)
player.PrintToChat("Returned from sub-menu");
});

Text Input Items

Add an INPUT item to collect free-text from a player via chat:

menu.Items.Add(new MenuItem(MenuItemType.INPUT, new MenuValue("Name: ")));

Menu.Display(player, menu, callback: (m, action) => {
if (action == MenuAction.INPUT) {
var item  = m.SelectedItem?.Item;
var input = item?.Data as string;
player.PrintToChat($"You typed: {input}");
}
});

When the player selects the INPUT item, the placeholder is shown and the next chat message they send is captured as the value — without printing to chat.


OnPrintMenu Event

Intercept and modify the raw HTML string before it is sent to the player each tick:

Menu.OnPrintMenu += (_, e) => {
e.Html = e.Html.Replace("someText", "replacedText");
};

Per-Item Callbacks

Each MenuItem and MenuValue can have its own callback in addition to the top-level menu callback. All three are fired in order: value → item → menu.

menu.Items.Add(new MenuItem(
MenuItemType.BUTTON,
new MenuValue("Delete"),
data: playerId,
callback: (menu, item, action) => {
if (action == MenuAction.SELECT)
player.PrintToChat($"Deleted: {item.Data}");
}
));

Default Button Bindings

Menu Action Default CS2 Button
UP Forward (W)
DOWN Back (S)
LEFT Moveleft (A)
RIGHT Moveright (D)
SELECT Jump (Space)
BACK Duck (Ctrl)
EXIT Scoreboard (Tab)

Built for the EdgeGamers community. All credit for the foundational work again goes to oscar-wos — an absolute legend.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 35 4/8/2026
1.1.0 36 4/7/2026
1.0.1 35 4/7/2026
1.0.0 39 4/7/2026