Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Off-MapText

Draw custom text labels on the GTA V minimap and pause map in FiveM - district names, custom POIs, faction turf tags, event banners, anything you want written directly on the map.

Full control per label: font, size, bold, RGB color, opacity, alignment, rotation and outline. Everything is drawn at runtime on a canvas - no pre-made images required.

type: client lua


Features

  • Custom text labels placed at any in-game world coordinate.
  • 6 built-in system fonts out of the box (Arial, Verdana, Georgia, Courier New, Trebuchet MS, Comic Sans MS) - no .ttf files needed.
  • Custom .ttf/.otf fonts supported if you want your own branding (see Using custom fonts).
  • Per-text color (RGB), opacity, size, bold, alignment and rotation.
  • Optional outline/stroke (its own color, opacity and thickness) for readability over any map background.
  • Rendered on both the minimap and the pause (big) map.
  • Simple exports API to add / remove / update / clear text labels at runtime.

Preview (Example)

image image image

How it works

Because DrawText is not rendered on the pause map, Off-MapText uses the runtime-texture overlay technique:

  1. For every text label, its position is projected into an offscreen browser (DUI) that renders it on a <canvas> (transparent background) - html/text.html + html/text.js.
  2. The DUI is converted to a runtime texture (CreateRuntimeTextureFromDuiHandle).
  3. The texture is placed on the map through a scaleform overlay (MINIMAP_LOADER.gfxADD_SCALED_OVERLAY).
  4. All labels share one atlas texture, rebuilt whenever a label is added, removed or updated.

Requirements

  • A recent FiveM server artifacts build.
  • MINIMAP_LOADER.gfx must be present in the resource folder.

Installation

  1. Drop the resource folder into your server's resources directory.
  2. Make sure MINIMAP_LOADER.gfx is in the folder (next to fxmanifest.lua).
  3. Add it to your server.cfg:
    ensure Off-MapText

    The export/resource name is your folder name. If you keep the folder as Off-MapText, use exports['Off-MapText']. Rename consistently if you use another folder name.


Configuration

All settings live in config.lua.

Option Default Description
AtlasSize 4096 Resolution (px) of the shared atlas texture holding every text label. Higher = sharper text, more VRAM.
Pad 25.0 Minimum world-unit margin around the text bounds.
TextPadFactor 1.0 Extra safety margin around labels, as a multiple of the largest font size in use. Prevents glyphs from being clipped by the atlas sprite.
FlipY true Vertical orientation. Set to false if text appears mirrored top/bottom.
Fonts see below List of font family names available to use in font =.
DefaultFont 'Arial' Font used when a label omits font.
DefaultSize 32 Font size (px on the atlas) used when a label omits size.
DefaultColor {255, 255, 255} {r, g, b} used when a label omits color.
DefaultAlpha 255 Fill opacity (0–255) used when a label omits alpha.
DefaultAlign 'center' 'left' | 'center' | 'right', used when a label omits align.
DefaultOutline true Whether labels get an outline by default.
DefaultOutlineColor {0, 0, 0} Outline color used when a label omits outlineColor.
DefaultOutlineAlpha 255 Outline opacity used when a label omits outlineAlpha.
DefaultOutlineWidth 4 Outline thickness (px) used when a label omits outlineWidth.

Built-in fonts

Config.Fonts = {
    'Arial',
    'Verdana',
    'Georgia',
    'Courier New',
    'Trebuchet MS',
    'Comic Sans MS',
}

These are system fonts bundled with the CEF/Chromium browser FiveM uses for DUI - no font file to ship, they just work.

Text label format

{
    text = 'Elysian Island',        -- the string to draw
    font = 'Arial',                 -- must be one of Config.Fonts (or a custom font, see below)
    size = 34,                      -- font size in px (on the atlas)
    bold = true,                    -- optional, default false
    color = { 70, 130, 220 },       -- { r, g, b } 0-255
    alpha = 255,                    -- optional, overrides Config.DefaultAlpha
    align = 'center',               -- 'left' | 'center' | 'right'
    rotation = 0,                   -- degrees
    outline = true,                 -- optional, overrides Config.DefaultOutline
    outlineColor = { 0, 0, 0 },     -- { r, g, b } 0-255
    outlineAlpha = 200,             -- 0-255
    outlineWidth = 4,               -- px
    x = -150.0,                     -- world X
    y = -1620.0,                    -- world Y
}

Labels are 2D (X/Y position only). There is no hover/enter/exit detection - Off-MapText is a display-only resource.


Exports

All exports are client-side. Replace Off-MapText with your resource folder name.

addText(data)

Creates and renders a text label. Returns a numeric id (or nil if invalid).

