> For the complete documentation index, see [llms.txt](https://docs.lostdev.store/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.lostdev.store/territories/graffiti.md).

# Graffiti

Players can spray a tag on a wall while standing inside a territory. It's a way for a gang to mark turf they're fighting over — tags placed by an attacking faction give that faction a small, temporary boost to how fast they capture that specific territory, and a territory's owner can scrub tags off their own walls to fight back.

Everything below is configured in `config/graffiti.lua`. No other file needs to be touched for normal setup or tuning.

## Requirements

* `ox_lib` — already required by the rest of the resource.
* `ox_target` — **optional**. If it's running on your server, the cleaning option automatically uses it instead of the on-screen key prompt. Nothing to configure either way.

## How it works for players

{% stepper %}
{% step %}

## Start spraying

Run `/spray` (or bind a key to it — see `Config.Graffiti.keybind` below) while aiming roughly at a wall. A panel opens to type the tag and pick its font, color and size.
{% endstep %}

{% step %}

## Place the tag

Confirming moves to placement: the panel shrinks to a small on-screen hint, and the player walks/aims freely to find a spot. A live preview follows the crosshair on the actual wall, with a hint telling them why a spot doesn't work if it doesn't (too far, not flat, not a valid surface). Confirming plays a short spray animation and the tag is placed.
{% endstep %}

{% step %}

## Remove tags

A territory's owning faction can remove any tag inside their own territory — either by walking up to it and pressing a key, or via the ox\_target menu if installed. Anyone can also always remove their own tag, in any territory, regardless of who owns it.
{% endstep %}
{% endstepper %}

Only factions that are actually allowed to fight over a given territory (see the `allowedCapturers` setting on each zone in `config/territories.lua`) can tag it in the first place.

## Basic setup (`config/graffiti.lua`)

| Setting                  | What it does                                                                                                                                                                                                 |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `enabled`                | Master on/off switch for the whole feature.                                                                                                                                                                  |
| `command`                | Chat command that opens the spray menu (`/spray` by default).                                                                                                                                                |
| `keybind`                | Optional default keybind for that command. Left blank so no key is claimed automatically, players can still bind it themselves in FiveM's own Key Bindings menu, or you can set a default here (e.g. `'G'`). |
| `requireInsideTerritory` | Keep this `true` unless you want tags to be placeable anywhere, not just inside territories.                                                                                                                 |
| `maxTextLength`          | Longest tag a player can type.                                                                                                                                                                               |

## Requiring an item to spray

By default spraying is free. To require an item (e.g. a spray can) from your inventory:

```lua
item = {
    enabled = true,
    name = 'spray_can', -- must match an item in your inventory
},
```

This works automatically with your framework's inventory (ox\_inventory on qbx, the built-in inventory on QBCore, ESX's inventory) — no extra setup beyond making sure the item exists.

## Limits

```lua
limits = {
    playerCooldown = 300,               -- seconds between sprays, per player
    maxActivePerPlayer = 3,             -- a player's own oldest tag is removed past this
    maxActivePerTerritory = 15,         -- oldest tag in a territory (any gang) is removed past this
    maxActivePerFactionPerTerritory = 5,-- oldest tag from the same gang in the same territory is removed past this
    maxActiveOutsideTerritories = 30,   -- only used if requireInsideTerritory is false (see below)
},

lifetime = 6 * 3600, -- how long a tag stays up before disappearing on its own, in seconds
```

Tags don't need to be manually cleaned to free these limits up — once a tag expires or is removed (by its author or the territory owner), it stops counting immediately.

## Capture boost

```lua
captureBoost = {
    enabled = true,
    bonusPerTag = 0.08, -- +8% capture speed per active tag from the attacking gang
    maxBonus = 0.40,    -- capped at +40%, however many tags are up
},
```

Only ever speeds up a gang that's actively **attacking** a territory, it never helps a gang defend a territory it already owns. Set `enabled = false` to make graffiti purely cosmetic.

## Word filter

```lua
blacklist = {}, -- e.g. { 'someword', 'anotherword' }
```

