[title: "UI Modification Guide"] ← Back to index

Learn how to customize menus, interfaces, and user experience in PadManiaX.

[heading: "Understanding the UI System"]

PadManiaX uses several UI systems that you can modify:

[list] * Window System - Modal dialogs and settings * CarouselMenu - Vertical scrolling menus * Text System - Retro font rendering * Notification System - Temporary messages * HUD Elements - Gameplay interface [/list] [heading: "Basic UI Modification"] [subheading: "Modifying Menus with game.onMenuIn"]

The most powerful way to modify UI is using the game.onMenuIn signal:

[codeblock js] // behaviors/menu.js game.onMenuIn.add(function(menuName, menuInstance) { console.log("Menu created:", menuName); // Different menus have different instances switch(menuName) { case 'home': modifyHomeMenu(menuInstance); break; case 'settings': modifySettings(menuInstance); break; case 'songList': modifySongList(menuInstance); break; } }); function modifyHomeMenu(menu) { // menu is a CarouselMenu instance console.log("Home menu items:", menu.items); // Add custom menu item menu.addItem("Custom Option", function() { notifications.show("Custom option selected!"); }); } [/codeblock] [subheading: "Available Menu Names"] [table header] [ Menu Name | Description | Instance Type ] [ home | Main home menu | CarouselMenu ] [ startGame | Game mode selection | CarouselMenu ] [ extraSongs | Additional songs menu | CarouselMenu ] [ settings | Settings window | Window ] [ addons | Addon manager | CarouselMenu ] [ addonDetails | Addon details | CarouselMenu ] [ songList | Song selection | CarouselMenu ] [ difficulty | Difficulty selection | CarouselMenu ] [ results | Results screen | CarouselMenu ] [ pause | Pause menu | CarouselMenu ] [/table] [heading: "Working with CarouselMenu"] [subheading: "Adding Menu Items"] [codeblock js] game.onMenuIn.add(function(menuName, menu) { if (menuName === 'home') { // Add simple menu item menu.addItem("My Feature", function() { notifications.show("My feature activated!"); }); // Add item with custom data menu.addItem( "Styled Item", function() { /* callback */ }, { bgcolor: "#ff0000", // Red background fgcolor: "#ffffff" // White text } ); } }); [/codeblock] [subheading: "Modifying Existing Items"] [codeblock js] game.onMenuIn.add(function(menuName, menu) { if (menuName === 'home') { // Wait for menu to be fully created setTimeout(() => { // Modify existing items menu.items.forEach((item, index) => { if (item.textContent === "Rhythm Game") { item.setText("Let's Rock!"); // Customize text } }); }, 100); } }); [/codeblock] [heading: "Working with Window System"] [subheading: "Creating Custom Windows"] [codeblock js] function showCustomWindow() { // Create window using WindowManager const windowManager = new WindowManager(); const customWindow = windowManager.createWindow(5, 5, 10, 8, "1"); // Add content to window customWindow.addItem("Option 1", function() { notifications.show("Option 1 selected"); windowManager.remove(customWindow, true); }); customWindow.addItem("Option 2", function() { notifications.show("Option 2 selected"); windowManager.remove(customWindow, true); }); customWindow.addItem("Close", function() { windowManager.remove(customWindow, true); }, true); // true makes this a back button } [/codeblock] [subheading: "Adding Settings"] [codeblock js] game.onMenuIn.add(function(menuName, menu) { if (menuName === 'settings' && menu.addSettingItem) { // Add custom setting menu.addSettingItem( "My Custom Setting", // Display name ["Disabled", "Enabled"], // Options 0, // Default index function(index, value) { // Callback Account.settings.mySetting = index === 1; saveAccount(); notifications.show("Setting saved: " + value); } ); } }); [/codeblock] [heading: "Custom Text and Graphics"] [subheading: "Creating Text Elements"] [codeblock js] function addCustomText() { // Create text with different fonts const text1 = new Text(50, 30, "Welcome!", FONTS.default); const text2 = new Text(50, 50, "Shaded Text", FONTS.shaded); const text3 = new Text(50, 70, "Outlined", FONTS.stroke); // Customize text text1.tint = 0xff0000; // Red color text2.anchor.set(0.5); // Center anchor // Add to game world game.world.add(text1); game.world.add(text2); game.world.add(text3); } [/codeblock] [subheading: "Creating Custom Graphics"] [codeblock js] function addCustomGraphics() { // Create graphics object const graphics = game.add.graphics(0, 0); // Draw rectangle graphics.beginFill(0x00ff00, 0.5); // Green, 50% opacity graphics.drawRect(50, 50, 100, 50); graphics.endFill(); // Draw line graphics.lineStyle(2, 0xff0000, 1.0); // Red, 2px width graphics.moveTo(0, 0); graphics.lineTo(100, 100); } [/codeblock] [heading: "Advanced UI Techniques"] [subheading: "Modal Dialogs"] [codeblock js] function showConfirmationDialog(message, onConfirm, onCancel) { const windowManager = new WindowManager(); const dialog = windowManager.createWindow(5, 5, 15, 6, "1"); // Add message text const text = new Text(8, 8, message, FONTS.default); dialog.addChild(text); // Add buttons dialog.addItem("Yes", function() { windowManager.remove(dialog, true); onConfirm && onConfirm(); }); dialog.addItem("No", function() { windowManager.remove(dialog, true); onCancel && onCancel(); }, true); } // Usage: showConfirmationDialog( "Are you sure?", function() { notifications.show("Confirmed!"); }, function() { notifications.show("Cancelled!"); } ); [/codeblock] [subheading: "Dynamic Menu Creation"] [codeblock js] function createDynamicMenu(items) { const carousel = new CarouselMenu(0, 30, 100, 80, { bgcolor: "#3498db", fgcolor: "#ffffff", align: 'left' }); // Add items dynamically items.forEach(item => { carousel.addItem(item.name, item.callback, item.data); }); // Handle selection carousel.onSelect.add(function(index, item) { console.log("Selected:", item.textContent); }); return carousel; } // Usage: const menuItems = [ { name: "Item 1", callback: () => console.log("1") }, { name: "Item 2", callback: () => console.log("2") }, { name: "Item 3", callback: () => console.log("3") } ]; const dynamicMenu = createDynamicMenu(menuItems); [/codeblock] [heading: "Gameplay HUD Modification"] [subheading: "Modifying Play State UI"] [codeblock js] // behaviors/gameplay.js if (state && state.createHud) { // Store original method const originalCreateHud = state.createHud; // Override with custom HUD state.createHud = function() { // Call original to create standard HUD originalCreateHud.call(this); // Add custom HUD elements this.customScoreText = new Text(10, 10, "Custom: 0", FONTS.default); this.hud.addChild(this.customScoreText); }; } [/codeblock] [subheading: "Real-time HUD Updates"] [codeblock js] // behaviors/gameplay.js if (state && state.player) { // Hook into player update const originalUpdate = state.player.update; state.player.update = function() { // Call original update originalUpdate.call(this); // Update custom HUD if (state.customScoreText) { state.customScoreText.write("Custom: " + this.score); } }; } [/codeblock] [heading: "Best Practices"] [subheading: "UI Design Guidelines"] [list] * Maintain consistent styling with the game * Use the retro pixel art aesthetic * Keep text readable and concise * Test on different screen sizes * Consider mobile touch targets [/list] [subheading: "Performance Considerations"] [list] * Avoid creating too many UI elements * Clean up elements when not needed * Use appropriate update frequencies * Test on target devices [/list] [subheading: "User Experience"] [list] * Provide clear feedback for user actions * Use familiar interaction patterns * Include accessibility considerations * Test with actual users [/list] [heading: "Debugging UI Modifications"] [subheading: "Enable Debug Console"] [codeblock js] eruda.init(); // Enable developer console // Log UI events game.onMenuIn.add(function(menuName, menu) { console.log("Menu created:", menuName, menu); }); [/codeblock] [subheading: "Common Issues"] [table header] [ Issue | Cause | Solution ] [ UI not appearing | Wrong menu name | Check game.onMenuIn logs ] [ Elements misaligned | Wrong coordinates | Use game.width/game.height ] [ Performance issues | Too many elements | Optimize or remove elements ] [ Crashes | Invalid operations | Use try-catch blocks ] [/table] [heading: "Example: Complete UI Mod"] [subheading: "Manifest"] [codeblock json] { "id": "custom-ui-theme", "name": "Custom UI Theme", "version": "1.0.0", "behaviors": { "Global": "behaviors/global.js", "MainMenu": "behaviors/menu.js" }, "assets": { "ui_window_1": "assets/custom_window.png" } } [/codeblock] [subheading: "Menu Behavior"] [codeblock js] // behaviors/menu.js game.onMenuIn.add(function(menuName, menu) { console.log("Custom UI: Menu created -", menuName); if (menuName === 'home') { // Add welcome message const welcomeText = new Text( game.width / 2, 20, "Welcome to Custom UI!", FONTS.shaded ); welcomeText.anchor.set(0.5); welcomeText.tint = 0x76fcde; // Cyan color game.world.add(welcomeText); // Modify menu appearance menu.config.bgcolor = "#9b59b6"; // Purple menu.config.fgcolor = "#ffffff"; // White // Add custom menu item menu.addItem("Custom Music Player", function() { notifications.show("Music player launched!"); }); } }); [/codeblock] [heading: "Next Steps"]

Now that you've understood how to modify UI, check out these tutorials:

[list] * Asset Replacement Tutorial * Creating Behavior Scripts [/list] [footer: "© Retora 2025"]