> For the complete documentation index, see [llms.txt](https://jesus-gimenez.gitbook.io/xex-scripts/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jesus-gimenez.gitbook.io/xex-scripts/premium-mods/blips-menu.md).

# Blips Menu

<figure><img src="/files/xA2797NOMOQyQF4lL7jf" alt=""><figcaption></figcaption></figure>

***

## Table of Contents

1. [Overview](#overview)
2. [Features Summary](#features-summary)
3. [Installation](#installation)
4. [Configuration](#configuration)
   * [Framework Settings](#framework-settings)
   * [Language Settings](#language-settings)
   * [Access Control](#access-control)
   * [Default Blip Settings](#default-blip-settings)
   * [Discord Webhook](#discord-webhook)
5. [Database](#database)
6. [How It Works](#how-it-works)
   * [Flow](#flow)
   * [Blip Types](#blip-types)
   * [Blip Properties](#blip-properties)
   * [Job Whitelisting](#job-whitelisting)
7. [NUI Interface](#nui-interface)
   * [Main Menu](#main-menu)
   * [Customize Panel](#customize-panel)
   * [Sprite Selector](#sprite-selector)
   * [Create Dialog](#create-dialog)
8. [Admin vs Player Permissions](#admin-vs-player-permissions)
9. [Exports & Events](#exports--events)
   * [Server Callbacks](#server-callbacks)
   * [Server Events](#server-events)
   * [Client Events](#client-events)
   * [Client Commands](#client-commands)
   * [NUI Callbacks](#nui-callbacks)
   * [Server Exports](#server-exports)
10. [Localization](#localization)
11. [File Structure](#file-structure)
12. [Security](#security)
13. [Troubleshooting](#troubleshooting)
14. [Changelog](#changelog)
15. [Support](#support)

***

## Overview

XeX Blips Manager is a premium, full-featured blip management system for FiveM servers. It provides a modern glassmorphism NUI interface that allows admins to create public blips visible to all players, and regular players to create private blips visible only to themselves. Built with multi-framework support and optimized for performance.

### Supported Frameworks

| Framework  | Version | Status         |
| ---------- | ------- | -------------- |
| ESX Legacy | 1.6.0+  | ✅ Full Support |
| QBCore     | Latest  | ✅ Full Support |
| QBox       | Latest  | ✅ Full Support |

***

## Features Summary

### Core Features

| Category       | Feature              | Description                                                                                          |
| -------------- | -------------------- | ---------------------------------------------------------------------------------------------------- |
| **Blips**      | Public Blips         | Admins can create blips visible to all players                                                       |
| **Blips**      | Private Blips        | Regular players can create blips visible only to themselves                                          |
| **Blips**      | 3 Blip Types         | Normal markers, square area blips, and radius circle blips                                           |
| **UI**         | Glassmorphism Design | Modern dark translucent glass-effect interface                                                       |
| **UI**         | Tab System           | Filter by All / Public / Private with live badge counters                                            |
| **UI**         | Search               | Instant search by blip name with debounced input                                                     |
| **UI**         | Responsive           | Auto-fill card grid, min 150px per card                                                              |
| **Customizer** | Sprite Selector      | Visual grid with 500+ GTA blip sprites, searchable by ID                                             |
| **Customizer** | Color Grid           | 86 GTA blip colors with hex preview                                                                  |
| **Customizer** | Full Properties      | Scale, opacity, rotation, outline, tick, short range, display mode                                   |
| **Customizer** | Advanced Properties  | Flashes, heading indicator, cone, GPS route, category, priority, hide legend, high detail (ESX only) |
| **Customizer** | Dynamic Controls     | Controls show/hide based on blip type                                                                |
| **Management** | Move Blip            | Relocate a blip by clicking on map (ESX only)                                                        |
| **Management** | Duplicate Blip       | Clone a blip with offset coordinates (ESX only)                                                      |
| **Management** | Export Blips         | Export all blips as JSON file, admin only (ESX only)                                                 |
| **Management** | Import Blips         | Import blips from JSON file, admin only (ESX only)                                                   |
| **Management** | Corrupt Recovery     | Corrupt blip cards shown in red with delete option                                                   |
| **Access**     | Job Whitelisting     | Restrict public blips to specific jobs (comma-separated)                                             |
| **Access**     | Admin Roles          | Configurable admin roles for public blip management                                                  |
| **Access**     | Private Toggle       | Allow/deny non-admins from opening the menu                                                          |
| **System**     | Auto SQL Table       | Creates database table automatically on first start                                                  |
| **System**     | Discord Webhooks     | Logs blip creation, updates, and deletions                                                           |
| **System**     | Auto Updater         | Checks for new versions via GitHub Gist on startup                                                   |
| **System**     | Multi-Framework      | ESX, QBCore, QBox with per-framework logic                                                           |
| **I18n**       | 2 Languages          | English, Spanish                                                                                     |
| **Perf**       | Optimized            | Sleep-based loops, only active when map is open                                                      |

***

## Installation

### Requirements

* FiveM Server Build 5181+
* [oxmysql](https://github.com/overextended/oxmysql)
* [ox\_lib](https://github.com/overextended/ox_lib) (required for all frameworks)
* Framework: ESX Legacy, QBCore, or QBox

### Quick Start

{% stepper %}
{% step %}

### Place resource

Place `xex_blipsmenu` in your resources folder.
{% endstep %}

{% step %}

### Add to server.cfg

Add:

```cfg
ensure xex_blipsmenu
```

{% endstep %}

{% step %}

### Configure

Edit `config.lua` as needed.
{% endstep %}

{% step %}

### Restart server

Restart server — the database table is created automatically on first start.
{% endstep %}
{% endstepper %}

> Note: No manual SQL import is needed. The table `user_blips` is auto-created on resource start.

### Recommended Resource Order

```cfg
# server.cfg
ensure oxmysql
ensure ox_lib
ensure es_extended     # or qb-core / qbx_core
ensure xex_blipsmenu
```

***

## Configuration

### Framework Settings

```lua
Config.Framework = 'auto' -- 'auto' | 'esx' | 'qb' | 'qbox'
```

| Value    | Framework                                  |
| -------- | ------------------------------------------ |
| `'auto'` | Auto-detect: QBox → QBCore → ESX (default) |
| `'esx'`  | ESX Legacy                                 |
| `'qb'`   | QBCore                                     |
| `'qbox'` | QBox (qbx\_core)                           |

### Language Settings

```lua
Config.Language = 'en' -- 'en' | 'es'
```

| Code | Language          |
| ---- | ----------------- |
| `en` | English           |
| `es` | Spanish (Español) |

### Access Control

```lua
Config.AllowPrivateBlips = true       -- Allow non-admin players to open the menu (private blips only)
Config.AdminRoles = {'admin', 'mod'}  -- Roles that can create/manage public blips
```

| Option              | Default            | Description                                                                                                       |
| ------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------- |
| `AllowPrivateBlips` | `true`             | When `true`, all players can open the menu and create private blips. When `false`, only admins can open the menu. |
| `AdminRoles`        | `{'admin', 'mod'}` | Roles/permissions checked for public blip access                                                                  |

Admin detection per framework:

| Framework | Method                                                                  |
| --------- | ----------------------------------------------------------------------- |
| ESX       | `xPlayer.group` compared against `Config.AdminRoles`                    |
| QBCore    | `QBCore.Functions.HasPermission` + `IsPlayerAceAllowed(src, 'command')` |
| QBox      | `IsPlayerAceAllowed(src, role)` for each role in `AdminRoles`           |

### Default Blip Settings

```lua
Config.DefaultNewBlipName = 'New Blip'   -- Default name for newly created blips
Config.DefaultNewBlipSprite = 123        -- Default sprite ID (Ammunation icon)
```

### Keybind

```lua
Config.OpenMenuMapping = 'SPACE'  -- Key to open menu while big map is open
```

### Discord Webhook

```lua
Config.WebhookEnabled = false              -- Enable/disable Discord logging
Config.WebhookServerName = 'My Server'     -- Server name in embeds
Config.Webhook = ''                        -- Discord webhook URL
Config.DateFormat = '%d/%m/%Y [%X]'        -- Timestamp format
Config.IconUrl = 'https://i.imgur.com/w3JYiO0.png'  -- Embed thumbnail
Config.BotName = 'Blips BOT'               -- Bot display name
```

| Option              | Default                     | Description                         |
| ------------------- | --------------------------- | ----------------------------------- |
| `WebhookEnabled`    | `false`                     | Enable Discord webhook logging      |
| `WebhookServerName` | `'My Server'`               | Server name shown in embed footer   |
| `Webhook`           | `''`                        | Discord webhook URL                 |
| `DateFormat`        | `'%d/%m/%Y [%X]'`           | Lua `os.date` format for timestamps |
| `IconUrl`           | `'https://i.imgur.com/...'` | Thumbnail URL for webhook embeds    |
| `BotName`           | `'Blips BOT'`               | Bot display name for webhooks       |

Webhook Events:

| Action | Color              | Description        |
| ------ | ------------------ | ------------------ |
| Create | 🟢 Green (65352)   | New blip created   |
| Update | 🔵 Blue (13172480) | Blip data modified |
| Delete | 🔴 Red (16515843)  | Blip deleted       |

Each embed includes: Player server ID, License identifier, Discord mention, Action description, Timestamp.

### Auto Updater

```lua
Config.CheckForUpdates = true  -- Check for updates on resource start
```

***

## Database

### SQL Table (Auto-Created)

The `user_blips` table is automatically created on first resource start via `server/scrow.lua`. No manual import needed.

```sql
CREATE TABLE IF NOT EXISTS `user_blips` (
    `id` INT NOT NULL AUTO_INCREMENT,
    `identifier` VARCHAR(90) NOT NULL,
    `blipcoords` VARCHAR(120) NOT NULL,
    `blipdata` TEXT NOT NULL,
    `bliptype` VARCHAR(20) NOT NULL,
    `created` DATE DEFAULT (CURRENT_DATE),
    PRIMARY KEY (`id`),
    INDEX `idx_bliptype` (`bliptype`),
    INDEX `idx_identifier` (`identifier`)
);
```

| Column       | Type                | Description                          |
| ------------ | ------------------- | ------------------------------------ |
| `id`         | INT AUTO\_INCREMENT | Primary key                          |
| `identifier` | VARCHAR(90)         | Player identifier (license)          |
| `blipcoords` | VARCHAR(120)        | JSON string `{x, y, z}`              |
| `blipdata`   | TEXT                | JSON object with all blip properties |
| `bliptype`   | VARCHAR(20)         | `'public'` or `'private'`            |
| `created`    | DATE                | Auto-set to creation date            |

***

## How It Works

### Flow

{% stepper %}
{% step %}

### Resource Start

* `scrow.lua` auto-creates `user_blips` table
* Server loads all public blips into memory
* Updater checks for new versions
  {% endstep %}

{% step %}

### Player Join

* Client requests admin status (getMyRank / isAdmin)
* Client requests blip data (getStatus callback)
* Receives public blips + own private blips
* Renders all blips on GTA map
  {% endstep %}

{% step %}

### Opening Menu

* Player opens GTA big map (Pause menu → Map)
* Help notification shows "Press SPACE to open blips menu"
* Player presses SPACE → NUI menu opens
* Non-admins see Private blips only (Public button hidden)
* Admins see both Public and Private options
  {% endstep %}

{% step %}

### Creating a Blip

* Player clicks "Private" or "Public" button
* Dialog appears: "Enter Coordinates" or "Select on Map"
* Blip saved to database via server callback
* If public: broadcast to ALL clients via refreshPublicBlips
* If private: only visible to creator
  {% endstep %}

{% step %}

### Editing/Deleting

* Click blip card → Customize panel opens on left
* Modify properties and save
* Or click trash icon to delete
* Server validates ownership/admin permissions
  {% endstep %}
  {% endstepper %}

### Blip Types

| Type        | ID | Description                | GTA Native         |
| ----------- | -- | -------------------------- | ------------------ |
| Normal      | 1  | Standard map marker (pin)  | `AddBlipForCoord`  |
| Square Area | 2  | Rectangular area highlight | `AddBlipForArea`   |
| Circle      | 3  | Circular radius highlight  | `AddBlipForRadius` |

### Blip Properties

| Property        | Type   | Range    | Description                                   |
| --------------- | ------ | -------- | --------------------------------------------- |
| `title`         | string | —        | Display name (appears on map)                 |
| `sprite`        | int    | 0-500+   | GTA blip sprite ID                            |
| `colour`        | int    | 0-85     | GTA blip color index                          |
| `scale`         | string | 0-10     | Marker size (normal blips)                    |
| `alpha`         | int    | 0-255    | Transparency (0 = invisible, 255 = opaque)    |
| `display`       | int    | —        | GTA display mode                              |
| `tick`          | bool   | —        | Show tick mark on blip                        |
| `outline`       | bool   | —        | Show outline ring                             |
| `short`         | bool   | —        | Short range (disappears when zoomed out)      |
| `showon`        | int    | 2/3/5    | 2=Map & Minimap, 3=Map only, 5=Minimap only   |
| `whitelist`     | string | —        | Comma-separated job names (public blips only) |
| `type`          | int    | 1/2/3    | Blip type (Normal/Square/Circle)              |
| `w`             | int    | 0-1500   | Area/radius size (type 2 & 3 only)            |
| `h`             | int    | 0-1500   | Area height (type 2 only)                     |
| `rotation`      | int    | 0-90     | Rotation degrees (type 2 only)                |
| `flashes`       | bool   | —        | Blip flashes on/off (ESX only)                |
| `flashInterval` | int    | 100-2000 | Flash interval in ms (ESX only)               |
| `number`        | int    | 0-99     | Number displayed on blip (ESX only)           |
| `heading`       | bool   | —        | Show heading direction indicator (ESX only)   |
| `showCone`      | bool   | —        | Show vision cone on blip (ESX only)           |
| `category`      | int    | 1-10     | Blip category for map filtering (ESX only)    |
| `priority`      | int    | 0-10     | Blip render priority (ESX only)               |
| `hideLegend`    | bool   | —        | Hide from map legend (ESX only)               |
| `highDetail`    | bool   | —        | High detail rendering (ESX only)              |
| `gpsRoute`      | bool   | —        | Show GPS route line to blip (ESX only)        |
| `routeColour`   | int    | 0-29     | GPS route line color (ESX only)               |

### Job Whitelisting

Public blips can be restricted to specific jobs using the `whitelist` field:

```
police,ambulance,mechanic
```

* Players with matching jobs will see the blip
* Empty whitelist = visible to all
* Only applies to public blips
* Automatically re-evaluated when a player's job changes

***

## NUI Interface

### Main Menu

**Position:** Center screen, 52% width × 55% height

| Element       | Description                                                                                                                                     |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| Header        | Title bar with "Private" and "Public" create buttons. Public button hidden for non-admins.                                                      |
| Tabs          | All / Public / Private with live badge counters showing blip counts                                                                             |
| Search        | Instant filtering by blip name with 300ms debounce                                                                                              |
| Blip Cards    | Responsive grid (`auto-fill`, min 150px). Shows sprite preview, name, type badge. Hover reveals 4 action buttons: Duplicate, Move, Edit, Delete |
| Corrupt Cards | Blips with missing/invalid data show as red "Corrupt #ID" cards with a delete-only button                                                       |
| Admin Toolbar | Export and Import buttons shown to admins (ESX only)                                                                                            |
| Empty State   | Helpful icon and text when no blips match current filter                                                                                        |

### Customize Panel

**Position:** Left sidebar, 320px wide, max 70vh. Opens when clicking a blip card.

| Control           | Visibility          | Description                                              |
| ----------------- | ------------------- | -------------------------------------------------------- |
| Blip Type         | Always              | Selector: Normal / Square Area / Circle                  |
| Title             | Always              | Text input for blip name                                 |
| Whitelisted Jobs  | Public blips only   | Comma-separated job names                                |
| Sprite            | Normal only         | Visual preview + "Change" button to open sprite selector |
| Color             | Always              | 86-color GTA blip color grid with hex values             |
| Area Scale        | Area/Circle only    | Slider 0-1500                                            |
| Rotation          | Square Area only    | Slider 0-90°                                             |
| Scale             | Normal only         | Slider 0-10x                                             |
| Opacity           | Always              | Slider 0-255                                             |
| Outline           | Normal only         | Toggle Yes/No                                            |
| Tick              | Normal only         | Toggle Yes/No                                            |
| Short Range       | Normal only         | Toggle Yes/No                                            |
| Show On           | Normal only         | Map & Minimap / Map only / Minimap only                  |
| Flashes           | Normal only         | Toggle Yes/No (ESX only)                                 |
| Flash Interval    | Normal + Flashes=on | Slider in milliseconds (ESX only)                        |
| Number            | Normal only         | Slider 0-99 (ESX only)                                   |
| Heading Indicator | Normal only         | Toggle Yes/No (ESX only)                                 |
| Show Cone         | Normal only         | Toggle Yes/No (ESX only)                                 |
| Category          | Normal only         | Dropdown selector (ESX only)                             |
| Priority          | Normal only         | Slider (ESX only)                                        |
| Hide Legend       | Normal only         | Toggle Yes/No (ESX only)                                 |
| High Detail       | Normal only         | Toggle Yes/No (ESX only)                                 |
| GPS Route         | Normal only         | Toggle Yes/No (ESX only)                                 |
| Route Color       | Normal + GPS=on     | 30-color grid (ESX only)                                 |
| Height            | Square Area only    | Slider 0-1500 (ESX only)                                 |

### Sprite Selector

**Position:** Center overlay, 55% × 55%

* Grid of 500+ GTA blip sprite images (40×40px each)
* Search by sprite ID **or name** with debounced filtering
* **Category tab filtering:** Services, Shops, Vehicles, Properties, Entertainment, Basic, Other
* Images loaded from `nui/img/bliptypes/` folder
* Click sprite to select and return to customize panel

### Create Dialog

**Position:** Full-screen overlay modal

When creating a new blip, the player chooses:

| Option            | Description                                     |
| ----------------- | ----------------------------------------------- |
| Enter Coordinates | Manually type X and Y coordinates               |
| Select on Map     | Click directly on the GTA map to place the blip |

***

## Admin vs Player Permissions

| Action                      | Player                            | Admin    |
| --------------------------- | --------------------------------- | -------- |
| Open menu                   | ✅ (if `AllowPrivateBlips = true`) | ✅ Always |
| Create private blips        | ✅                                 | ✅        |
| Create public blips         | ❌                                 | ✅        |
| Edit own private blips      | ✅                                 | ✅        |
| Edit public blips           | ❌                                 | ✅        |
| Delete own private blips    | ✅                                 | ✅        |
| Delete public blips         | ❌                                 | ✅        |
| Set job whitelisting        | ❌                                 | ✅        |
| Move blip coordinates (ESX) | Own only                          | Any      |
| Duplicate blips (ESX)       | ✅ (own type)                      | ✅        |
| Export all blips (ESX)      | ❌                                 | ✅        |
| Import blips (ESX)          | ❌                                 | ✅        |

***

## Exports & Events

### Server Callbacks

#### ESX

| Callback                            | Parameters                   | Returns                                 | Description                                                 |
| ----------------------------------- | ---------------------------- | --------------------------------------- | ----------------------------------------------------------- |
| `xex_blipsmenu:saveNewBlip`         | `coords`, `blipType`, `data` | Blip object or `{public = publicBlips}` | Creates a new blip. Only admins can create `'public'` type. |
| `xex_blipsmenu:getStatus`           | —                            | `{public, private}`                     | Returns all public blips + player's private blips           |
| `xex_blipsmenu:getMyRank`           | —                            | `string` (e.g., `'admin'`)              | Returns the player's ESX group                              |
| `xex_blipsmenu:isPaid` (*not used*) | —                            | —                                       | Reserved                                                    |

#### QBCore

| Callback                    | Parameters                   | Returns             | Description                                       |
| --------------------------- | ---------------------------- | ------------------- | ------------------------------------------------- |
| `xex_blipsmenu:saveNewBlip` | `coords`, `blipType`, `data` | Blip object         | Creates a new blip with QB permission checks      |
| `xex_blipsmenu:getStatus`   | —                            | `{public, private}` | Returns all public blips + player's private blips |
| `xex_blipsmenu:isAdmin`     | —                            | `boolean`           | Checks `HasPermission` + ACE permissions          |

#### QBox

| Callback                    | Parameters                   | Returns             | Description                                           |
| --------------------------- | ---------------------------- | ------------------- | ----------------------------------------------------- |
| `xex_blipsmenu:saveNewBlip` | `coords`, `blipType`, `data` | Blip object         | Uses `lib.callback.register` and `MySQL.insert.await` |
| `xex_blipsmenu:getStatus`   | —                            | `{public, private}` | Uses `lib.callback.register` and `MySQL.query.await`  |
| `xex_blipsmenu:isAdmin`     | —                            | `boolean`           | Uses `IsPlayerAceAllowed` for each role               |

#### ESX (Additional)

| Callback                    | Parameters | Returns      | Description                                  |
| --------------------------- | ---------- | ------------ | -------------------------------------------- |
| `xex_blipsmenu:exportBlips` | —          | `blipsArray` | Returns all blips from database. Admin only. |

### Server Events

| Event                       | Parameters            | Description                                                            |
| --------------------------- | --------------------- | ---------------------------------------------------------------------- |
| `xex_blipsmenu:updateBlip`  | `blipId`, `data`      | Updates blip data. Validates ownership or admin status.                |
| `xex_blipsmenu:removeBlip`  | `blipId`              | Deletes a blip. Validates ownership or admin status.                   |
| `xex_blipsmenu:moveBlip`    | `blipId`, `newCoords` | Moves a blip to new coordinates. Validates ownership/admin. (ESX only) |
| `xex_blipsmenu:importBlips` | `blipsArray`          | Bulk imports blips from JSON array. Admin only. (ESX only)             |

### Client Events

| Event                                 | Data                    | Description                                                            |
| ------------------------------------- | ----------------------- | ---------------------------------------------------------------------- |
| `xex_blipsmenu:refreshPublicBlips`    | `{public = blipsArray}` | Received when public blips change. Re-renders all public blips on map. |
| `esx:setJob` (ESX only)               | job data                | Listens for job changes to re-render job-whitelisted blips             |
| `QBCore:Client:OnJobUpdate` (QB/QBox) | job data                | Same purpose for QB/QBox frameworks                                    |

### Client Commands

| Command         | Key Mapping      | Description                                                           |
| --------------- | ---------------- | --------------------------------------------------------------------- |
| `showblipsmenu` | Default: `SPACE` | Opens the Blips Manager NUI. Only works when the GTA big map is open. |

### NUI Callbacks

| Callback         | Data                                | Description                                                                             |
| ---------------- | ----------------------------------- | --------------------------------------------------------------------------------------- |
| `closeButton`    | —                                   | Closes NUI, releases cursor focus                                                       |
| `create`         | `{visibility: 'public'\|'private'}` | Enters create mode (player clicks map to place blip)                                    |
| `createByCoords` | `{visibility, coords}`              | Creates blip at manually entered X/Y coordinates                                        |
| `refreshBlip`    | blip data                           | Updates a blip's data locally and re-renders map blips                                  |
| `removeBlip`     | blip id                             | Removes blip locally and triggers server delete event                                   |
| `saveBlip`       | blip data                           | Saves blip changes and triggers server update event                                     |
| `duplicateBlip`  | blip data                           | Clones a blip with +50 offset to coordinates and " (copy)" suffix. ESX only             |
| `moveBlip`       | blip data                           | Enters move mode — player clicks on map to set new coordinates. ESX only                |
| `exportBlips`    | —                                   | Triggers server export callback, downloads JSON file via Blob URL. Admin only, ESX only |
| `importBlips`    | JSON array                          | Sends blip array to server for bulk import. Admin only, ESX only                        |

### Server Exports

| Export            | Description                                                 |
| ----------------- | ----------------------------------------------------------- |
| `CheckForUpdates` | Programmatically trigger update check from another resource |

### Console Commands

| Command            | Access              | Description                          |
| ------------------ | ------------------- | ------------------------------------ |
| `blipsmenu_update` | Server console only | Manually triggers the update checker |

***

## Localization

### Supported Languages

| Code | Language |
| ---- | -------- |
| `en` | English  |
| `es` | Español  |

### Locale Keys

```lua
Locales = {
    ['en'] = {
        ['blips_menu']              = 'Press SPACEBAR to open blips menu',
        ['open_blips_menu']         = 'Blips Menu',
        ['blip_created']            = 'A new blip has been created',
        ['blip_created_title']      = 'Blip Created',
        ['blip_updated']            = 'Blip has been updated',
        ['blip_updated_title']      = 'Blip Updated',
        ['blip_removed']            = 'A blip has been removed',
        ['blip_removed_title']      = 'Blip Removed',
        ['blip_moved']              = 'Blip has been moved',
        ['blip_moved_title']        = 'Blip Moved',
        ['move_hint']               = 'Click on the map to set new position',
        ['blip_duplicated']         = 'Blip has been duplicated',
        ['blip_duplicated_title']   = 'Blip Duplicated',
        ['export_success']          = 'Blips exported successfully',
        ['import_success']          = 'Blips imported successfully',
    },
}
```

### Adding Languages

{% stepper %}
{% step %}

### Add language block

Add a new language block in `locales.lua` with all keys.
{% endstep %}

{% step %}

### Configure language

Set `Config.Language` to your language code.
{% endstep %}
{% endstepper %}

***

## File Structure

```
xex_blipsmenu/
├── config.lua              # All configuration options
├── fxmanifest.lua          # Resource manifest
├── locales.lua             # EN/ES translations
├── readme.md               # Quick reference
├── DOCS.md                 # This documentation
├── client/
│   ├── esx.lua             # ESX client logic
│   ├── qb.lua              # QBCore client logic
│   ├── qbox.lua            # QBox client logic
│   └── scrow.lua           # Shared utility (isBigMapOpen)
├── server/
│   ├── esx.lua             # ESX server callbacks & webhooks
│   ├── qb.lua              # QBCore server callbacks
│   ├── qbox.lua            # QBox server callbacks
│   ├── scrow.lua           # Auto SQL table creation + cleanTargets
│   └── updater.lua         # Auto update checker
└── nui/
    ├── index.html           # Main UI structure
    ├── script.js            # UI controller & logic (jQuery)
    ├── styles.css           # Glassmorphism styling
    └── img/
        └── bliptypes/       # 500+ blip sprite PNG images
```

***

## Security

### Permission Validation

* **Create:** Only admins can create public blips. Server-side role check before insert.
* **Update:** Server validates that the requesting player owns the blip (private) or is an admin (public).
* **Delete:** Same ownership/admin validation as update.
* **Move:** Server validates ownership (private) or admin (public). ESX only.
* **Export/Import:** Server-side admin check before operation. ESX only.
* **NUI:** Public create button is hidden for non-admins in the UI, but also validated server-side.

### Identifier Handling

| Framework | Method                                                                 |
| --------- | ---------------------------------------------------------------------- |
| ESX       | `xPlayer.identifier`                                                   |
| QBCore    | `GetPlayerIdentifierByType(src, 'license')`                            |
| QBox      | `GetPlayerIdentifierByType(src, 'license2')` with `'license'` fallback |

***

## Troubleshooting

| Issue                           | Solution                                                                                             |
| ------------------------------- | ---------------------------------------------------------------------------------------------------- |
| Menu not opening                | Ensure you have the GTA **big map** open (not minimap). Press the configured key (default: `SPACE`). |
| "No blips" showing              | Check that the resource started without errors. Verify `oxmysql` is running.                         |
| Public blips not visible        | Verify the blip doesn't have a job whitelist that excludes your job.                                 |
| Private blips aren't saving     | Check `oxmysql` connection. Look for SQL errors in server console.                                   |
| Players can't open menu         | Set `Config.AllowPrivateBlips = true` to allow non-admins.                                           |
| Webhook not sending             | Set `Config.WebhookEnabled = true` and provide a valid `Config.Webhook` URL.                         |
| Blip not showing on map         | Check blip `alpha > 0`, `scale > 0`, and appropriate `showon` value.                                 |
| ox\_lib errors                  | Ensure `ox_lib` is started before `xex_blipsmenu` in server.cfg.                                     |
| Admin can't create public blips | Check `Config.AdminRoles` matches your admin group name.                                             |
| SQL table not created           | Check `oxmysql` is running and database connection is valid.                                         |

***

## Changelog

### v2.1.0

* Added QBox (qbx\_core) framework support
* Uses native QBox exports and `lib.callback` (ox\_lib) instead of deprecated QBCore bridge
* Admin detection via ACE permissions (`IsPlayerAceAllowed`)
* Player identification via `GetPlayerIdentifierByType` (license2 with license fallback)
* Notifications via `lib.notify` (ox\_lib)
* Loads ox\_lib internally via `pcall(load(LoadResourceFile(...)))` in QBox client/server files

### v2.0.0

* Complete UI rewrite with modern glassmorphism design
* Dynamic sprite and color grids (no more hardcoded HTML)
* Tab system with search and filtering
* Migrated from mysql-async to oxmysql
* All MySQL queries converted to async (no more `MySQL.Sync` blocking calls)
* Server-side permission validation on blip update/delete
* Auto-create SQL table on startup
* Dedicated update checker via GitHub Gist
* Debounced search inputs
* Fixed `removeBlipFromEntities` unsafe iteration bug
* Fixed QBCore job detection storing object instead of name
* Fixed `blipdata` column from `VARCHAR(230)` to `TEXT`
* Added database indexes for `bliptype` and `identifier`
* Removed obsolete `GetSharedObject` patterns
* Removed duplicate version checkers
* Removed hardcoded webhook URL from default config
* Fixed global `privateBlips` variable leak between player sessions

### v1.0.2

* Fix for non-export sharedObject on ESX

### v1.0.1

* Added support for ESX getSharedObject export

***

## Support

| Channel | Link                                                   |
| ------- | ------------------------------------------------------ |
| Discord | [discord.gg/9yY3Jxnhh8](https://discord.gg/9yY3Jxnhh8) |

***
