> For the complete documentation index, see [llms.txt](https://lethium.gitbook.io/lethium-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lethium.gitbook.io/lethium-docs/server-setup/portals-npcs-holograms.md).

# Portals, NPCs and holograms

AdvancedPortals (world and best-zone portals), FancyNpcs (the hub NPCs) and FancyHolograms (signs and hub text).

Three plugins build the hub experience: **AdvancedPortals** moves players, **FancyNpcs** puts clickable characters in the hub, and **FancyHolograms** writes the floating text.

### AdvancedPortals

Files: `plugins/AdvancedPortals/config.yaml` and `portals/<name>.yaml`.

Nine portals exist:

| Portal             | Where                         | What it does                                                      |
| ------------------ | ----------------------------- | ----------------------------------------------------------------- |
| `bztp1` to `bztp5` | The hub of World 1 to World 5 | Runs `bestzone`: sends the player to their **best unlocked zone** |
| `world1_2`         | World 1                       | Runs `#spawn2 @player`                                            |
| `world2_3`         | World 2                       | Runs `#spawn3 @player`                                            |
| `world3_4`         | World 3                       | Runs `#spawn4 @player`                                            |
| `world4_5`         | World 4                       | Runs `#spawn5 @player`                                            |

The `#spawnN` commands are ClickEm's `/spawn2` to `/spawn5`. They **only work if the player has unlocked that world** (see [Navigation](/lethium-docs/gameplay/navigation.md)), so a locked world portal simply refuses.

```yaml
args:
  name: [bztp1]
  triggerblock: [END_PORTAL]
  command: [bestzone]
maxLoc: {posX: 630, posY: 126, posZ: 556, worldName: World1}
minLoc: {posX: 623, posY: 126, posZ: 548, worldName: World1}
```

| Key                | Meaning                                                                                          |
| ------------------ | ------------------------------------------------------------------------------------------------ |
| `triggerblock`     | The block the portal fills. `END_PORTAL`, `STRING`, `AIR`, `PAPER` and `TRIPWIRE_HOOK` are used. |
| `command`          | The command run when a player steps in. `#` runs it as the console with `@player` replaced.      |
| `minLoc`, `maxLoc` | The two corners.                                                                                 |

#### Create or change a portal

1. Get the **selector** (an iron axe: `selectorMaterial: IRON_AXE`, use `/portal selector`).
2. Left-click one corner and right-click the other.
3. `/portal create name:<name> triggerblock:END_PORTAL command:bestzone`.
4. `/portal remove <name>` deletes it. `/portal list` shows them.

Settings worth knowing in `config.yaml`: `joinCooldown: 5` (seconds after joining before portals work), `portalProtection: true` (blocks protected from breaking), `throwbackStrength: 0.7` (push back when refused), `warpMessageOnActionBar: true`, `commandPortals.console: true` (allows `#` console commands).

Portals are identical across worlds (only `worldName` differs), so to add a world, copy a portal file and change the world names.

### FancyNpcs

File: `plugins/FancyNpcs/npcs.yml`. Manage with `/npc`.

About **260 NPCs**, 52 per world. There are two kinds:

1. **Feature NPCs**: a character for each major feature (`events`, `pets`, `echoes`, `settings`, `artifacts`, `gift`, `navigation`, `quest`, `battlepass`, `clans`, `trade`, `killstreak`, `auctionhouse`, `dailylogin`, `gear`, `achievements`, `stats`, `skills`, `leaderboards`, `cosmetics`, `boosts`, `upgrades`, `tutorial`, `store`, `discord`). Clicking one **runs the matching command as the player**.
2. **`ClickEm<n>` NPCs**: players who look like **the viewer** (`mirrorSkin: true`). They run `/clickem`.

```yaml
name: pets
type: PLAYER
location: {world: World1, x: 687.5, y: 127.0, z: 533.5}
turnToPlayer: true
scale: 1.5
skin: {identifier: ..., variant: AUTO}
actions:
  ANY_CLICK:
    '1':
      action: player_command
      value: pets
```

| Key                                    | Meaning                                                             |
| -------------------------------------- | ------------------------------------------------------------------- |
| `turnToPlayer`, `turnToPlayerDistance` | The NPC looks at nearby players.                                    |
| `scale`                                | Size.                                                               |
| `skin.identifier`                      | The skin name. `mirrorSkin: true` copies the viewer's skin.         |
| `actions.ANY_CLICK`                    | What happens on click. `player_command` runs `value` as the player. |
| `visibility_distance`                  | How far away it is shown.                                           |
| `showInTab: false`                     | Keeps it off the tab list.                                          |

#### Common jobs

{% tabs %}
{% tab title="Change what an NPC does" %}
`/npc action <npc> any_click set 1 player_command <command>`, or edit `value` in `npcs.yml` with the server stopped.
{% endtab %}

{% tab title="Move an NPC" %}
Stand where you want it and run `/npc move <npc>`.
{% endtab %}

{% tab title="Add a feature NPC" %}
`/npc create <name>`, then `/npc skin <name> <skin>`, then set its click action as above. Give it a hologram (next section) linked with `linkedNpc`.
{% endtab %}

{% tab title="NPCs are missing for someone" %}
Check their render distance and that FancyNpcs loaded (`/npc list`). Bedrock players see the NPC with the normal skin.
{% endtab %}
{% endtabs %}

{% hint style="info" %}
A feature NPC is **per world**: the World 2 NPC is a separate entry from World 1's. To duplicate the hub to a new world, copy the world folder, then copy the NPC and hologram entries and change `world:`.
{% endhint %}

### FancyHolograms

Files: `plugins/FancyHolograms/holograms.yml` and `config.yml`. Manage with `/hologram`.

About 316 holograms. Each feature NPC has a **text hologram above it** named `npc_<feature>` (`npc_pets`, `npc_clans`, ...), and World 2 to 5 copies end in `_w2` to `_w5`. The rest mark places in the hub:

| Names                                                                                                                                             | What                                                                   |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| `welcome`, `welcome_w2` ...                                                                                                                       | The big "Welcome to" sign with the logo. `%player_name%` is filled in. |
| `bestzone_w1`, `startzone_w1`, `marketzone_w1`, `tutorialzone_w1`, `cratezone_w1`, `hubzone_w1`, `afkzone_w1`, `portaltp_w1` (and `_w2` to `_w5`) | Signs marking each hub area and portal.                                |
| `afkzone_info_w1` ...                                                                                                                             | How the AFK pool works.                                                |
| `npc_gemshop`, `npc_eggs`, `npc_abilities`                                                                                                        | The Gems Shop, eggs and abilities NPC signs.                           |

```yaml
npc_clans:
  type: TEXT
  location: {world: World1, x: 654.5, y: 130.18, z: 592.5}
  visibility_distance: 200
  scale_x: 1.5
  billboard: vertical
  linkedNpc: clans
  text:
    - '&#A6C9F0&lCLANS'
    - '&8[&#CCE0FF/clans&8]'
    - ''
    - '&#C2CCD1Rally your allies and'
    - '&8[&f%img_double_click%&8] &aClick to Access.'
  background: transparent
```

| Key                    | Meaning                                                                                                    |
| ---------------------- | ---------------------------------------------------------------------------------------------------------- |
| `type`                 | `TEXT`.                                                                                                    |
| `text`                 | The lines. `&#RRGGBB`, `&` codes and any PlaceholderAPI placeholder work.                                  |
| `billboard`            | `vertical` faces the player. `fixed` hangs in place.                                                       |
| `linkedNpc`            | The NPC it follows. Move the NPC and the text follows.                                                     |
| `visibility_distance`  | How far it is visible (200).                                                                               |
| `update_text_interval` | Milliseconds between placeholder refreshes, `-1` = never. Set a number if the text uses live placeholders. |
| `background`           | `transparent`, or a colour.                                                                                |

#### A live leaderboard hologram

```
/hologram create top_kills text
/hologram edit top_kills setline 1 &6Top Kills
/hologram edit top_kills addline &f1. %clickem_leaderboard_kills_1_name% &7- %clickem_leaderboard_kills_1_value%
```

Then set `update_text_interval` (for example `5000`) in `holograms.yml`, so the placeholders refresh. See [Leaderboards](/lethium-docs/gameplay/leaderboards.md).

{% hint style="warning" %}
Holograms are **per world and saved automatically** (`autosave` every 15 minutes, and on change). Do not edit `holograms.yml` while the server runs, or the plugin will overwrite your edit.
{% endhint %}


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://lethium.gitbook.io/lethium-docs/server-setup/portals-npcs-holograms.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
