Scripting Plate Logic

Patterns, charsets, presets, and fixed text splits are often enough to handle most license plate designs without any scripting. However, if you need the plate’s appearance to react to the text the player enters, like showing a specific badge for certain prefixes, hiding a line for special codes, or changing the background based on a region number, then scripted logic becomes necessary.

How It Fits Together

The template file stays declarative. It describes what can be drawn, but it does not run code by itself.

If your plate needs logic, add a Lua module to your mod and point to it from the template with the top-level logic field:

{
  "name": "my_license_plate",
  "version": 3,
  "type": "licenseplate",
  "logic": "ge.extensions.mod_name.specialPlateLogic",
  "vars": {
    "plate": {
      "type": "string",
      "default": "A123",
      "maxLength": 8
    }
  },
  "format": {
    "30-15": {
      "size": [512, 256],
      "background": "vehicles/common/licenseplates/my_license_plate/my_license_plate_background_d.png",
      "root": {
        "name": "root",
        "children": [
          {
            "name": "badge",
            "type": "image",
            "src": "",
            "style": { "position": "absolute", "left": 24, "top": 24, "width": 64, "height": 64 }
          },
          {
            "name": "plateText",
            "type": "text",
            "text": "{displayText}",
            "font": "plate",
            "fontSize": 92,
            "color": "#000000",
            "fit": "shrink",
            "style": { "position": "absolute", "left": 96, "right": 24, "top": 82, "height": 100 }
          }
        ]
      }
    }
  }
}

The logic path matches a Lua file in your mod. This example expects:

/mods/unpacked/mod_name/lua/ge/extensions/mod_name/specialPlateLogic.lua

The Resolver Function

The Lua file returns a module with a resolve function:

local M = {}

function M.resolve(text, format, design)
    local displayText = tostring(text or "")
    local badge = ""

    if displayText:sub(1, 2) == "EV" then
        badge = "vehicles/common/licenseplates/my_license_plate/badge_ev.png"
        displayText = displayText:sub(3)
    elseif displayText:sub(1, 2) == "TR" then
        badge = "vehicles/common/licenseplates/my_license_plate/badge_truck.png"
        displayText = displayText:sub(3)
    end

    return {
        vars = {
            displayText = displayText
        },
        nodes = {
            badge = {
                src = badge
            }
        }
    }
end

return M

The function receives:

  • text: the plate text being rendered.
  • format: the format code, such as 30-15 or 52-11.
  • design: the whole template table.

It can return:

  • vars: extra values that replace {tokens} in text nodes.
  • nodes: patches for nodes with matching name values.
  • background: a replacement background path.
  • normal: a replacement normal map path.

In the example, typing EV1234 displays 1234 and shows an EV badge. Typing TR1234 displays 1234 and shows a truck badge. Any other text shows no badge.

Naming Nodes For Logic

A resolver can only patch nodes that have a stable name. If Lua needs to change a text color, an image path, a transform, or letter spacing, give that node a clear name in the template.

Good names are boring and specific: plateText, regionText, leftBadge, inspectionSticker.

Keep It Deterministic

Do not use the current date, true random numbers, or anything that changes between players unless you derive it from the plate text. The same plate text should render the same way after a reload and for every player in multiplayer.

If you want variety, prefer preset variables in the template. If you need Lua, base the choice on the text string.

Last modified: July 30, 2026

Any further questions?

Join our discord
Our documentation is currently incomplete and undergoing active development. If you have any questions or feedback, please visit this forum thread.