Skip to main content

9AM TextUI overview

9AM TextUI is a free animated Text UI replacement for FiveM that supports both 3D world-space and screen-space rendering with smooth morphing animations. It automatically overrides ox_lib’s Text UI so all existing scripts use it without code changes.

Public features

  • 3D world prompts rendered at world coordinates with camera projection tracking
  • Classic screen-anchored overlay mode
  • Drop-in ox_lib override for lib.showTextUI / lib.hideTextUI
  • Sphere, box, and poly zone types via ox_lib
  • Distance-based animation that expands when near and collapses into a dot when far
  • Configurable accent color
  • Free and open source

Dependencies

  • ox_lib

Compatibility and editions

TypeDetails
CompatibilityStandalone
PriceFree

Config

-- config.lua
Config.PrimaryColor = '#f7e472'

Config.Zones = {
  {
    id = 'management-menu',
    text = 'Open Management',
    key = 'E',
    coords = vec3(-34.9118, -1102.1649, 26.4224),
    displayDist = 10.0,
    nearDist = 2.0,
    offset = vec3(0.0, 0.0, -0.6),
  },
}

Zone options

OptionTypeDefaultDescription
idstringUnique identifier (required)
textstringPrompt label
keystring""Key hint in the badge (e.g. 'E')
coordsvec3World position
displayDistnumber10.0Distance at which the prompt is visible
nearDistnumber2.0Distance at which the prompt expands
offsetvec3(0, 0, 1)Offset from coords for display anchor
typestring'sphere'Zone type: sphere, box, or poly
radiusnumberdisplayDistZone radius (sphere only)
sizevec3Zone dimensions (box only)
rotationnumberZone rotation (box only)
pointstableZone vertices (poly only)
thicknessnumberZone height (poly only)
debugbooleanfalseDraw debug zone outline

Exports

3D World TextUI

-- Create
exports['9am-textui']:createTextUI('shop-door', {
  text = 'Open Shop',
  key = 'E',
  coords = vec3(250.0, -850.0, 29.5),
  displayDist = 10.0,
  nearDist = 2.0,
})

-- Update (partial, only changed fields)
exports['9am-textui']:updateTextUI('shop-door', { text = 'Closed' })

-- Remove
exports['9am-textui']:removeTextUI('shop-door')

Screen Overlay TextUI

-- Show (key is parsed from [X] prefix)
exports['9am-textui']:showOverlayTextUI('[E] Open Menu')

-- Show at world coords
exports['9am-textui']:showOverlayTextUI('[E] Open Menu', {
  coords = vec3(100.0, 200.0, 30.0),
})

-- Hide
exports['9am-textui']:hideOverlayTextUI()

-- Check state
local isOpen = exports['9am-textui']:isOverlayTextUIOpen()

ox_lib override

The included override.lua replaces lib.showTextUI / lib.hideTextUI globally. Two ways to set it up: Option A — Add directly to ox_lib (recommended, applies to all resources automatically): Copy override.lua into ox_lib/imports/ (or any loaded path), then add it to ox_lib’s fxmanifest.lua:
files { '@9am-textui/override.lua' }
client_scripts { '@9am-textui/override.lua' }
Option B — Per resource: Add to the target resource’s fxmanifest.lua:
files { '@9am-textui/override.lua' }
client_scripts { '@9am-textui/override.lua' }
After either setup, these calls route through 9am-textui automatically:
lib.showTextUI('[E] Interact')
lib.hideTextUI()
lib.isTextUIOpen()

Advanced zone types

Box

exports['9am-textui']:createTextUI('garage', {
  text = 'Enter Garage',
  key = 'E',
  type = 'box',
  coords = vec3(200.0, -800.0, 30.0),
  size = vec3(10.0, 6.0, 4.0),
  rotation = 45.0,
  displayDist = 15.0,
})

Poly

exports['9am-textui']:createTextUI('park', {
  text = 'Rest Area',
  key = 'G',
  type = 'poly',
  points = {
    vec3(100.0, 200.0, 30.0),
    vec3(110.0, 200.0, 30.0),
    vec3(110.0, 210.0, 30.0),
    vec3(100.0, 210.0, 30.0),
  },
  thickness = 4.0,
  displayDist = 20.0,
})
Poly zones don’t require coords — defaults to the centroid of the points.

Example

CreateThread(function()
  exports['9am-textui']:createTextUI('atm_legion', {
    text = 'Use ATM',
    key = 'E',
    coords = vec3(149.0, -1040.0, 29.4),
    displayDist = 5.0,
    nearDist = 1.5,
    offset = vec3(0.0, 0.0, 0.5),
  })
end)

-- Dynamic update
RegisterNetEvent('bank:client:toggleATM', function(enabled)
  if enabled then
    exports['9am-textui']:updateTextUI('atm_legion', { text = 'Use ATM', key = 'E' })
  else
    exports['9am-textui']:updateTextUI('atm_legion', { text = 'Out of Service', key = '' })
  end
end)

-- Cleanup
AddEventHandler('onResourceStop', function(res)
  if res == GetCurrentResourceName() then
    exports['9am-textui']:removeTextUI('atm_legion')
  end
end)

Best for

Choose this script if you want:
  • A visually polished Text UI with smooth animations at no cost
  • 3D world-space prompts that track camera projection
  • A seamless ox_lib Text UI replacement without changing existing code
Open TextUI in the store