# 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]]