channel lines get their warm color, and a /wave gets its sentence

- a channel line renders in the channel family's color, not the grey notice row the client consults and throws away
- a text emote composes its sentence — gender and target picked from the game's own tables — so a /wave is a line in chat, not just an animation
- a FontString's `font=` resolves a font object by name and gates the whole block, `<Gradient>` tints the art it sits on, and buttons' state fonts read `font=` too — Bagnon's white boxes and bare stack counts are fixed
- the money frame sizes its coins from the digits themselves, so Bagnon's gold stops opening cramped

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Sam
2026-08-14 19:25:00 +07:00
co-authored by Claude Fable 5
parent a8718ad62c
commit a075a2ef44
23 changed files with 1495 additions and 129 deletions
+5
View File
@@ -24,6 +24,10 @@ pub(crate) struct Model {
pub(crate) addons: Vec<super::addon::AddOnInfo>,
/// The AddOns folder, so `LoadAddOn` can read an addon's files from inside a Lua binding.
pub(crate) addons_root: Option<std::path::PathBuf>,
/// NumberFontNormal's per-digit advances, `'0'..='9'` ([`super::UiScript::set_digit_advances`])
/// — the synchronous stand-in for a text measure, read by the `BenillaNumberWidth` binding.
/// `None` until the host feeds them, which is every VM without a font atlas (every engine test).
pub(crate) digit_advances: Option<[f32; 10]>,
/// Where per-addon saved variables live: the account-scoped folder, then this character's.
/// Both are directories holding one `<Addon>.lua` per declaring addon.
pub(crate) addons_saved_account: Option<std::path::PathBuf>,
@@ -1010,6 +1014,7 @@ impl Model {
Model {
addons: Vec::new(),
addons_root: None,
digit_advances: None,
addons_saved_account: None,
addons_saved_character: None,
framexml_templates: Default::default(),