Conditions

visible-if appears on boards, panels and individual buttons. It takes one condition.

visible-if:
  permission: example.staff

Condition kinds

permissionnode

True when the viewer holds the node.

visible-if:
  permission: example.warps.view
selectedpanel id

True when that panel currently has a selection for this viewer. The usual companion to selection: on a detail panel.

visible-if:
  selected: list
entry-attributename + equals

Compares an attribute on the selected entry. Attributes are plain strings, and the comparison ignores case.

visible-if:
  entry-attribute:
    name: donor
    equals: 'true'
session-statename + equals

Compares a value written by set-state or toggle-state on this viewer's session. A missing key compares as empty.

visible-if:
  session-state:
    name: tab
    equals: 'combat'
customid + arguments

Hand off to a ConditionEvaluator another plugin registered. Every key other than id is passed through as an argument.

visible-if:
  custom:
    id: example:in_region
    region: spawn

Combining them

all, any and not take conditions and nest freely.

visible-if:
  all:
    - permission: example.staff
    - not:
        permission: example.staff.hide_boards
    - any:
        - session-state:
            name: tab
            equals: "combat"
        - session-state:
            name: tab
            equals: "blocks"

not takes a single condition, not a list.

Empty all and any lists follow Java's aggregate semantics: an empty all passes and an empty any fails. Prefer an explicit condition so a later reader does not have to rely on that edge case.

Patterns worth stealing

A detail panel and its placeholder

Two panels at the same offset with mirrored conditions: one shows the selection, the other shows the hint when there is none.

detail:
  type: text
  selection: list
  visible-if:
    selected: list
  lines:
    - "<white><bold><entry:label>"

hint:
  type: text
  visible-if:
    not:
      selected: list
  lines:
    - "<gray><italic>Choose a warp to see where it goes."

A tab strip

toggle-state or set-state on the buttons, session-state on the panels. Nothing is stored server-side beyond the viewer's session, and two players can be on different tabs of the same board.

tabs:
  type: buttons
  buttons:
    - id: combat
      text: "<gray>Combat"
      clicks:
        left:
          - type: set-state
            key: tab
            value: combat

A donor-only note

Conditions on a button read the selected entry, so one button can appear only for the rows that warrant it.

- id: donor_note
  text: "<gold>✦ <gray>Supporter warp. <white>/donate<gray> for access."
  visible-if:
    entry-attribute:
      name: donor
      equals: "true"
clicks: {}

Test both sides

Conditions are evaluated per viewer, so validate with accounts that differ in the exact permission, selection or session state involved. /holopanels debug only describes the current viewer; output from an operator does not prove what a default player receives.