Case-insensitive list of words that can't be sprayed. Empty by default, add whatever your server needs filtered.

## Fonts and the `stream/` folder

The available fonts are listed in `Config.Graffiti.fonts`, and the custom ones (marked `custom = true`) are streamed from the `stream/` folder as `.gfx` files.

To swap a font for your own:

{% stepper %}
{% step %}

## Replace the font file

Replace the matching `.gfx` file in `stream/` (keep the same filename, e.g. `graffiti1.gfx`, or update the `font` value below to match your new filename).
{% endstep %}

{% step %}

## Update allowed characters

Adjust `allowed` so it matches the characters your replacement font actually has — see below.
{% endstep %}

{% step %}

## Adjust font size

Adjust `sizeMult` if the new font renders noticeably bigger or smaller than the others at the same size setting.
{% endstep %}
{% endstepper %}

The built-in game fonts (`PricedownGTAVInt`, `Chalet-LondonNineteenSixty`) don't need a `.gfx` file and should be left without `custom = true`.

### What `allowed` actually does

`allowed` is checked one character at a time against whatever the player typed: any character that doesn't match gets silently dropped before the tag is placed. This matters because a character your font has no picture (glyph) for renders in-game as an empty square — `allowed` is what keeps that from happening, by stripping anything the font can't draw before it ever reaches the wall. If `forceUppercase` is also set, the text is uppercased first, then filtered.

It's written as one of Lua's built-in character-class shortcuts, optionally wrapped in `[ ]` to combine several of them:

| Pattern                | Matches                                                                   |
| ---------------------- | ------------------------------------------------------------------------- |
| `%u`                   | uppercase letters only (`A`-`Z`)                                          |
| `%a`                   | any letter, upper or lower case                                           |
| `%d`                   | digits (`0`-`9`)                                                          |
| `%w`                   | letters and digits (no symbols/spaces)                                    |
| `%-`, `%.`, `%%`, etc. | a literal symbol — symbols need this `%` in front to be matched literally |

For example:

* `allowed = '%u'` with `forceUppercase = true` → only capital letters make it through; numbers and everything else are dropped. Used for a font that only drew capital letters.
* `allowed = '[%u%d%-%.]'` with `forceUppercase = true` → capital letters, digits, hyphens and periods. Used for a font that also included those two symbols.
* `allowed = '[%w%-%.%$%+%*/=%%\'"#@&%(%);:,<>!_~]'` (no `forceUppercase`) → letters, digits, and a long list of symbols, case preserved. Used for a font that drew nearly every printable character.

If you swap in a font that, say, only has letters and numbers (nothing else), you'd set it to `allowed = '%w'` with no `forceUppercase`. If a symbol shows up as a square in-game, the font doesn't have that glyph — either remove it from `allowed` (it'll just get dropped from what players type) or pick a font that includes it.

## Cleaning

```lua
clean = {
    enabled = true,
    range = 2.0, -- meters, how close a player needs to be to remove a tag
    key = 38,    -- E, used when ox_target isn't installed
},
```

## Map blips

```lua
blips = {
    enabled = true,
    sprite = 1, -- swap for a different blip sprite ID if you'd like
    scale = 0.6,
},
```

Shows a territory's tags as map blips, colored by the tagging gang's own color, while a player is standing inside that territory — mainly so the owner can see what needs cleaning without having to walk the whole zone.

## Visual tuning

* `forwardOffset` — how far the tag sits off the wall. If a tag ever looks like it's flickering or has a dark plate behind it, try increasing this slightly.
* `maxRayDistance` / `minSurfaceTiltDegrees` — how far a player can spray from, and how close to vertical a surface needs to be to count as a "wall" rather than a floor/ceiling.
* `forbiddenMaterials` — surface types that can never be sprayed on (glass, water, foliage, vehicles, ...). Add or remove entries by their in-game material name.
* `drawMode` — `'solid'` (default, exact colors) or `'additive'` (glows, and very dark colors become invisible). Only change this if tags consistently show a dark background behind them.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.lostdev.store/territories/graffiti.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