local id = exports['Off-MapText']:addText({
    text = 'Vespucci',
    font = 'Georgia',
    size = 30,
    color = { 200, 70, 190 },
    x = -1250.0,
    y = -1050.0,
})

removeText(id)

Removes a label by id. Returns true if it existed.

exports['Off-MapText']:removeText(id)

updateText(id, data)

Replaces an existing label's data (position, text, style, ...) and redraws it. Returns true if it existed.

exports['Off-MapText']:updateText(id, {
    text = 'Vespucci (contested)',
    font = 'Georgia',
    size = 30,
    color = { 220, 40, 40 },
    x = -1250.0,
    y = -1050.0,
})

clearTexts()

Removes every label.

exports['Off-MapText']:clearTexts()

Loading text labels

test.lua is a minimal example: it loads every entry from Config.TestTexts through addText. Replace it with your own loader (database, server sync, admin command, etc.).

CreateThread(function()
    for i = 1, #Config.TestTexts do
        exports[GetCurrentResourceName()]:addText(Config.TestTexts[i])
    end
end)

Using custom fonts

The 6 built-in fonts require no setup because they're preinstalled in the CEF/Chromium engine FiveM uses for DUI. If you want your own .ttf/.otf font (a branded/stylized font for your server), you need to load it in the DUI page with a standard CSS @font-face. Two ways to do it:

Option A - Local font file (recommended)

  1. Create a html/fonts/ folder and drop your font file in it, e.g. html/fonts/MyFont.ttf.
  2. Register it in fxmanifest.lua so it's shipped to the client:
    files {
        'MINIMAP_LOADER.gfx',
        'html/text.html',
        'html/text.js',
        'html/fonts/MyFont.ttf'
    }
  3. Open html/text.html and load the font with @font-face in a <style> block:
    <style>
        @font-face {
            font-family: 'MyFont';
            src: url('fonts/MyFont.ttf') format('truetype');
        }
        html, body { margin: 0; padding: 0; background: transparent; overflow: hidden; }
        #c { display: block; background: transparent; }
    </style>
  4. Open html/text.js and make sure the font is loaded before the first draw, otherwise the canvas silently falls back to the default font on the first frame:
    const customFont = new FontFace('MyFont', 'url(fonts/MyFont.ttf)');
    customFont.load().then(function (loaded) {
        document.fonts.add(loaded);
        draw(); // redraw once the font is actually ready
    });
  5. Add the family name to config.lua so it shows up as a valid option:
    Config.Fonts = {
        'Arial',
        'Verdana',
        'Georgia',
        'Courier New',
        'Trebuchet MS',
        'Comic Sans MS',
        'MyFont',
    }
  6. Use it on any label like any other font:
    { text = 'Custom Font!', font = 'MyFont', size = 32, x = 0.0, y = 0.0 }

Option B - Embedded (base64) font

If you'd rather not ship a separate file, you can inline the font directly as base64 inside the @font-face src, avoiding an extra network/file request:

<style>
    @font-face {
        font-family: 'MyFont';
        src: url(data:font/ttf;base64,AAEAAAAL... ) format('truetype');
    }
</style>

This makes text.html heavier but keeps everything in a single file. Use an online "file to base64" converter or certutil -encode (Windows) / base64 (Linux/macOS) on your font file to get the string.

Whichever option you pick, custom fonts must be licensed for embedding/redistribution if you plan to share or sell the resource.


File structure

Off-MapText/
├─ fxmanifest.lua
├─ config.lua          -- settings + Config.TestTexts
├─ test.lua            -- example loader
├─ MINIMAP_LOADER.gfx  -- required scaleform
└─ client/
   ├─ overlay.lua      -- DUI -> runtime texture -> scaleform overlay engine
   └─ client.lua       -- text API (exports), atlas bounds & projection
└─ html/
   ├─ text.html         -- DUI canvas page (shared atlas)
   └─ text.js           -- draws every text label, updated via SendDuiMessage

Notes & limitations

  • All labels share one atlas texture. Every label is drawn into a single DUI (one Chromium process total, regardless of label count) and displayed as one scaleform sprite. Sharpness depends on how much of the map the labels span: labels spread across the whole map get fewer pixels each than labels clustered in one district. Raise AtlasSize (e.g. 8192) if text looks blurry once zoomed in, at the cost of more VRAM.
  • Adding or removing a label redraws the whole atlas. Changes made in the same frame are batched into a single rebuild, so adding many labels at once is cheap. Avoid adding labels one-per-frame in a loop.
  • Labels are 2D. Only X/Y is used; there's no altitude/room separation.
  • No interaction/events. Off-MapText only draws; it does not detect hover or player proximity (see MapZones if you need that).

Credits

  • Author: OffSey

About

Put Text en Map

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages