RLS Studios
ProjectsPatreonCommunityDocsAbout
Join Patreon
BeamNG Modding Docs

Guides

Creating HUD AppsLua ↔ UI BridgeGUI Hooks Reference

Reference

UI

Resources

BeamNG Game Engine Lua Cheat SheetGE Developer RecipesMCP Server Setup

// RLS.STUDIOS=true

Premium Mods for BeamNG.drive. Career systems, custom vehicles, and immersive gameplay experiences.

Index

HomeProjectsPatreon

Socials

DiscordPatreon (RLS)Patreon (Vehicles)

© 2026 RLS Studios. All rights reserved.

Modding since 2024

GuidesUI

Creating HUD Apps

How to create UI apps (HUD widgets) for BeamNG.drive — directory structure, AngularJS directives, receiving Lua data, and styling.

UI apps are draggable HUD widgets that players add to their screen — speedometers, debug panels, mission trackers, or anything your mod needs to display. They're built with AngularJS directives and communicate with your Lua code through the UI bridge.


Directory Structure

ui/modules/apps/mymod-hud/
  app.js        -- AngularJS directive
  app.json      -- metadata
  app.css       -- styles (optional)

Place this inside your mod's zip or folder overlay.


app.json

Defines the app metadata:

{
  "name": "My Mod HUD",
  "author": "Your Name",
  "version": "1.0",
  "description": "Shows mod info on screen",
  "directive": "myModHud",
  "categories": ["debug"],
  "width": 300,
  "height": 200
}

The directive field must match the AngularJS directive name in app.js.


app.js

A minimal UI app:

angular.module('beamng.apps')
.directive('myModHud', ['bngApi', function (bngApi) {
  return {
    restrict: 'E',
    template: '<div class="my-mod-hud">' +
                '<span>Score: {{score}}</span>' +
              '</div>',
    link: function (scope, element) {
      scope.score = 0

      // Receive data from Lua
      scope.$on('MyModScoreUpdate', function (event, data) {
        scope.$apply(function () {
          scope.score = data.score
        })
      })

      // Send command to Lua
      scope.resetScore = function () {
        bngApi.engineLua('extensions.mymod_hud.resetScore()')
      }

      // Clean up listener on destroy
      scope.$on('$destroy', function () {
        // AngularJS handles $on cleanup automatically
      })
    }
  }
}])

Receiving Data from Lua

In your GE extension, push data to the UI:

local M = {}

local function updateScore(score)
  guihooks.trigger('MyModScoreUpdate', { score = score })
end

M.updateScore = updateScore

return M

In the app, listen with scope.$on():

scope.$on('MyModScoreUpdate', function (event, data) {
  scope.$apply(function () {
    scope.score = data.score
  })
})

Always wrap scope changes in scope.$apply() when they come from outside AngularJS.


Sending Commands to Lua

Use bngApi.engineLua() to call extension functions:

// Simple call
bngApi.engineLua('extensions.mymod_hud.doThing()')

// With arguments
bngApi.engineLua('extensions.mymod_hud.setValue(' + bngApi.serializeToLua(value) + ')')

Styling

Add an app.css file or use inline styles. Apps render inside the game's CEF browser, so standard CSS works.

.my-mod-hud {
  color: #fff;
  font-family: 'Roboto', sans-serif;
  padding: 8px;
  background: rgba(0, 0, 0, 0.6);
  border-radius: 4px;
}

Tips for styling:

  • Use rgba backgrounds for transparency over the game view
  • Light text on dark backgrounds for readability
  • Keep widgets compact - screen space is limited
  • Test at different resolutions

Tips

:::tip[Testing Apps] After making changes to your app files, call reloadUI() from the Lua console to see changes without restarting the game. :::

  • The directive name in app.json must exactly match the directive name in app.js
  • Directive names are camelCase in JS, but the HTML element is kebab-case (myModHud becomes <my-mod-hud>)
  • Use scope.$on('$destroy', ...) to clean up intervals or external listeners
  • Apps can be resized by the player - design for flexible dimensions

See Also

  • UI Bridge - How Lua communicates with the UI layer
  • GUI Hooks - Sending events to the UI
  • Cross-VM Comms - Full communication patterns

Lua Modding FAQ

Quick answers to the most common BeamNG Lua modding questions — extension structure, data persistence, UI communication, timers, and more.

Lua ↔ UI Bridge

How Lua communicates with the HTML/JavaScript UI layer — events, streams, engine calls, toast messages, and the fade screen system.

On this page

Directory Structureapp.jsonapp.jsReceiving Data from LuaSending Commands to LuaStylingTipsSee Also