Repository navigation
v1.0.0 – stable API, tabs, scroll panes, feeds and Bedrock
1.0: the API, the menu format and config.yml are now stable (see "Compatibility" in the
README). Before that promise some names were cleaned up; plugins built against 0.9 need these
changes, YAML menus and configs keep working (old keys are still read, with a hint in the log).
-
Renamed (API):
ListView.onSelect→onClick;Choice.onSelect,Checkbox.onToggleand
Tabs.onSelect→onChange;Button.textColorandCheckbox.textColor→color;
Grid.label/labelColor→text/color;Bar.color→fill;Tabs.tint→
inactiveTint;DisplayMode.SIMPLE→PLAIN(stored choices carry over). -
Changed (API):
visible,enabledandcheckedtake aPredicate<View>; sliders and form
numbers usedouble(Form.Values.numberreturns a double); form fields are the final classes
Form.TextField,CheckboxField,SliderField,ChoiceField;Label.DARKis gone, a label
without color (null, the default) uses the skin's text color;Click.openUrlaccepts only
http/https;Scene.Builder.build()rejects two lists, grids, tabs or scroll panes with the same id. -
New (API):
Click.page(listId, n),tab(tabsId, tabId)andscroll(scrollId, offset);
@NullMarkedpackage;@ApiStatus.Internalon renderer getters,@ApiStatus.Experimentalon
tabs, scroll panes, big heads, text styles, item tooltips, the own plain view andredrawAfter. -
Renamed (YAML): button
text-color→color, barcolor→fill, tabstint→
inactive-tint. Theinput:action now splits at|with spaces, likerequire:. -
Cooldowns need an
id(unique in the menu) or acooldown-key: before, an element without
them was keyed by its position, so adding an element moved cooldowns to other buttons. Stored is
when a key was last used; each element waits its own time from then (a key used with different
times is mentioned in the log). Running cooldowns of 0.9 start anew. -
Values from outside are text: feed and web entries,
%item_...%and%input%can no longer
add MiniMessage tags (colors, click events) or be filled in as another placeholder;|rawkeeps
the tags for a source you trust. Placeholders of a text are filled in one pass. -
Checks when loading menus: an unknown filter (
%x|dat%) or an invalid alias is an error;
frames the skin does not have, missing pictures,open:/give-item:targets without a menu
and a command used by two menus are hints, in the log and after/glyphwork reload. -
config.ymlcleaned up (config-version: 1):max-height→pack.min-height,
fallback→plain-dialog,icons/icon-source-pack→icons.enabled/
icons.source-pack,feeds.date-format→date-format; the pack prompt text lives only in the
language files (pack.prompt). Unknown or misspelled keys are reported. "Simple" is called
"plain" everywhere (/glyphwork display plain,/glyphwork test plain; the old words still work).
Edited language files:cmd.simple→cmd.plain,display.simple/display.info-simple→
display.plain/display.info-plain,fallback.*→plain.*(the log names old keys). -
Lists, grids, tabs and scroll panes without an
idget one that is unique in the whole menu;
before, the same element in several tabs shared its page. -
Own plain view:
plain:in a menu (APIScene.Builder.plain(...)) defines the dialog for
players without the pack and Bedrock players by hand, withcolumns: 1|2; same variables as the
pixel GUI. -
Grayed-out buttons in the plain dialog stay visible in gray; a click sends their tooltip
(e.g. the remaining cooldown) instead of doing nothing visible. -
Pack from your server or proxy:
pack.hosting: providedsends no pack; merge
plugins/Glyphwork/pack/glyphwork.zipinto the pack your server or proxy (Velocity) sends.
pack.provided-loaded: always(a required pack) orserver-pack(the server.properties answer)
tells Glyphwork who has it. -
Designer: a dashed area marks the room for the page buttons below lists and grids, with a hint
when another element is in the way. -
Plain dialog with pictures: players without the pack see item icons in front of button, list
and grid texts (sprite components the client draws from its own textures), and long button texts
switch the buttons to one wide column instead of cutting them (measured over all tabs, so the
layout stays when switching). Tabs become a clickable line above the buttons of the active tab
(on Bedrock: tab buttons and a divider). -
Bedrock players (Geyser, optionally Floodgate; found without a hard dependency) always get the
plain dialog, which Geyser turns into a Bedrock form, and no Java pack request; join menus open
at once for them. Their buttons show the first tooltip line below the text (forms have no
tooltips), and their forms close after a click until the server sends the next one, so a
quick second click can no longer hit a button of the previous screen and closing a menu closes
it (Geyser's waiting form could not be removed from the server). Timed redraws (cooldowns,
refresh, loading feeds) send a new form only when something visible changed, instead of closing
and reopening it every second (and at most one every 5 s). -
Text formatting: labels, buttons and list entries understand MiniMessage for parts of their
text (<b>,<i>,<u>,<st>, colors); labels also havebold,italic,underlineand
strikethroughfor the whole text. Bold counts 1 px per character when cutting, centering and
wrapping; underline and strikethrough are drawn as pixel-exact lines of their own. API:
markup(true)on Label, Button and ListView, plus the four switches on Label.|discordnow turns
Discord markdown into this formatting;|discord-plainkeeps the old plain text. -
Fix: a line break inside a value (chat messages, web data, PlaceholderAPI,
%input%) no
longer breaks the layout of the whole menu; single-line text shows it as a space. -
Clearer web errors: refused requests (401/403) say what to check, e.g. that Discord needs
Authorization: "Bot <token>", without showing the token. -
Placeholder filters:
|dateformats dates (ISO, RFC, Unix time) and|discordmakes Discord
markup readable (mentions, emojis, timestamps, markdown), for%item_...%,%menu_...%and
%web_...%. docs/menus.md shows a Discord channel as a web source. -
JSON web sources:
web:inconfig.yml(url,every, optional headers) and
%web_<name>_<path>%in any text (%web_status_players.online%, indexes andlengthfor arrays);
items-from: "web:<name>.<path>"turns a JSON array into list entries (%item_<key>%, nested keys
with dots). Loaded in the background with the same limits as feeds. -
Feeds:
items-from: "rss:https://..."fills lists and grids from an RSS or Atom feed (title,
text, date, link, author), loaded in the background, cached (feeds.cache,date-format
inconfig.yml), safe against external entities and limited to 1 MB / 50 entries. The menu
draws itself again when a feed arrives for the first time. -
Detail views:
%item_text%of a feed is the whole text with paragraphs (up to 4000
characters),%item_summary%the short one-line version;selected-ifon list and grid entries
highlights e.g. the clicked one (APIListView/Grid.selectedIf); a scroll paneidwith
placeholders keeps one position per content. Together: list on the left, article on the right. -
Action
url:shows a web address in a small native dialog with Open and Back
(url: %item_link%for feed entries); APIClick.openUrl. -
Scroll panes:
type: scroll/Scroll.of(...)shows part of its elements in a window with a
scroll bar (▲ / ▼ bysteppx, a click on the track jumps there) while the rest of the menu stays
in place. Only what fits completely is drawn and clickable; any element works inside. The plain
dialog lists all of them, the designer shows and scrolls the pane. -
Long menus: the pack height now follows the tallest YAML menu (rounded up to 32 px, at most
2048 px), so frames are drawn in menus of any height and the dialog scrolls them natively, mouse
wheel included.pack.min-heightis only the minimum (for scenes of plugins); small servers keep the
small pack. -
Tabs:
type: tabs/Tabs.of(...)puts tabs on top of a panel; the active tab merges with
the panel into one frame, the others sit slightly lower and darker behind it. Only the active
tab's elements are drawn and clickable, a click on another tab switches. Elements inside a tab are
placed relative to the panel and can be anything (templates,show-ifand cooldowns included);
varkeeps the active tab in a menu variable. The designer draws and switches tabs too. -
Action
add:counts:add: points 1,add: amount -1 min 1 max 64(amounts and limits may
be placeholders, decimals work) and redraws the menu likeset:. -
Saved variables:
persist: true(or a list of names) keeps menu variables in the player's
data, so they survive logouts and restarts;set: namewithout a value removes the saved value. -
Cooldowns:
cooldown: 1h(30s,5m,1d 12h…) on buttons, hitboxes, icons, panels,
pictures and heads: each player can use the element once per period, kept in the player's data.
A button on cooldown is grayed out with the remaining time as tooltip;cooldown-keyshares one
cooldown between elements; a failedrequiredoes not use it up. While a cooldown runs, the
open menu redraws itself when the shown time changes and when it ends (API:View.redrawAfter).
Texts:cooldown.tooltip/cooldown.waitin the language files, or per element
cooldown-tooltip/cooldown-messagewith%cooldown%. -
Menus that open by themselves:
open-on: { join: true }(orfirst) opens a menu when a
player joins, once the Glyphwork pack is loaded;open-on: { item: compass }(or with name,
lore, slot) hands out a menu item that opens it on right-click, cannot be dropped and comes back
after death (give: join|first|no,keep: true|false;/glyphwork item <menu> [player]and the
actiongive-item:hand it out on request).on-open/on-closeactions run when the menu opens (before drawing) and when the
player closes it; APIScene.Builder.onOpen/onClose. The designer has fields for all of it. -
Own dialog warning button:
dialog-warning.icon/icon-hoverinconfig.ymlreplace the
warning sign next to every dialog title with one of your pictures, and
dialog.warning-tooltipin the language files replaces its tooltip text (written into the pack
for every locale of that language). See docs/skin-format.md. -
Big heads:
type: head/Head.of(x, y, player).size(32)paints a player's face pixel by
pixel from the skin, 8 to 32 px, at any position, for any player without changing the pack;
head-sizeon lists and grids does the same for theirhead:icons. Skins load in the
background (Paper profile, Mojang lookup for other names) and are cached; until then the small
client head stands in and the menu redraws when the face arrives. -
Own pictures: PNGs in
plugins/Glyphwork/images/(folders too) go into the pack and are
placed withtype: image/Image.of(x, y, "logo"), pixel exact and at their own size; names
may use placeholders (ranks/%menu_rank%),tintmultiplies the colors. Pictures of any size
are cut into tiles of at most 128 x 128 px (the client cannot load bigger glyphs). Logos,
banners, rank badges and big player heads are all just pictures. The designer shows them once you
load the PNGs (or the folder) into it. -
Progress bars:
type: bar/Bar.of(...)fills pixel exact fromvalue/max
(placeholders work), in any color, 8 or 16 px high, with an optional text in the middle. The
plain dialog shows ten blocks plus the text. -
Item tooltips:
item-tooltip: trueon icons, lists and grids (APIitemTooltip(true))
shows the item's own vanilla tooltip when hovering; plugins can pass a fullItemStackwith
enchantments and lore. The example trader uses it. -
Text blocks: labels with
wrap: trueand awidthbreak into lines at spaces
(line-height, default 10);\nstarts a new line in any label. -
The menu designer knows all three.
-
Button text is centered on the width that is drawn (frames are whole tiles: a 22 px button is
16 px wide); before, it sat to the right.