# API Reference
Package root: `gg.lode.frameapi`. Artifact: `com.github.Lodestones:Frame-API:1.0.3`.
See [[Frame/Developers/Overview]] for how resolution works.
---
## `FrameAPI`
Static access point.
| Method | Returns |
|---|---|
| `FrameAPI.get()` | The live `IFrameAPI`, or `null` before Frame enables |
| `FrameAPI.isAvailable()` | Whether it is ready |
---
## `IFrameAPI`
### Providers
| Method | What it does |
|---|---|
| `register(Plugin, FrameProvider)` | Registers a provider; returns a `FrameRegistration` |
| `unregister(FrameProvider)` | Removes one |
| `unregisterAll(Plugin)` | Removes every provider a plugin registered |
| `registrations()` | Everything registered, highest priority first |
Providers are dropped automatically when their plugin disables, so keeping the registration is only needed for early removal.
### Layers
| Method | What it does |
|---|---|
| `createLayer(Plugin, String id, int priority)` | Creates and registers a `FrameLayer`. Calling twice with the same id returns the existing one. |
| `getLayer(Plugin, String id)` | An existing layer, or `null` |
### Refreshing
| Method | Scope |
|---|---|
| `refresh(Player)` | One viewer, every channel |
| `refresh(Player, FrameChannel)` | One viewer, one channel |
| `refreshAll()` | Everyone |
| `refreshTarget(Player)` | How one player appears to everyone |
Frame refreshes on its own ticker; these are for when you know something changed and don't want to wait.
### Reading resolved state
`resolvedHeader`, `resolvedFooter`, `resolvedEntry`, `resolvedNameTag`, `resolvedSidebar` — what a viewer currently resolves to. Useful for chat formatters that want to match the tablist. These resolve on demand rather than reading the last-sent value, so they reflect state as it is now.
### Control
| Method | Notes |
|---|---|
| `setChannelEnabled(FrameChannel, boolean)` | Until restart |
| `isChannelEnabled(FrameChannel)` | |
| `reload()` | Re-reads config; registered providers untouched |
| `version()` | |
---
## Provider interfaces
All extend `FrameProvider`, which supplies `priority()` and `appliesTo(Player viewer)`. One class may implement several.
| Interface | Method | Resolves as |
|---|---|---|
| `TablistProvider` | `header(viewer)`, `footer(viewer)`, `entry(viewer, target)` | Merged per field |
| `NametagProvider` | `style(viewer, target)` | Merged per field |
| `SidebarProvider` | `sidebar(viewer)` | Title merges; lines are all-or-nothing |
| `BossBarProvider` | `bossBars(viewer)` | **Additive** — every provider's bars show |
| `ActionBarProvider` | `actionBar(viewer)` | Highest non-null wins outright |
Everything takes the **viewer** — whose screen is being drawn. `entry` and `style` also take the **target**, the player being drawn on it. That pair is the whole point: the same target can look different on every screen.
---
## Value types
Each has all-nullable fields, a `builder()`, and merges independently. `null` on a field means "defer to the layer below".
### `TabEntry`
| Field | Meaning |
|---|---|
| `displayName` | Name shown in the list |
| `prefix` | Drawn immediately before the name |
| `suffix` | Drawn immediately after the name |
| `sortKey` | Sorted ascending; no key sorts last. Pad numbers so they compare as text — `010_` before `100_`. |
| `latency` | Ping in milliseconds |
| `skin` | `TabSkin` head override. Needs `tablist.allow-skin-override`. |
| `visible` | `false` hides the entry |
> [!tip] Prefer `prefix`/`suffix` over rewriting `displayName`
> They merge independently, so config contributing a rank prefix and your
> plugin contributing a suffix both land on the same entry. Setting
> `displayName` replaces the whole name, so whichever provider runs first
> loses its half. Set it only when you mean to replace the name itself.
### `NameTagStyle`
`prefix`, `suffix`, `color`, `visibility` (`NameVisibility`), `collision` (`CollisionRule`).
> [!note] Colour is limited to the sixteen named colours
> That is a vanilla scoreboard-team limit, not a Frame one. Put RGB in the prefix or suffix instead.
### `Sidebar`
`title` and `lines` (max 15). Title merges; lines are all-or-nothing — the highest-priority provider with a non-null list wins the whole list. Splicing lines across plugins was considered and deliberately rejected, because the result is a sidebar nobody can reason about.
`Sidebar.hidden()` actively removes the sidebar, beating anything below. `Sidebar.empty()` merely defers.
### `FrameBossBar`
`id`, `bar` (Adventure `BossBar`), `priority`. Return the same `id` across refreshes to update a bar in place — that is what stops a provider rebuilding its bar each tick from producing a flicker. Ids are namespaced per plugin.
---
## `FrameLayer`
A mutable provider you push into. Implements all five channel interfaces.
Setters come in pairs — one taking a viewer, one without. The per-viewer value beats the shared one **within that layer**; across layers, normal priority applies.
| Channel | Methods |
|---|---|
| Tablist | `setHeader`, `setFooter`, `setTabEntry`, `clearTabEntries` |
| Nametags | `setNameTag`, `clearNameTags` |
| Sidebar | `setSidebar` |
| Boss bars | `putBossBar`, `removeBossBar` |
| Action bar | `setActionBar` |
| Housekeeping | `clear(UUID)`, `clearAll()` |
```java
// Everyone sees Steve's rank colour...
layer.setTabEntry(steve, TabEntry.builder()
.displayName(text("[VIP] Steve", NamedTextColor.GREEN))
.build());
// ...except Alex, who has Steve ignored.
layer.setTabEntry(alex, steve, TabEntry.builder()
.displayName(text("Steve", NamedTextColor.DARK_GRAY))
.build());
```
Every setter schedules its own refresh. All are safe from any thread. Frame calls `clear` on quit for you.
---
## Not in the API
**Belowname** and the **playerlist objective** are config-only. Each is a single number per player with one shared title — there is no field to merge and nothing for a second plugin to contribute half of, so a provider interface would add surface without adding capability. Point the config placeholder at your own PlaceholderAPI expansion for dynamic values.
---
## Velocity
`Frame-Velocity` has its own smaller API in `gg.lode.frame.velocity.api` — `VelocityFrameAPI`, `VelocityTablistProvider`, `VelocityTabEntry`. Same shape, narrowed to what a proxy can draw. It shares no code with the Paper side, which it cannot: `Frame-API` depends on paper-api.
---
## Related
- [[Frame/Developers/Overview]]
- [[Frame/Server Owners/Configuration]]