From 8dade8c4b2ce04986a7c10ca00d59e0202d2e884 Mon Sep 17 00:00:00 2001
From: Jon Kazama
Date: Wed, 20 May 2026 08:57:33 +0200
Subject: [PATCH 01/10] feat(themes): add ThemeAbgrCacheLerp pure-helper for
crossfade
Per-slot ABGR byte-lerp between two cache value-records, stack-allocated
output, t clamped. Pattern anchor: imgui.cpp ImAlphaBlendColors.
---
HellionChat/Themes/ThemeAbgrCacheLerp.cs | 61 ++++++++++++++++++++++++
1 file changed, 61 insertions(+)
create mode 100644 HellionChat/Themes/ThemeAbgrCacheLerp.cs
diff --git a/HellionChat/Themes/ThemeAbgrCacheLerp.cs b/HellionChat/Themes/ThemeAbgrCacheLerp.cs
new file mode 100644
index 0000000..e2e750d
--- /dev/null
+++ b/HellionChat/Themes/ThemeAbgrCacheLerp.cs
@@ -0,0 +1,61 @@
+namespace HellionChat.Themes;
+
+// Per-slot ABGR byte-lerp between two ThemeAbgrCache value-records.
+// Pattern anchor: imgui.cpp:2820-2828 ImAlphaBlendColors -- decompose
+// each byte, lerp via Math.Round, recompose. Stack-allocated output
+// (readonly record struct), no heap pressure inside the crossfade
+// window. t is clamped to [0, 1] so float drift cannot overshoot.
+internal static class ThemeAbgrCacheLerp
+{
+ public static ThemeAbgrCache Lerp(ThemeAbgrCache from, ThemeAbgrCache to, float t)
+ {
+ t = Math.Clamp(t, 0f, 1f);
+
+ return new ThemeAbgrCache(
+ PrimaryDark: LerpAbgr(from.PrimaryDark, to.PrimaryDark, t),
+ Primary: LerpAbgr(from.Primary, to.Primary, t),
+ PrimaryLight: LerpAbgr(from.PrimaryLight, to.PrimaryLight, t),
+ PrimaryGlow: LerpAbgr(from.PrimaryGlow, to.PrimaryGlow, t),
+ AccentDark: LerpAbgr(from.AccentDark, to.AccentDark, t),
+ Accent: LerpAbgr(from.Accent, to.Accent, t),
+ AccentLight: LerpAbgr(from.AccentLight, to.AccentLight, t),
+ Identity: LerpAbgr(from.Identity, to.Identity, t),
+ WindowBg: LerpAbgr(from.WindowBg, to.WindowBg, t),
+ ChildBg: LerpAbgr(from.ChildBg, to.ChildBg, t),
+ FrameBg: LerpAbgr(from.FrameBg, to.FrameBg, t),
+ Surface: LerpAbgr(from.Surface, to.Surface, t),
+ SurfaceHover: LerpAbgr(from.SurfaceHover, to.SurfaceHover, t),
+ Border: LerpAbgr(from.Border, to.Border, t),
+ TextPrimary: LerpAbgr(from.TextPrimary, to.TextPrimary, t),
+ TextMuted: LerpAbgr(from.TextMuted, to.TextMuted, t),
+ TextDim: LerpAbgr(from.TextDim, to.TextDim, t),
+ StatusSuccess: LerpAbgr(from.StatusSuccess, to.StatusSuccess, t),
+ StatusDanger: LerpAbgr(from.StatusDanger, to.StatusDanger, t),
+ StatusWarning: LerpAbgr(from.StatusWarning, to.StatusWarning, t),
+ StatusInfo: LerpAbgr(from.StatusInfo, to.StatusInfo, t)
+ );
+ }
+
+ private static uint LerpAbgr(uint from, uint to, float t)
+ {
+ var ra = (byte)(from & 0xFFu);
+ var ga = (byte)((from >> 8) & 0xFFu);
+ var ba = (byte)((from >> 16) & 0xFFu);
+ var aa = (byte)((from >> 24) & 0xFFu);
+
+ var rb = (byte)(to & 0xFFu);
+ var gb = (byte)((to >> 8) & 0xFFu);
+ var bb = (byte)((to >> 16) & 0xFFu);
+ var ab = (byte)((to >> 24) & 0xFFu);
+
+ // Math.Round (default ToEven) matches ColourUtil.ApplyAlpha so a
+ // crossfade-into-hover transition does not produce a one-byte
+ // jump at the midpoint between the two paths.
+ var r = (byte)Math.Round(ra + (rb - ra) * t);
+ var g = (byte)Math.Round(ga + (gb - ga) * t);
+ var b = (byte)Math.Round(ba + (bb - ba) * t);
+ var a = (byte)Math.Round(aa + (ab - aa) * t);
+
+ return ((uint)a << 24) | ((uint)b << 16) | ((uint)g << 8) | r;
+ }
+}
From 74b07519f51f81a8575fdf2a46e0f57582ba7d93 Mon Sep 17 00:00:00 2001
From: Jon Kazama
Date: Wed, 20 May 2026 09:26:51 +0200
Subject: [PATCH 02/10] feat(themes): arm crossfade state in
ThemeRegistry.Switch
Three new private fields plus TryGetActiveCrossfade entry-point, plus
SwitchSilent variant for the plugin-load init path. ArmCrossfade
captures a value-copy of the active AbgrCache and stamps TickCount64;
mid-crossfade Switch composes the current lerped state as the next
fade origin so back-to-back theme switches stay smooth.
Same-slug Switch is a no-op (no identity-crossfade).
---
HellionChat/Themes/ThemeRegistry.cs | 95 +++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git a/HellionChat/Themes/ThemeRegistry.cs b/HellionChat/Themes/ThemeRegistry.cs
index c0e70b4..cbac2c1 100644
--- a/HellionChat/Themes/ThemeRegistry.cs
+++ b/HellionChat/Themes/ThemeRegistry.cs
@@ -32,6 +32,16 @@ public sealed class ThemeRegistry
private long _lastActiveStampCheckMs = -ActiveStampPollIntervalMs;
private DateTime _lastActiveStamp = DateTime.MinValue;
+ // PM-1 crossfade state. Switch() captures the previous AbgrCache as a
+ // VALUE-COPY (not a Theme reference) -- the built-in singletons share
+ // their RecomputeAbgrCache identity, so a reference would mutate
+ // alongside the new active. _crossfadeStartTickMs == long.MinValue
+ // means "no crossfade armed yet"; the field stays MinValue after
+ // SwitchSilent so the plugin-load init-path does not trigger a fade.
+ private ThemeAbgrCache? _previousAbgrSnapshot;
+ private long _crossfadeStartTickMs = long.MinValue;
+ private const int CrossfadeDurationMs = 300;
+
public ThemeRegistry(string? customThemesDir = null, ILogger? logger = null)
{
_logger = logger;
@@ -87,6 +97,13 @@ public sealed class ThemeRegistry
// a state where _active and Get(_active.Slug) disagree.
public void Switch(string slug)
{
+ // Same-slug switch is a no-op -- avoids a 300ms identity-crossfade
+ // when the user re-selects the active theme in the picker.
+ if (string.Equals(_active.Slug, slug, StringComparison.OrdinalIgnoreCase))
+ return;
+
+ ArmCrossfade();
+
if (_builtIns.TryGetValue(slug, out var builtin))
{
_active = builtin;
@@ -115,6 +132,84 @@ public sealed class ThemeRegistry
_activeCustomPath = null;
}
+ // SwitchSilent is the plugin-load init path -- identical to Switch
+ // but does NOT arm the crossfade state. Called from
+ // ThemeRegistryInitHostedService.StartAsync so opening the plugin
+ // does not produce a 300ms fade from the default theme to the user's
+ // saved theme.
+ public void SwitchSilent(string slug)
+ {
+ if (string.Equals(_active.Slug, slug, StringComparison.OrdinalIgnoreCase))
+ return;
+
+ if (_builtIns.TryGetValue(slug, out var builtin))
+ {
+ _active = builtin;
+ _active.RecomputeAbgrCache();
+ _activeCustomPath = null;
+ return;
+ }
+
+ var customTheme = LoadCustomBySlug(slug, out var customPath);
+ if (customTheme is not null)
+ {
+ _active = customTheme;
+ _active.RecomputeAbgrCache();
+ _activeCustomPath = customPath;
+ _lastActiveStamp = DateTime.MinValue;
+ return;
+ }
+
+ _active = _builtIns[DefaultSlug];
+ _active.RecomputeAbgrCache();
+ _activeCustomPath = null;
+ }
+
+ // Captures the AbgrCache snapshot that PushGlobal should fade FROM.
+ // If a crossfade is already mid-flight (second Switch within 300ms),
+ // the current lerped state replaces the snapshot -- the next fade
+ // starts from where we currently are, not from the original "from".
+ private void ArmCrossfade()
+ {
+ var now = Environment.TickCount64;
+ ThemeAbgrCache snapshot;
+ if (
+ _previousAbgrSnapshot.HasValue
+ && _crossfadeStartTickMs != long.MinValue
+ && now - _crossfadeStartTickMs < CrossfadeDurationMs
+ )
+ {
+ var t = (float)(now - _crossfadeStartTickMs) / CrossfadeDurationMs;
+ snapshot = ThemeAbgrCacheLerp.Lerp(_previousAbgrSnapshot.Value, _active.AbgrCache, t);
+ }
+ else
+ {
+ snapshot = _active.AbgrCache;
+ }
+
+ _previousAbgrSnapshot = snapshot;
+ _crossfadeStartTickMs = now;
+ }
+
+ // Returns the lerped AbgrCache while the crossfade is active.
+ // PushGlobal reads this once per frame; outside the 300ms window
+ // it short-circuits via the TickCount64 delta so the per-frame
+ // overhead is a couple of integer comparisons.
+ public bool TryGetActiveCrossfade(out ThemeAbgrCache lerped)
+ {
+ lerped = default;
+ if (_crossfadeStartTickMs == long.MinValue || !_previousAbgrSnapshot.HasValue)
+ return false;
+
+ var elapsed = Environment.TickCount64 - _crossfadeStartTickMs;
+ if (elapsed >= CrossfadeDurationMs)
+ return false;
+
+ var t = (float)elapsed / CrossfadeDurationMs;
+ lerped = ThemeAbgrCacheLerp.Lerp(_previousAbgrSnapshot.Value, _active.AbgrCache, t);
+ return true;
+ }
+
// 1Hz-throttled disk-stat on the currently active custom theme file.
// When the file's LastWriteTime moves forward (editor save), reload the
// theme via Get() so the user sees the edit immediately without
From a35067f80ac0808482a7a80bc464b5edda0d3991 Mon Sep 17 00:00:00 2001
From: Jon Kazama
Date: Wed, 20 May 2026 10:36:33 +0200
Subject: [PATCH 03/10] feat(ui): wire ThemeRegistry crossfade into PushGlobal
Switch picks a lerped AbgrCache during the 300ms crossfade window
(ReduceMotion bypass keeps the snap path). Plugin-load init path
switches to SwitchSilent so opening the plugin no longer fades from
the default theme. WindowBg/ChildBg RGBA path stays bound to the
user's per-window opacity override and never fades.
PushGlobal takes the ThemeRegistry as a parameter -- it is an instance
member on Plugin, not static, so the single Plugin.Draw call-site
threads it through alongside the active theme.
---
.../Hosting/InitHostedServices.cs | 2 +-
HellionChat/Plugin.cs | 1 +
HellionChat/Ui/HellionStyle.cs | 27 +++++++++++++++++--
3 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/HellionChat/Infrastructure/Hosting/InitHostedServices.cs b/HellionChat/Infrastructure/Hosting/InitHostedServices.cs
index 5d2a772..b7729f6 100644
--- a/HellionChat/Infrastructure/Hosting/InitHostedServices.cs
+++ b/HellionChat/Infrastructure/Hosting/InitHostedServices.cs
@@ -19,7 +19,7 @@ internal sealed class ThemeRegistryInitHostedService(ThemeRegistry registry) : I
// warm cache; otherwise the first Switch falls through to the built-in
// default when Config.Theme points at a custom slug.
foreach (var _ in registry.AllCustom()) { }
- registry.Switch(Plugin.Config.Theme);
+ registry.SwitchSilent(Plugin.Config.Theme);
return Task.CompletedTask;
}
diff --git a/HellionChat/Plugin.cs b/HellionChat/Plugin.cs
index 912bc7c..8ad1595 100755
--- a/HellionChat/Plugin.cs
+++ b/HellionChat/Plugin.cs
@@ -912,6 +912,7 @@ public sealed class Plugin : IAsyncDalamudPlugin
// Theme engine is always active; Classic is a theme, not a disabled state.
using IDisposable _style = HellionStyle.PushGlobal(
ThemeRegistry.Active,
+ ThemeRegistry,
Config.WindowOpacity
);
diff --git a/HellionChat/Ui/HellionStyle.cs b/HellionChat/Ui/HellionStyle.cs
index 96a6b7f..4e6481b 100644
--- a/HellionChat/Ui/HellionStyle.cs
+++ b/HellionChat/Ui/HellionStyle.cs
@@ -33,11 +33,34 @@ internal static class HellionStyle
// Global color and style stack pushed once per frame.
// windowOpacity: window background alpha (0.5-1.0).
- internal static IDisposable PushGlobal(Theme theme, float windowOpacity = 1.0f)
+ internal static IDisposable PushGlobal(
+ Theme theme,
+ ThemeRegistry registry,
+ float windowOpacity = 1.0f
+ )
{
var c = theme.Colors;
var l = theme.Layout;
- var a = theme.AbgrCache;
+
+ // Crossfade: PM-1 reads a lerped snapshot during the 300ms window
+ // following a Switch (TryGetActiveCrossfade returns false outside
+ // the window or while ReduceMotion is on). Only the ABGR-slot path
+ // crossfades -- WindowBg/ChildBg RGBA stays bound to the user's
+ // per-window opacity override and must not fade. See
+ // feedback_dalamud_pinning_override.
+ ThemeAbgrCache a;
+ if (
+ !Plugin.Config.ReduceMotion
+ && registry.TryGetActiveCrossfade(out var lerped)
+ )
+ {
+ a = lerped;
+ }
+ else
+ {
+ a = theme.AbgrCache;
+ }
+
var stack = new StackHandle();
var alphaByte = (uint)Math.Clamp((int)(windowOpacity * 255f), 0x55, 0xFF);
From a600f014eb458082d7d4712593b38993ff5660e2 Mon Sep 17 00:00:00 2001
From: Jon Kazama
Date: Wed, 20 May 2026 11:07:45 +0200
Subject: [PATCH 04/10] i18n: add quick-picker strings and reduce-motion
settings toggle
Five new keys across the EN source plus 24 locale variants (DE plus
23 AI-assisted, each carrying the pending-review marker): the header
quick-picker tooltip and two section headers, plus name and
description for a new ReduceMotion checkbox.
ReduceMotion was a config field with no UI -- the checkbox lands in
the Theme & Layout tab's window-style section. Designer.cs hand-edited
as a v1.5.4 block matching the v1.4.8 convention.
---
.../Resources/HellionStrings.Designer.cs | 7 +++++++
HellionChat/Resources/HellionStrings.ca.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.cs.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.da.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.de.resx | 15 ++++++++++++++
HellionChat/Resources/HellionStrings.el.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.es.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.fi.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.fr.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.hu.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.it.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.ja.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.ko.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.nb.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.nl.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.pl.resx | 20 +++++++++++++++++++
.../Resources/HellionStrings.pt-BR.resx | 20 +++++++++++++++++++
.../Resources/HellionStrings.pt-PT.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.resx | 15 ++++++++++++++
HellionChat/Resources/HellionStrings.ro.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.ru.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.sv.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.tr.resx | 20 +++++++++++++++++++
HellionChat/Resources/HellionStrings.uk.resx | 20 +++++++++++++++++++
.../Resources/HellionStrings.zh-Hans.resx | 20 +++++++++++++++++++
.../Resources/HellionStrings.zh-Hant.resx | 20 +++++++++++++++++++
HellionChat/Ui/SettingsTabs/ThemeAndLayout.cs | 14 +++++++++++++
27 files changed, 511 insertions(+)
diff --git a/HellionChat/Resources/HellionStrings.Designer.cs b/HellionChat/Resources/HellionStrings.Designer.cs
index 2e55fcf..d02a74c 100644
--- a/HellionChat/Resources/HellionStrings.Designer.cs
+++ b/HellionChat/Resources/HellionStrings.Designer.cs
@@ -444,4 +444,11 @@ internal class HellionStrings
internal static string DbViewer_FullTextToggle => Get(nameof(DbViewer_FullTextToggle));
internal static string DbViewer_FullTextToggle_Hint_Indexing => Get(nameof(DbViewer_FullTextToggle_Hint_Indexing));
internal static string DbViewer_FullTextToggle_Hint_PhraseMode => Get(nameof(DbViewer_FullTextToggle_Hint_PhraseMode));
+
+ // Hellion Chat — v1.5.4 header quick-picker + reduce-motion toggle
+ internal static string Settings_QuickPicker_Tooltip => Get(nameof(Settings_QuickPicker_Tooltip));
+ internal static string Settings_QuickPicker_Themes_Header => Get(nameof(Settings_QuickPicker_Themes_Header));
+ internal static string Settings_QuickPicker_Tabs_Header => Get(nameof(Settings_QuickPicker_Tabs_Header));
+ internal static string Settings_ThemeAndLayout_ReduceMotion_Name => Get(nameof(Settings_ThemeAndLayout_ReduceMotion_Name));
+ internal static string Settings_ThemeAndLayout_ReduceMotion_Description => Get(nameof(Settings_ThemeAndLayout_ReduceMotion_Description));
}
diff --git a/HellionChat/Resources/HellionStrings.ca.resx b/HellionChat/Resources/HellionStrings.ca.resx
index d5686c4..aa9c399 100644
--- a/HellionChat/Resources/HellionStrings.ca.resx
+++ b/HellionChat/Resources/HellionStrings.ca.resx
@@ -1034,4 +1034,24 @@
HellionChat mostra les 24 llengües, però l'entrada de xat de FFXIV només admet completament EN, DE, FR i JA. Altres alfabets poden mostrar-se com a caràcters incorrectes en escriure al xat del joc o en enviar missatges.
AI-assisted machine translation. Pending native-speaker review.
+
+ Selector ràpid de temes i pestanyes
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Temes
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Pestanyes
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Redueix el moviment
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Desactiva la transició de temes, les animacions en passar el cursor per la barra lateral i les targetes, i la pulsació de pestanyes no llegides. Els canvis de tema i els estats de cursor s'apliquen a l'instant.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.cs.resx b/HellionChat/Resources/HellionStrings.cs.resx
index 051bc00..d4bee19 100644
--- a/HellionChat/Resources/HellionStrings.cs.resx
+++ b/HellionChat/Resources/HellionStrings.cs.resx
@@ -1033,4 +1033,24 @@
HellionChat zobrazuje všech 24 jazyků, ale chatovací vstup FFXIV plně podporuje pouze EN, DE, FR a JA. Ostatní písma se mohou zobrazovat jako poškozené znaky při psaní do herního chatu nebo při odesílání zpráv.
+
+ Rychlý výběr motivů a karet
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Motivy
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Karty
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Omezit pohyb
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Vypne prolínání motivů, animace najetí myší na postranní panel a karty a pulzování nepřečtených karet. Změny motivu a stavy najetí myší se použijí okamžitě.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.da.resx b/HellionChat/Resources/HellionStrings.da.resx
index caeb66a..1a06a22 100644
--- a/HellionChat/Resources/HellionStrings.da.resx
+++ b/HellionChat/Resources/HellionStrings.da.resx
@@ -1033,4 +1033,24 @@
HellionChat viser alle 24 sprog, men FFXIV's chatinput understøtter kun EN, DE, FR og JA fuldt ud. Andre skrifter kan vises som forvrængede tegn, når de skrives i spillets chat eller sendes som beskeder.
+
+ Hurtigvælger til temaer og faner
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Temaer
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Faner
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Reducér bevægelse
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Deaktiverer temaovergangen, hover-animationer for sidepanel og kort samt pulseringen af ulæste faner. Temaskift og hover-tilstande anvendes i stedet med det samme.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.de.resx b/HellionChat/Resources/HellionStrings.de.resx
index 4e3ac22..10fd942 100644
--- a/HellionChat/Resources/HellionStrings.de.resx
+++ b/HellionChat/Resources/HellionStrings.de.resx
@@ -1033,4 +1033,19 @@
HellionChat zeigt alle 24 Sprachen, aber FFXIVs Chat-Eingabe unterstützt nur EN, DE, FR und JA vollständig. Andere Schriften können beim Tippen in den Spiel-Chat oder beim Senden von Nachrichten als unleserliche Zeichen erscheinen.
+
+ Schnellauswahl für Themes und Tabs
+
+
+ Themes
+
+
+ Tabs
+
+
+ Bewegung reduzieren
+
+
+ Deaktiviert die Theme-Überblendung, die Hover-Animationen von Seitenleiste und Karten sowie das Pulsieren ungelesener Tabs. Theme-Wechsel und Hover-Zustände greifen dann sofort.
+
diff --git a/HellionChat/Resources/HellionStrings.el.resx b/HellionChat/Resources/HellionStrings.el.resx
index 3d1c4ce..73dda04 100644
--- a/HellionChat/Resources/HellionStrings.el.resx
+++ b/HellionChat/Resources/HellionStrings.el.resx
@@ -1033,4 +1033,24 @@
Το HellionChat εμφανίζει και τις 24 γλώσσες, αλλά η εισαγωγή συνομιλίας του FFXIV υποστηρίζει πλήρως μόνο EN, DE, FR και JA. Άλλες γραφές ενδέχεται να εμφανίζονται ως αλλοιωμένοι χαρακτήρες όταν πληκτρολογούνται στη συνομιλία του παιχνιδιού ή αποστέλλονται ως μηνύματα.
+
+ Γρήγορη επιλογή θεμάτων και καρτελών
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Θέματα
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Καρτέλες
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Μείωση κίνησης
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Απενεργοποιεί τη σταδιακή εναλλαγή θεμάτων, τα εφέ αιώρησης στην πλαϊνή μπάρα και τις κάρτες, και την παλμική ένδειξη μη αναγνωσμένων καρτελών. Οι αλλαγές θέματος και οι καταστάσεις αιώρησης εφαρμόζονται άμεσα.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.es.resx b/HellionChat/Resources/HellionStrings.es.resx
index 45f116d..6cc79b6 100644
--- a/HellionChat/Resources/HellionStrings.es.resx
+++ b/HellionChat/Resources/HellionStrings.es.resx
@@ -1034,4 +1034,24 @@
HellionChat muestra los 24 idiomas, pero la entrada de chat de FFXIV solo admite completamente EN, DE, FR y JA. Otros alfabetos pueden mostrarse como caracteres ilegibles al escribir en el chat del juego o al enviar mensajes.
AI-assisted machine translation. Pending native-speaker review.
+
+ Selector rápido de temas y pestañas
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Temas
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Pestañas
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Reducir movimiento
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Desactiva la transición de temas, las animaciones al pasar el cursor por la barra lateral y las tarjetas, y el parpadeo de pestañas no leídas. Los cambios de tema y los estados del cursor se aplican al instante.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.fi.resx b/HellionChat/Resources/HellionStrings.fi.resx
index 57f152b..953a867 100644
--- a/HellionChat/Resources/HellionStrings.fi.resx
+++ b/HellionChat/Resources/HellionStrings.fi.resx
@@ -1033,4 +1033,24 @@
HellionChat näyttää kaikki 24 kieltä, mutta FFXIV:n chat-syöte tukee täysin vain EN, DE, FR ja JA. Muut kirjoitusjärjestelmät voivat näkyä virheellisinä merkkeinä, kun ne kirjoitetaan pelin chattiin tai lähetetään viesteinä.
+
+ Teemojen ja välilehtien pikavalitsin
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Teemat
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Välilehdet
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Vähennä liikettä
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Poistaa käytöstä teeman ristihäivytyksen, sivupalkin ja korttien osoitinanimaatiot sekä lukemattomien välilehtien sykkeen. Teeman vaihdot ja osoitintilat tulevat voimaan välittömästi.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.fr.resx b/HellionChat/Resources/HellionStrings.fr.resx
index 94a8a9a..e1231cb 100644
--- a/HellionChat/Resources/HellionStrings.fr.resx
+++ b/HellionChat/Resources/HellionStrings.fr.resx
@@ -1034,4 +1034,24 @@
HellionChat affiche les 24 langues, mais la saisie de chat de FFXIV ne prend en charge intégralement que EN, DE, FR et JA. Les autres scripts peuvent apparaître comme des caractères illisibles lors de la saisie dans le chat du jeu ou lors de l'envoi de messages.
AI-assisted machine translation. Pending native-speaker review.
+
+ Sélecteur rapide de thèmes et d'onglets
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Thèmes
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Onglets
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Réduire les animations
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Désactive le fondu enchaîné des thèmes, les animations de survol de la barre latérale et des cartes, ainsi que la pulsation des onglets non lus. Les changements de thème et les états de survol s'appliquent alors instantanément.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.hu.resx b/HellionChat/Resources/HellionStrings.hu.resx
index 261b572..3e13183 100644
--- a/HellionChat/Resources/HellionStrings.hu.resx
+++ b/HellionChat/Resources/HellionStrings.hu.resx
@@ -1033,4 +1033,24 @@
A HellionChat mind a 24 nyelvet megjeleníti, de a FFXIV csevegési bemenete csak az EN, DE, FR és JA nyelveket támogatja teljes mértékben. Más írásrendszerek torzított karakterekként jelenhetnek meg a játék csevegésébe írva vagy üzenetként elküldve.
+
+ Témák és lapok gyorsválasztója
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Témák
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Lapok
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Mozgás csökkentése
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Letiltja a témák áttűnését, az oldalsáv és a kártyák rámutatási animációit, valamint az olvasatlan lapok pulzálását. A témaváltások és a rámutatási állapotok ehelyett azonnal érvénybe lépnek.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.it.resx b/HellionChat/Resources/HellionStrings.it.resx
index 1bfd967..1bb8346 100644
--- a/HellionChat/Resources/HellionStrings.it.resx
+++ b/HellionChat/Resources/HellionStrings.it.resx
@@ -1034,4 +1034,24 @@
HellionChat mostra tutte le 24 lingue, ma l'input chat di FFXIV supporta completamente solo EN, DE, FR e JA. Altre scritture potrebbero apparire come caratteri illeggibili durante la digitazione nella chat di gioco o l'invio di messaggi.
AI-assisted machine translation. Pending native-speaker review.
+
+ Selettore rapido di temi e schede
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Temi
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Schede
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Riduci movimento
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Disattiva la dissolvenza dei temi, le animazioni al passaggio del mouse su barra laterale e schede e la pulsazione delle schede non lette. I cambi di tema e gli stati al passaggio del mouse vengono applicati immediatamente.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.ja.resx b/HellionChat/Resources/HellionStrings.ja.resx
index 6fbacc1..06527c9 100644
--- a/HellionChat/Resources/HellionStrings.ja.resx
+++ b/HellionChat/Resources/HellionStrings.ja.resx
@@ -1034,4 +1034,24 @@
HellionChat は 24 言語すべてを表示しますが、FFXIV のチャット入力が完全に対応しているのは EN、DE、FR、JA のみです。他のスクリプトはゲーム内チャットへの入力時やメッセージ送信時に文字化けする可能性があります。
AI-assisted machine translation. Pending native-speaker review.
+
+ テーマとタブのクイックピッカー
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ テーマ
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ タブ
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ モーションを減らす
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ テーマのクロスフェード、サイドバーとカードのホバーアニメーション、未読タブのパルスを無効にします。テーマの切り替えとホバー状態は即座に適用されます。
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.ko.resx b/HellionChat/Resources/HellionStrings.ko.resx
index f441aca..c71353f 100644
--- a/HellionChat/Resources/HellionStrings.ko.resx
+++ b/HellionChat/Resources/HellionStrings.ko.resx
@@ -1034,4 +1034,24 @@
HellionChat은 24개 언어 모두를 표시하지만, FFXIV의 채팅 입력은 EN, DE, FR, JA만 완전히 지원합니다. 다른 문자 체계는 게임 내 채팅에 입력하거나 메시지로 보낼 때 깨진 문자로 표시될 수 있습니다.
AI-assisted machine translation. Pending native-speaker review.
+
+ 테마 및 탭 빠른 선택기
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ 테마
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ 탭
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ 모션 줄이기
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ 테마 크로스페이드, 사이드바 및 카드 호버 애니메이션, 읽지 않은 탭의 펄스 효과를 비활성화합니다. 테마 전환과 호버 상태가 즉시 적용됩니다.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.nb.resx b/HellionChat/Resources/HellionStrings.nb.resx
index 171a7d2..9103a67 100644
--- a/HellionChat/Resources/HellionStrings.nb.resx
+++ b/HellionChat/Resources/HellionStrings.nb.resx
@@ -1033,4 +1033,24 @@
HellionChat viser alle 24 språk, men FFXIVs chat-innmating støtter bare EN, DE, FR og JA fullt ut. Andre skrifter kan vises som forvrengte tegn når de skrives i spillets chat eller sendes som meldinger.
+
+ Hurtigvelger for temaer og faner
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Temaer
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Faner
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Reduser bevegelse
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Deaktiverer temaovergangen, hover-animasjoner for sidepanel og kort samt pulseringen av uleste faner. Temabytter og hover-tilstander brukes i stedet umiddelbart.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.nl.resx b/HellionChat/Resources/HellionStrings.nl.resx
index 7ea7bac..d0ce217 100644
--- a/HellionChat/Resources/HellionStrings.nl.resx
+++ b/HellionChat/Resources/HellionStrings.nl.resx
@@ -1034,4 +1034,24 @@
HellionChat toont alle 24 talen, maar de chat-invoer van FFXIV ondersteunt alleen EN, DE, FR en JA volledig. Andere schriften kunnen als onleesbare tekens verschijnen wanneer ze in de in-game chat worden getypt of als berichten worden verzonden.
AI-assisted machine translation. Pending native-speaker review.
+
+ Snelkiezer voor thema's en tabbladen
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Thema's
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Tabbladen
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Beweging beperken
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Schakelt de themaovergang, de hover-animaties van de zijbalk en kaarten, en het pulseren van ongelezen tabbladen uit. Themawissels en hover-statussen worden in plaats daarvan direct toegepast.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.pl.resx b/HellionChat/Resources/HellionStrings.pl.resx
index 6f0a83c..7c4fb71 100644
--- a/HellionChat/Resources/HellionStrings.pl.resx
+++ b/HellionChat/Resources/HellionStrings.pl.resx
@@ -1033,4 +1033,24 @@
HellionChat wyświetla wszystkie 24 języki, ale wprowadzanie czatu FFXIV w pełni obsługuje tylko EN, DE, FR i JA. Inne systemy pisma mogą być wyświetlane jako zniekształcone znaki podczas wpisywania do czatu w grze lub wysyłania wiadomości.
+
+ Szybki wybór motywów i kart
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Motywy
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Karty
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Ogranicz ruch
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Wyłącza płynne przejścia motywów, animacje najechania kursorem na pasek boczny i karty oraz pulsowanie nieprzeczytanych kart. Zmiany motywu i stany najechania są wtedy stosowane natychmiast.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.pt-BR.resx b/HellionChat/Resources/HellionStrings.pt-BR.resx
index b9e7a6f..9dbefd7 100644
--- a/HellionChat/Resources/HellionStrings.pt-BR.resx
+++ b/HellionChat/Resources/HellionStrings.pt-BR.resx
@@ -1034,4 +1034,24 @@
O HellionChat exibe todos os 24 idiomas, mas a entrada de chat do FFXIV oferece suporte completo apenas para EN, DE, FR e JA. Outros alfabetos podem aparecer como caracteres ilegíveis ao digitar no chat do jogo ou enviar mensagens.
AI-assisted machine translation. Pending native-speaker review.
+
+ Seletor rápido de temas e abas
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Temas
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Abas
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Reduzir movimento
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Desativa a transição de temas, as animações de foco da barra lateral e dos cartões e a pulsação de abas não lidas. As trocas de tema e os estados de foco passam a ser aplicados instantaneamente.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.pt-PT.resx b/HellionChat/Resources/HellionStrings.pt-PT.resx
index debe45d..63d291f 100644
--- a/HellionChat/Resources/HellionStrings.pt-PT.resx
+++ b/HellionChat/Resources/HellionStrings.pt-PT.resx
@@ -1033,4 +1033,24 @@
O HellionChat apresenta os 24 idiomas, mas a entrada de chat do FFXIV apenas suporta totalmente EN, DE, FR e JA. Outros alfabetos podem aparecer como caracteres ilegíveis ao escrever no chat do jogo ou enviar mensagens.
+
+ Seletor rápido de temas e separadores
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Temas
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Separadores
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Reduzir movimento
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Desativa a transição de temas, as animações de passagem do rato sobre a barra lateral e os cartões e a pulsação de separadores não lidos. As mudanças de tema e os estados de passagem do rato passam a ser aplicados instantaneamente.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.resx b/HellionChat/Resources/HellionStrings.resx
index a38b367..25b64ef 100644
--- a/HellionChat/Resources/HellionStrings.resx
+++ b/HellionChat/Resources/HellionStrings.resx
@@ -1033,4 +1033,19 @@
HellionChat renders all 24 languages, but FFXIV's chat input only fully supports EN, DE, FR and JA. Other scripts may display as garbled characters when typed into the in-game chat or sent as messages.
+
+ Quick picker for themes and tabs
+
+
+ Themes
+
+
+ Tabs
+
+
+ Reduce motion
+
+
+ Disables the theme crossfade, the sidebar and card-row hover animations, and the unread-tab pulse. Theme switches and hover states apply instantly instead.
+
diff --git a/HellionChat/Resources/HellionStrings.ro.resx b/HellionChat/Resources/HellionStrings.ro.resx
index 41b2fcd..5334b42 100644
--- a/HellionChat/Resources/HellionStrings.ro.resx
+++ b/HellionChat/Resources/HellionStrings.ro.resx
@@ -1034,4 +1034,24 @@
HellionChat afișează toate cele 24 de limbi, dar intrarea chatului FFXIV acceptă complet doar EN, DE, FR și JA. Alte scrieri pot apărea ca caractere deteriorate când sunt tastate în chatul jocului sau trimise ca mesaje.
AI-assisted machine translation. Pending native-speaker review.
+
+ Selector rapid pentru teme și file
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Teme
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ File
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Reducere mișcare
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Dezactivează tranziția temelor, animațiile la trecerea cursorului peste bara laterală și carduri și pulsația filelor necitite. Schimbările de temă și stările de cursor se aplică instantaneu.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.ru.resx b/HellionChat/Resources/HellionStrings.ru.resx
index 3d9076d..edc1490 100644
--- a/HellionChat/Resources/HellionStrings.ru.resx
+++ b/HellionChat/Resources/HellionStrings.ru.resx
@@ -1034,4 +1034,24 @@
HellionChat отображает все 24 языка, но ввод чата FFXIV полностью поддерживает только EN, DE, FR и JA. Другие письменности могут отображаться как искажённые символы при наборе во внутриигровом чате или отправке сообщений.
AI-assisted machine translation. Pending native-speaker review.
+
+ Быстрый выбор тем и вкладок
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Темы
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Вкладки
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Уменьшить движение
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Отключает плавное переключение тем, анимации наведения для боковой панели и карточек, а также пульсацию непрочитанных вкладок. Смена темы и состояния наведения применяются мгновенно.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.sv.resx b/HellionChat/Resources/HellionStrings.sv.resx
index bcd31af..a5ff167 100644
--- a/HellionChat/Resources/HellionStrings.sv.resx
+++ b/HellionChat/Resources/HellionStrings.sv.resx
@@ -1034,4 +1034,24 @@
HellionChat visar alla 24 språk, men FFXIV:s chattinmatning stödjer endast EN, DE, FR och JA fullt ut. Andra skriftsystem kan visas som förvrängda tecken när de skrivs i spelets chatt eller skickas som meddelanden.
AI-assisted machine translation. Pending native-speaker review.
+
+ Snabbväljare för teman och flikar
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Teman
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Flikar
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Minska rörelse
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Inaktiverar temaövergången, hover-animationerna för sidofältet och korten samt pulseringen av olästa flikar. Temabyten och hover-tillstånd tillämpas i stället direkt.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.tr.resx b/HellionChat/Resources/HellionStrings.tr.resx
index 7cc710e..4dd56ee 100644
--- a/HellionChat/Resources/HellionStrings.tr.resx
+++ b/HellionChat/Resources/HellionStrings.tr.resx
@@ -1033,4 +1033,24 @@
HellionChat 24 dilin tümünü gösterir, ancak FFXIV'in sohbet girişi yalnızca EN, DE, FR ve JA dillerini tam olarak destekler. Diğer alfabeler, oyun içi sohbete yazıldığında veya mesaj olarak gönderildiğinde bozuk karakterler olarak görünebilir.
+
+ Temalar ve sekmeler için hızlı seçici
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Temalar
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Sekmeler
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Hareketi azalt
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Tema geçişini, kenar çubuğu ve kart vurgulama animasyonlarını ve okunmamış sekme nabzını devre dışı bırakır. Tema değişiklikleri ve vurgulama durumları bunun yerine anında uygulanır.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.uk.resx b/HellionChat/Resources/HellionStrings.uk.resx
index 8f6e762..2a677e4 100644
--- a/HellionChat/Resources/HellionStrings.uk.resx
+++ b/HellionChat/Resources/HellionStrings.uk.resx
@@ -1033,4 +1033,24 @@
HellionChat відображає всі 24 мови, але введення чату FFXIV повністю підтримує лише EN, DE, FR та JA. Інші писемності можуть відображатися як спотворені символи під час введення в ігровий чат або надсилання повідомлень.
+
+ Швидкий вибір тем і вкладок
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Теми
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Вкладки
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Зменшити рух
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ Вимикає плавне перемикання тем, анімації наведення для бічної панелі та карток, а також пульсацію непрочитаних вкладок. Зміна теми та стани наведення застосовуються миттєво.
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.zh-Hans.resx b/HellionChat/Resources/HellionStrings.zh-Hans.resx
index 5c8fc9a..998b8ee 100644
--- a/HellionChat/Resources/HellionStrings.zh-Hans.resx
+++ b/HellionChat/Resources/HellionStrings.zh-Hans.resx
@@ -1034,4 +1034,24 @@
HellionChat 显示全部 24 种语言,但 FFXIV 的聊天输入仅完全支持 EN、DE、FR 和 JA。其他文字在游戏内聊天输入或作为消息发送时可能显示为乱码。
AI-assisted machine translation. Pending native-speaker review.
+
+ 主题和标签页快速选择器
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ 主题
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ 标签页
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ 减少动态效果
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ 禁用主题交叉淡入淡出、侧边栏和卡片的悬停动画以及未读标签页的脉冲效果。主题切换和悬停状态将立即应用。
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Resources/HellionStrings.zh-Hant.resx b/HellionChat/Resources/HellionStrings.zh-Hant.resx
index b25e011..e0a8dff 100644
--- a/HellionChat/Resources/HellionStrings.zh-Hant.resx
+++ b/HellionChat/Resources/HellionStrings.zh-Hant.resx
@@ -1034,4 +1034,24 @@
HellionChat 顯示全部 24 種語言,但 FFXIV 的聊天輸入僅完全支援 EN、DE、FR 和 JA。其他文字在遊戲內聊天輸入或作為訊息傳送時可能顯示為亂碼。
AI-assisted machine translation. Pending native-speaker review.
+
+ 佈景主題與分頁快速選擇器
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ 佈景主題
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ 分頁
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ 減少動態效果
+ AI-assisted machine translation. Pending native-speaker review.
+
+
+ 停用佈景主題交叉淡入淡出、側邊欄與卡片的滑鼠停留動畫以及未讀分頁的脈衝效果。佈景主題切換與滑鼠停留狀態將立即套用。
+ AI-assisted machine translation. Pending native-speaker review.
+
diff --git a/HellionChat/Ui/SettingsTabs/ThemeAndLayout.cs b/HellionChat/Ui/SettingsTabs/ThemeAndLayout.cs
index 63f6707..ccc1e62 100644
--- a/HellionChat/Ui/SettingsTabs/ThemeAndLayout.cs
+++ b/HellionChat/Ui/SettingsTabs/ThemeAndLayout.cs
@@ -295,6 +295,20 @@ internal sealed class ThemeAndLayout : ISettingsTab
Mutable.WindowOpacity = opacityPercent / 100f;
}
ImGuiUtil.HelpMarker(HellionStrings.Settings_ThemeAndLayout_WindowOpacity_Description);
+
+ ImGui.Spacing();
+ ImGui.Separator();
+ ImGui.Spacing();
+
+ // Master accessibility toggle for the v1.5.4 motion work: the
+ // theme crossfade, the sidebar/card hover lerps and the
+ // unread-tab pulse all read Config.ReduceMotion and snap
+ // instantly when it is on.
+ ImGui.Checkbox(
+ HellionStrings.Settings_ThemeAndLayout_ReduceMotion_Name,
+ ref Mutable.ReduceMotion
+ );
+ ImGuiUtil.HelpMarker(HellionStrings.Settings_ThemeAndLayout_ReduceMotion_Description);
}
}
From 0237602ab7875298e437e2074b4ec6a3f183a0f6 Mon Sep 17 00:00:00 2001
From: Jon Kazama
Date: Wed, 20 May 2026 11:20:48 +0200
Subject: [PATCH 05/10] feat(util): add ColourUtil.ApplyAlpha for hover-lerp
modulation
Alpha-only modulator for ABGR colors -- RGB stays intact, factor
clamped to [0, 1]. Used by the v1.5.4 PM-3 hover-lerp path.
---
HellionChat/Util/ColourUtil.cs | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/HellionChat/Util/ColourUtil.cs b/HellionChat/Util/ColourUtil.cs
index 4b9fc9f..31b08c4 100755
--- a/HellionChat/Util/ColourUtil.cs
+++ b/HellionChat/Util/ColourUtil.cs
@@ -66,6 +66,18 @@ internal static class ColourUtil
return ((uint)a << 24) | ((uint)nb << 16) | ((uint)ng << 8) | nr;
}
+ // Modulates the alpha byte of an ABGR color by a factor in [0, 1].
+ // RGB stays intact. Used by the PM-3 hover-lerp path where each
+ // frame produces a fractional alpha value but the colour itself
+ // must not shift.
+ internal static uint ApplyAlpha(uint abgr, float alphaFactor)
+ {
+ alphaFactor = Math.Clamp(alphaFactor, 0f, 1f);
+ var origAlpha = (byte)((abgr >> 24) & 0xFFu);
+ var newAlpha = (byte)Math.Round(origAlpha * alphaFactor);
+ return (abgr & 0x00FFFFFFu) | ((uint)newAlpha << 24);
+ }
+
public static uint HexToRgba(string hex)
{
ArgumentNullException.ThrowIfNull(hex);
From 01a7f9b4ecfc502f4fac30f39422881c6e78e5d0 Mon Sep 17 00:00:00 2001
From: Jon Kazama
Date: Wed, 20 May 2026 12:48:31 +0200
Subject: [PATCH 06/10] feat(ui): add header quick-picker for themes and tabs
Palette button left of the cog opens a two-section popup. The themes
section enumerates AllBuiltIns + AllCustom; the tabs section
enumerates Config.Tabs. The active entry gets a leading check-glyph,
inactive rows a same-width blank so labels stay aligned. Click
selects without closing the popup (DontClosePopups).
Theme click triggers the PM-1 crossfade via ThemeRegistry.Switch;
tab click routes through ChangeTab so LastActivityTime stays
consistent with the sidebar and top-bar click paths.
The header input-width reservation now counts the new button plus
the per-button SameLine spacing -- the old formula dropped the
spacing term and overflowed the row once a third button appeared.
---
HellionChat/Ui/ChatLogWindow.cs | 124 +++++++++++++++++++++++++++++++-
1 file changed, 123 insertions(+), 1 deletion(-)
diff --git a/HellionChat/Ui/ChatLogWindow.cs b/HellionChat/Ui/ChatLogWindow.cs
index 7800315..30b5c10 100644
--- a/HellionChat/Ui/ChatLogWindow.cs
+++ b/HellionChat/Ui/ChatLogWindow.cs
@@ -472,6 +472,107 @@ public sealed class ChatLogWindow : Window
ChangeTab(newIndex);
}
+ // PM-2b v1.5.4 header quick-picker. Two scrollable sections -- every
+ // built-in plus custom theme, and every tab. Clicking a theme arms
+ // the PM-1 crossfade via ThemeRegistry.Switch; clicking a tab routes
+ // through ChangeTab so LastActivityTime stays consistent with the
+ // sidebar and top-bar click paths. DontClosePopups keeps the popup
+ // open so the user can hop between entries without re-opening it.
+ private void DrawQuickPickerPopup()
+ {
+ using var popup = ImRaii.Popup("##hellion-quick-picker");
+ if (!popup.Success)
+ return;
+
+ ImGui.TextUnformatted(HellionStrings.Settings_QuickPicker_Themes_Header);
+ ImGui.Separator();
+
+ var activeSlug = Plugin.ThemeRegistry.Active.Slug;
+ var allThemes = Plugin
+ .ThemeRegistry.AllBuiltIns()
+ .Concat(Plugin.ThemeRegistry.AllCustom())
+ .ToList();
+
+ using (
+ var scroll = ImRaii.Child(
+ "##hellion-quick-picker-themes",
+ new Vector2(220f, Math.Min(allThemes.Count * 22f, 200f))
+ )
+ )
+ {
+ if (scroll.Success)
+ {
+ foreach (var theme in allThemes)
+ {
+ var isActive = string.Equals(
+ theme.Slug,
+ activeSlug,
+ StringComparison.OrdinalIgnoreCase
+ );
+ DrawQuickPickerGlyph(isActive);
+ if (
+ ImGui.Selectable(
+ $"{theme.Name}##quick-theme-{theme.Slug}",
+ isActive,
+ ImGuiSelectableFlags.DontClosePopups
+ )
+ && !isActive
+ )
+ Plugin.ThemeRegistry.Switch(theme.Slug);
+ }
+ }
+ }
+
+ ImGui.Spacing();
+ ImGui.TextUnformatted(HellionStrings.Settings_QuickPicker_Tabs_Header);
+ ImGui.Separator();
+
+ var tabs = Plugin.Config.Tabs;
+ var activeTabIndex = Plugin.LastTab;
+ using (
+ var scroll = ImRaii.Child(
+ "##hellion-quick-picker-tabs",
+ new Vector2(220f, Math.Min(tabs.Count * 22f, 200f))
+ )
+ )
+ {
+ if (scroll.Success)
+ {
+ for (var i = 0; i < tabs.Count; i++)
+ {
+ var isActive = i == activeTabIndex;
+ DrawQuickPickerGlyph(isActive);
+ if (
+ ImGui.Selectable(
+ $"{tabs[i].Name}##quick-tab-{i}",
+ isActive,
+ ImGuiSelectableFlags.DontClosePopups
+ )
+ && !isActive
+ )
+ ChangeTab(i);
+ }
+ }
+ }
+ }
+
+ // Leading check-glyph slot for a quick-picker row. Active rows get a
+ // FontAwesome check; inactive rows get a same-width blank so the
+ // labels stay aligned. The glyph font push stays on its own line so
+ // it never bleeds into the body-font Selectable label.
+ private void DrawQuickPickerGlyph(bool isActive)
+ {
+ using (Plugin.FontManager.FontAwesome.Push())
+ {
+ var check = FontAwesomeIcon.Check.ToIconString();
+ if (isActive)
+ ImGui.TextUnformatted(check);
+ else
+ ImGui.Dummy(new Vector2(ImGui.CalcTextSize(check).X, ImGui.GetTextLineHeight()));
+ }
+ ImGui.SameLine();
+ }
+
private void TabSwitched(Tab newTab, Tab previousTab)
{
// Use the fixed channel if set by the user. Otherwise, if the new tab
@@ -903,7 +1004,15 @@ public sealed class ChatLogWindow : Window
var buttonWidth = afterIcon.X - beforeIcon.X;
var showNovice = Plugin.Config.ShowNoviceNetwork && GameFunctions.GameFunctions.IsMentor();
var buttonsRight = (showNovice ? 1 : 0) + (Plugin.Config.ShowHideButton ? 1 : 0);
- var inputWidth = ImGui.GetContentRegionAvail().X - buttonWidth * (1 + buttonsRight);
+ // Right-side buttons: quick-picker palette + cog (always present)
+ // plus the optional hide / novice buttons. Each slot costs the
+ // measured button width AND one ItemSpacing for the SameLine gap
+ // in front of it -- leaving the spacing term out overflows the
+ // header row by one gap per button (v1.5.4 quick-picker fix).
+ var rightButtonCount = 2 + buttonsRight;
+ var inputWidth =
+ ImGui.GetContentRegionAvail().X
+ - rightButtonCount * (buttonWidth + ImGui.GetStyle().ItemSpacing.X);
var normalColor = ImGui.GetColorU32(ImGuiCol.Text);
var push = inputColour != null;
@@ -1013,6 +1122,19 @@ public sealed class ChatLogWindow : Window
ImGui.SameLine();
+ if (
+ ImGuiUtil.IconButton(
+ FontAwesomeIcon.Palette,
+ tooltip: HellionStrings.Settings_QuickPicker_Tooltip,
+ width: (int)buttonWidth
+ )
+ )
+ ImGui.OpenPopup("##hellion-quick-picker");
+
+ DrawQuickPickerPopup();
+
+ ImGui.SameLine();
+
if (ImGuiUtil.IconButton(FontAwesomeIcon.Cog, width: (int)buttonWidth))
Plugin.SettingsWindow.Toggle();
From 0bfe3a62cbb7172bcd0b8395f112abc4ed55a76b Mon Sep 17 00:00:00 2001
From: Jon Kazama
Date: Wed, 20 May 2026 13:26:16 +0200
Subject: [PATCH 07/10] feat: add FrameLerp helper and per-tab hover-alpha
fields
FrameLerp.Smooth is the framerate-independent smoothing path -- a
Umbra-style v += (target - v) * factor with the factor clamped to 1
so a stalled frame snaps cleanly instead of overshooting. Tab gets
two NonSerialized fields (_hoverAlpha, _cardHoverAlpha) that the
v1.5.4 render loops drive.
---
HellionChat/Configuration.cs | 11 +++++++++++
HellionChat/Util/FrameLerp.cs | 17 +++++++++++++++++
2 files changed, 28 insertions(+)
create mode 100644 HellionChat/Util/FrameLerp.cs
diff --git a/HellionChat/Configuration.cs b/HellionChat/Configuration.cs
index ea925fa..e93adaa 100755
--- a/HellionChat/Configuration.cs
+++ b/HellionChat/Configuration.cs
@@ -485,6 +485,17 @@ public class Tab
[NonSerialized]
internal string? _cachedTellIcon;
+ // PM-3 hover-lerp state. Default 0f means "not hovered". Sidebar
+ // path animates per tab; card-mode-border path is tab-aggregate
+ // (any card-row hover ramps the alpha for all cards in this tab).
+ // Lerp speed lives in the render loop, not here, so the same field
+ // serves both sites at the same animation curve.
+ [NonSerialized]
+ internal float _hoverAlpha;
+
+ [NonSerialized]
+ internal float _cardHoverAlpha;
+
public bool Matches(Message message)
{
if (!message.Matches(SelectedChannels, ExtraChatAll, ExtraChatChannels))
diff --git a/HellionChat/Util/FrameLerp.cs b/HellionChat/Util/FrameLerp.cs
new file mode 100644
index 0000000..2593f6f
--- /dev/null
+++ b/HellionChat/Util/FrameLerp.cs
@@ -0,0 +1,17 @@
+namespace HellionChat.Util;
+
+// Framerate-independent smoothing for per-frame hover and motion
+// values. Pattern anchor: Umbra Toolbar.Autohide.cs:55
+// (`v += (target - v) * deltaTime`). The Math.Min(1f, speed*dt)
+// clamp is a deliberate HellionChat addition -- on Wine/DXVK a
+// stalled frame can push deltaTime well over 16ms, which would
+// otherwise let the raw factor exceed 1.0 and overshoot the target.
+// Clamping makes a stalled frame land exactly on target instead.
+internal static class FrameLerp
+{
+ public static float Smooth(float current, float target, float speed, float deltaTime)
+ {
+ var factor = Math.Min(1f, speed * deltaTime);
+ return current + (target - current) * factor;
+ }
+}
From 96ff4ddfd838540ddb62ee2be20e85b5912a51d6 Mon Sep 17 00:00:00 2001
From: Jon Kazama
Date: Wed, 20 May 2026 14:42:21 +0200
Subject: [PATCH 08/10] feat(ui): lerp sidebar-icon and card-mode-border hover
alphas
Sidebar icons ease from 40% to 100% alpha on hover-in via FrameLerp
plus ApplyAlpha. Card-mode borders aggregate row-hover per tab and
lift the border alpha by up to ~+0x70 across every row in that tab.
borderColorAbgr moves into the loop so the per-iteration boost can
apply. ReduceMotion snaps both paths instantly.
Card-hover detection uses IsMouseHoveringRect over the row bounds --
IsItemHovered would only see the 2px spacer dummy below each row.
---
HellionChat/Ui/ChatLogWindow.cs | 79 ++++++++++++++++++++++++++++++---
1 file changed, 72 insertions(+), 7 deletions(-)
diff --git a/HellionChat/Ui/ChatLogWindow.cs b/HellionChat/Ui/ChatLogWindow.cs
index 30b5c10..758b965 100644
--- a/HellionChat/Ui/ChatLogWindow.cs
+++ b/HellionChat/Ui/ChatLogWindow.cs
@@ -1627,15 +1627,19 @@ public sealed class ChatLogWindow : Window
var maxLines = Plugin.Config.MaxLinesToRender;
var startLine = messages.Count > maxLines ? messages.Count - maxLines : 0;
- // Card-mode pre-loop: theme/drawList/winLeft/winRight/border are invariant
- // per DrawMessages call; only cursorY moves per row.
+ // Card-mode pre-loop: theme/drawList/winLeft/winRight are
+ // invariant per DrawMessages call. borderColorAbgr used to be
+ // hoisted here too, but PM-3d (v1.5.4) modulates it by
+ // tab._cardHoverAlpha per row, so it moves into the AddLine
+ // call below. anyCardHovered aggregates the row-hover state
+ // across all card-rows; the lerp runs once at the loop end so
+ // the next frame paints with the updated alpha.
var theme = Plugin.ThemeRegistry.Active;
var drawList = ImGui.GetWindowDrawList();
var winLeft = ImGui.GetWindowPos().X;
var winRight = winLeft + ImGui.GetWindowSize().X;
- var borderColorAbgr = ColourUtil.RgbaToAbgr(
- (theme.Colors.Border & 0xFFFFFF00u) | 0x33u
- );
+ var baseBorderRgba = (theme.Colors.Border & 0xFFFFFF00u) | 0x33u;
+ var anyCardHovered = false;
for (var i = startLine; i < messages.Count; i++)
{
@@ -1791,6 +1795,8 @@ public sealed class ChatLogWindow : Window
var useCard = !Plugin.Config.UseCompactDensity;
if (useCard)
{
+ var rowStartY = ImGui.GetCursorScreenPos().Y;
+
if (message.Sender.Count > 0)
{
var senderColor =
@@ -1814,9 +1820,18 @@ public sealed class ChatLogWindow : Window
else
DrawChunks(message.Content, true, handler, lineWidth);
- // Border bottom as card separator. Alpha reduced to 0x33 for subtlety.
+ // Border bottom as card separator. Base alpha 0x33;
+ // PM-3d lifts it by up to ~+0x70 while any row in this
+ // tab is hovered. _cardHoverAlpha lerps at the loop
+ // end, so the one-frame lag is invisible at 10f speed.
{
var rowEndY = ImGui.GetCursorScreenPos().Y;
+ var hoverBoost = 0.45f * tab._cardHoverAlpha;
+ var alphaByte = (uint)
+ Math.Clamp((int)(0x33u + hoverBoost * 255f), 0x33, 0xCC);
+ var borderColorAbgr = ColourUtil.RgbaToAbgr(
+ (baseBorderRgba & 0xFFFFFF00u) | alphaByte
+ );
drawList.AddLine(
new Vector2(winLeft + 4, rowEndY - 1),
new Vector2(winRight - 4, rowEndY - 1),
@@ -1824,6 +1839,17 @@ public sealed class ChatLogWindow : Window
1f
);
ImGui.Dummy(new Vector2(0, 2));
+
+ // Whole-row hover test. IsItemHovered would only see
+ // the 2px Dummy above, so hit-test the row rect from
+ // its start Y down to the separator line instead.
+ if (
+ ImGui.IsMouseHoveringRect(
+ new Vector2(winLeft, rowStartY),
+ new Vector2(winRight, rowEndY)
+ )
+ )
+ anyCardHovered = true;
}
}
else
@@ -1848,6 +1874,20 @@ public sealed class ChatLogWindow : Window
message.IsVisible[tab.Identifier] = ImGui.IsItemVisible();
}
+
+ // PM-3d: update the per-tab card-hover lerp once per
+ // DrawMessages call. ReduceMotion snaps to the target;
+ // otherwise the border alpha eases toward it over a few
+ // frames the next time the rows paint.
+ var cardTarget = anyCardHovered ? 1f : 0f;
+ tab._cardHoverAlpha = Plugin.Config.ReduceMotion
+ ? cardTarget
+ : FrameLerp.Smooth(
+ tab._cardHoverAlpha,
+ cardTarget,
+ speed: 10f,
+ deltaTime: ImGui.GetIO().DeltaTime
+ );
}
catch (ApplicationException)
{
@@ -2098,7 +2138,19 @@ public sealed class ChatLogWindow : Window
ColourUtil.RgbaToAbgr(theme.Colors.Surface)
)
)
- using (ImRaii.PushColor(ImGuiCol.Text, ColourUtil.RgbaToAbgr(iconColor)))
+ // PM-3c: icon alpha eases from 40% (dim) to 100% on
+ // hover. _hoverAlpha lerps at the end of this block,
+ // so the colour for frame N uses frame N-1's value --
+ // a sub-frame lag that is invisible at 10f speed.
+ using (
+ ImRaii.PushColor(
+ ImGuiCol.Text,
+ ColourUtil.ApplyAlpha(
+ ColourUtil.RgbaToAbgr(iconColor),
+ 0.4f + 0.6f * tab._hoverAlpha
+ )
+ )
+ )
using (Plugin.FontManager.FontAwesome.Push())
{
// Button stretches with the configured sidebar width so a
@@ -2110,6 +2162,19 @@ public sealed class ChatLogWindow : Window
);
}
+ // PM-3c hover-lerp: ramp _hoverAlpha toward 1 while the
+ // icon button is hovered, back to 0 otherwise.
+ // ReduceMotion snaps so the dim/full states stay binary.
+ var hoverTarget = ImGui.IsItemHovered() ? 1f : 0f;
+ tab._hoverAlpha = Plugin.Config.ReduceMotion
+ ? hoverTarget
+ : FrameLerp.Smooth(
+ tab._hoverAlpha,
+ hoverTarget,
+ speed: 10f,
+ deltaTime: ImGui.GetIO().DeltaTime
+ );
+
if (isCurrentTab)
{
// Vertical accent pill on the left window edge, 3px wide, half tab height,
From a42cc2a97ed5b99d95583ce812fdcb91f9fce048 Mon Sep 17 00:00:00 2001
From: Jon Kazama
Date: Wed, 20 May 2026 16:21:29 +0200
Subject: [PATCH 09/10] test(selftest): pin v1.5.4 crossfade and quick-picker
contracts
ThemeCrossfadeSelfTestStep walks Switch -> crossfade-observed ->
mid-crossfade-switch -> crossfade-end -> restore using
TryGetActiveCrossfade, returns Waiting frame-by-frame and Pass after
the restore concludes. The mid-switch phase fires a second Switch
within ~100ms of the first observed crossfade and asserts the lerped
value is neither identity-from nor identity-to, exercising the
ArmCrossfade mid-flight-origin override.
QuickPickerSelfTestStep verifies the three new resource strings, the
built-in theme floor (>=10), and Config.Tabs non-empty.
---
HellionChat/Plugin.cs | 2 +
.../SelfTests/QuickPickerSelfTestStep.cs | 64 ++++++
.../SelfTests/ThemeCrossfadeSelfTestStep.cs | 216 ++++++++++++++++++
3 files changed, 282 insertions(+)
create mode 100644 HellionChat/SelfTests/QuickPickerSelfTestStep.cs
create mode 100644 HellionChat/SelfTests/ThemeCrossfadeSelfTestStep.cs
diff --git a/HellionChat/Plugin.cs b/HellionChat/Plugin.cs
index 8ad1595..fa37ccf 100755
--- a/HellionChat/Plugin.cs
+++ b/HellionChat/Plugin.cs
@@ -330,9 +330,11 @@ public sealed class Plugin : IAsyncDalamudPlugin
SelfTestRegistry.RegisterTestSteps([
new SelfTests.ThemeSwitchSelfTestStep(this),
+ new SelfTests.ThemeCrossfadeSelfTestStep(this),
new SelfTests.FontManagerCtorSmokeStep(this),
new SelfTests.FontPushSmokeStep(this),
new SelfTests.WizardStateSmokeStep(this),
+ new SelfTests.QuickPickerSelfTestStep(this),
]);
// Re-surface the wizard for existing users when a major UX
diff --git a/HellionChat/SelfTests/QuickPickerSelfTestStep.cs b/HellionChat/SelfTests/QuickPickerSelfTestStep.cs
new file mode 100644
index 0000000..ec0e537
--- /dev/null
+++ b/HellionChat/SelfTests/QuickPickerSelfTestStep.cs
@@ -0,0 +1,64 @@
+using Dalamud.Bindings.ImGui;
+using Dalamud.Plugin.SelfTest;
+using HellionChat.Resources;
+
+namespace HellionChat.SelfTests;
+
+// Verifies the v1.5.4 PM-2 quick-picker plumbing without rendering:
+// resource strings resolve, the theme registry yields the expected
+// minimum built-in count, and Config.Tabs is populated.
+internal sealed class QuickPickerSelfTestStep : ISelfTestStep
+{
+ private readonly Plugin plugin;
+
+ public QuickPickerSelfTestStep(Plugin plugin)
+ {
+ this.plugin = plugin;
+ }
+
+ public string Name => "Hellion Chat - Quick picker plumbing";
+
+ public SelfTestStepResult RunStep()
+ {
+ if (string.IsNullOrWhiteSpace(HellionStrings.Settings_QuickPicker_Tooltip))
+ {
+ ImGui.Text("Settings_QuickPicker_Tooltip is empty in the active locale.");
+ return SelfTestStepResult.Fail;
+ }
+ if (string.IsNullOrWhiteSpace(HellionStrings.Settings_QuickPicker_Themes_Header))
+ {
+ ImGui.Text("Settings_QuickPicker_Themes_Header is empty in the active locale.");
+ return SelfTestStepResult.Fail;
+ }
+ if (string.IsNullOrWhiteSpace(HellionStrings.Settings_QuickPicker_Tabs_Header))
+ {
+ ImGui.Text("Settings_QuickPicker_Tabs_Header is empty in the active locale.");
+ return SelfTestStepResult.Fail;
+ }
+
+ var registry = this.plugin.ThemeRegistry;
+ if (registry is null)
+ {
+ ImGui.Text("ThemeRegistry not resolved.");
+ return SelfTestStepResult.Fail;
+ }
+
+ var builtIns = registry.AllBuiltIns().ToList();
+ if (builtIns.Count < 10)
+ {
+ ImGui.Text($"Expected at least 10 built-in themes, found {builtIns.Count}.");
+ return SelfTestStepResult.Fail;
+ }
+
+ var tabs = Plugin.Config.Tabs;
+ if (tabs is null || tabs.Count == 0)
+ {
+ ImGui.Text("Config.Tabs is empty.");
+ return SelfTestStepResult.Fail;
+ }
+
+ return SelfTestStepResult.Pass;
+ }
+
+ public void CleanUp() { }
+}
diff --git a/HellionChat/SelfTests/ThemeCrossfadeSelfTestStep.cs b/HellionChat/SelfTests/ThemeCrossfadeSelfTestStep.cs
new file mode 100644
index 0000000..d1034a3
--- /dev/null
+++ b/HellionChat/SelfTests/ThemeCrossfadeSelfTestStep.cs
@@ -0,0 +1,216 @@
+using Dalamud.Bindings.ImGui;
+using Dalamud.Plugin.SelfTest;
+using HellionChat.Themes;
+
+namespace HellionChat.SelfTests;
+
+// Verifies the v1.5.4 PM-1 crossfade contract: switching the active
+// theme arms TryGetActiveCrossfade for ~300ms, then the registry
+// returns to direct AbgrCache reads. A second switch within 100ms
+// keeps the lerped path active (no identity-snap). CleanUp restores
+// the initial theme so /xlperf stays idempotent.
+internal sealed class ThemeCrossfadeSelfTestStep : ISelfTestStep
+{
+ private readonly Plugin plugin;
+
+ private string? initialSlug;
+ private string? targetSlug;
+ private string? midSwitchSlug;
+ private long armedAtTickMs = long.MinValue;
+ private long midArmedAtTickMs = long.MinValue;
+ private bool sawCrossfade;
+ private bool sawMidCrossfadeSwitch;
+ private bool sawCrossfadeEnd;
+ private bool restoredInitial;
+
+ public ThemeCrossfadeSelfTestStep(Plugin plugin)
+ {
+ this.plugin = plugin;
+ }
+
+ public string Name => "Hellion Chat - Theme crossfade";
+
+ public SelfTestStepResult RunStep()
+ {
+ var registry = this.plugin.ThemeRegistry;
+ if (registry is null)
+ return SelfTestStepResult.Fail;
+
+ if (this.initialSlug is null)
+ {
+ this.initialSlug = registry.Active.Slug;
+ this.targetSlug = PickDifferentSlug(registry, this.initialSlug);
+ if (this.targetSlug is null)
+ {
+ ImGui.Text("Need at least two themes available; only one built-in found.");
+ return SelfTestStepResult.Fail;
+ }
+
+ registry.Switch(this.targetSlug);
+ this.armedAtTickMs = Environment.TickCount64;
+ ImGui.Text($"Crossfade armed: {this.initialSlug} -> {this.targetSlug}");
+ return SelfTestStepResult.Waiting;
+ }
+
+ if (!this.sawCrossfade)
+ {
+ if (registry.TryGetActiveCrossfade(out _))
+ {
+ this.sawCrossfade = true;
+ this.midArmedAtTickMs = Environment.TickCount64;
+ ImGui.Text("Crossfade observed mid-window, arming mid-switch test...");
+ return SelfTestStepResult.Waiting;
+ }
+
+ // If the window already closed before we observed it, that
+ // is acceptable only on extremely slow frame paths; accept
+ // it as "saw the start" if more than 300ms have elapsed.
+ // Skip the mid-crossfade-switch phase in that case -- the
+ // lerped path is no longer active, so a second switch would
+ // re-arm a fresh crossfade and not exercise PM-1b's
+ // mid-flight-origin override.
+ if (Environment.TickCount64 - this.armedAtTickMs > 300)
+ {
+ this.sawCrossfade = true;
+ this.sawMidCrossfadeSwitch = true;
+ this.sawCrossfadeEnd = true;
+ ImGui.Text("Crossfade window closed before observation; accepting.");
+ return SelfTestStepResult.Waiting;
+ }
+
+ return SelfTestStepResult.Waiting;
+ }
+
+ if (!this.sawMidCrossfadeSwitch)
+ {
+ // PM-Test-3 mid-crossfade-switch phase: within ~100ms of the
+ // first observed crossfade, fire a second Switch to a THIRD
+ // theme. ArmCrossfade must compose the current lerped state
+ // as the new origin -- TryGetActiveCrossfade still returns
+ // true (lerped path stays active, no identity-snap) and the
+ // lerped value is neither the identity-from nor the
+ // identity-to of the new switch (origin shifted to the
+ // mid-flight cache, target is the third theme).
+ if (Environment.TickCount64 - this.midArmedAtTickMs < 100)
+ {
+ this.midSwitchSlug = PickDifferentSlug(
+ registry,
+ [this.initialSlug!, this.targetSlug!]
+ );
+ if (this.midSwitchSlug is null)
+ {
+ // Only two themes available -- mid-switch phase cannot
+ // exercise the lerped-origin path. Accept and move on
+ // (the v1.5.3 baseline ships >=10 built-ins, so this
+ // branch is defensive).
+ this.sawMidCrossfadeSwitch = true;
+ ImGui.Text("Only two themes available; skipping mid-switch assert.");
+ return SelfTestStepResult.Waiting;
+ }
+
+ var fromCache = registry.Active.AbgrCache;
+ registry.Switch(this.midSwitchSlug);
+ var toCache = registry.Active.AbgrCache;
+
+ if (!registry.TryGetActiveCrossfade(out var midLerped))
+ {
+ ImGui.Text("Mid-switch failed: TryGetActiveCrossfade returned false.");
+ return SelfTestStepResult.Fail;
+ }
+
+ // Lerped value must be neither the new identity-from
+ // (target cache of the first switch) nor the new
+ // identity-to (third theme cache) -- it must originate
+ // from the mid-flight composed snapshot.
+ if (midLerped.Equals(fromCache) || midLerped.Equals(toCache))
+ {
+ ImGui.Text("Mid-switch failed: lerped value is an identity snap.");
+ return SelfTestStepResult.Fail;
+ }
+
+ this.sawMidCrossfadeSwitch = true;
+ ImGui.Text(
+ $"Mid-switch armed: {this.targetSlug} -> {this.midSwitchSlug} (lerped origin)."
+ );
+ return SelfTestStepResult.Waiting;
+ }
+
+ // Window for mid-switch already elapsed; accept and continue.
+ this.sawMidCrossfadeSwitch = true;
+ ImGui.Text("Mid-switch window elapsed before fire; accepting.");
+ return SelfTestStepResult.Waiting;
+ }
+
+ if (!this.sawCrossfadeEnd)
+ {
+ if (!registry.TryGetActiveCrossfade(out _))
+ {
+ this.sawCrossfadeEnd = true;
+ ImGui.Text("Crossfade window closed cleanly.");
+ return SelfTestStepResult.Waiting;
+ }
+ return SelfTestStepResult.Waiting;
+ }
+
+ if (!this.restoredInitial)
+ {
+ registry.Switch(this.initialSlug);
+ this.restoredInitial = true;
+ ImGui.Text($"Restored: {this.initialSlug}");
+ return SelfTestStepResult.Waiting;
+ }
+
+ // Wait for the restore-crossfade to also conclude before
+ // declaring Pass, so /xlperf does not flicker out mid-fade.
+ if (registry.TryGetActiveCrossfade(out _))
+ return SelfTestStepResult.Waiting;
+
+ return SelfTestStepResult.Pass;
+ }
+
+ public void CleanUp()
+ {
+ // Best-effort: if anything went sideways, snap back to the
+ // initial slug. Switch is idempotent on same-slug.
+ var registry = this.plugin.ThemeRegistry;
+ if (registry is not null && this.initialSlug is not null)
+ {
+ registry.Switch(this.initialSlug);
+ }
+
+ this.initialSlug = null;
+ this.targetSlug = null;
+ this.midSwitchSlug = null;
+ this.armedAtTickMs = long.MinValue;
+ this.midArmedAtTickMs = long.MinValue;
+ this.sawCrossfade = false;
+ this.sawMidCrossfadeSwitch = false;
+ this.sawCrossfadeEnd = false;
+ this.restoredInitial = false;
+ }
+
+ private static string? PickDifferentSlug(ThemeRegistry registry, string activeSlug) =>
+ PickDifferentSlug(registry, [activeSlug]);
+
+ private static string? PickDifferentSlug(
+ ThemeRegistry registry,
+ IReadOnlyCollection excludeSlugs
+ )
+ {
+ foreach (var theme in registry.AllBuiltIns())
+ {
+ var match = false;
+ foreach (var excluded in excludeSlugs)
+ {
+ if (string.Equals(theme.Slug, excluded, StringComparison.OrdinalIgnoreCase))
+ {
+ match = true;
+ break;
+ }
+ }
+ if (!match)
+ return theme.Slug;
+ }
+ return null;
+ }
+}
From 57b6ead003ff76109fc9f4ecfef58acf57198866 Mon Sep 17 00:00:00 2001
From: Jon Kazama
Date: Wed, 20 May 2026 16:32:42 +0200
Subject: [PATCH 10/10] release(v1.5.4): manifest bump and forge post
Bumps csproj, yaml, repo.json, CHANGELOG, ROADMAP and README in
lock-step to 1.5.4. Forge-post DE-body added with the Polish & Motion
versionsnatur. Slim-rule applied to the yaml and repo.json changelog
blocks (keeps v1.5.4 + v1.5.3 + v1.5.2 + v1.5.1, drops v1.5.0).
A csharpier reflow of two v1.5.4 source files (ChatLogWindow,
HellionStyle) is folded in. preflight.sh blocks A-F all green.
---
.github/forge-posts/v1.5.4.md | 9 ++++
HellionChat/HellionChat.csproj | 2 +-
HellionChat/HellionChat.yaml | 86 +++++++++++++++------------------
HellionChat/Ui/ChatLogWindow.cs | 6 +--
HellionChat/Ui/HellionStyle.cs | 5 +-
README.md | 22 +++++++--
docs/CHANGELOG.md | 11 +++++
docs/ROADMAP.md | 12 +++++
repo.json | 14 +++---
9 files changed, 99 insertions(+), 68 deletions(-)
create mode 100644 .github/forge-posts/v1.5.4.md
diff --git a/.github/forge-posts/v1.5.4.md b/.github/forge-posts/v1.5.4.md
new file mode 100644
index 0000000..c6020fb
--- /dev/null
+++ b/.github/forge-posts/v1.5.4.md
@@ -0,0 +1,9 @@
+---
+subtitle: "Theme-Crossfade, Quick-Picker, Hover-Animationen"
+versionsnatur: "Polish & Motion"
+---
+- **Theme-Crossfade.** Theme-Wechsel blenden jetzt sanft über rund 300 ms ineinander, statt hart umzuschalten. Alle Hellion-Flächen gleiten mit: Sidebar, Titel, Buttons, Tabs, Scrollbar, Trennlinien. Der Fenster-Hintergrund snappt bewusst weiter, damit das Per-Window-Deckkraft-Setting aus Dalamuds Pinning-Menü unangetastet bleibt.
+- **Header-Quick-Picker.** Neuer Paletten-Button links vom Zahnrad im Chat-Header. Ein Klick öffnet ein kompaktes Popup mit zwei Sektionen: alle Built-in- und Custom-Themes sowie alle Tabs. Der aktive Eintrag trägt ein Häkchen, ein Klick wechselt ohne das Popup zu schließen. So lassen sich mehrere Wechsel hintereinander erledigen, ohne den Umweg über die Einstellungen.
+- **Sanfte Hover-Animationen.** Sidebar-Icons faden bei Hover sanft von gedimmt auf volle Deckkraft. Card-Mode-Trennlinien heben sich beim Überfahren einer Zeile für den ganzen Tab dezent ab. Beides framerate-unabhängig gerechnet, also auch bei Wine-Stall-Frames stabil.
+- **Bewegung reduzieren.** Neuer Toggle im Tab für Theme und Layout. Er deaktiviert Crossfade, Hover-Animationen und das Pulsieren ungelesener Tabs für alle, die eine statische Oberfläche bevorzugen.
+- Drei P3-Items plus der Accessibility-Toggle, kein Schema-Bump, keine Migration. Eine kleine Polish-Welle vor den größeren Cycles.
diff --git a/HellionChat/HellionChat.csproj b/HellionChat/HellionChat.csproj
index a2cf624..a9071a9 100644
--- a/HellionChat/HellionChat.csproj
+++ b/HellionChat/HellionChat.csproj
@@ -1,7 +1,7 @@
- 1.5.3
+ 1.5.4
enable
enable
diff --git a/HellionChat/HellionChat.yaml b/HellionChat/HellionChat.yaml
index c47b9ab..cf781c5 100755
--- a/HellionChat/HellionChat.yaml
+++ b/HellionChat/HellionChat.yaml
@@ -35,6 +35,44 @@ tags:
- Replacement
- Privacy
changelog: |-
+ **v1.5.4 — Polish and Motion (2026-05-20)**
+
+ A polish cycle: smoother theme switching, faster theme and tab
+ access, and subtle hover motion. Three P3 items plus an
+ accessibility toggle.
+
+ User-visible:
+
+ - Theme switches now crossfade smoothly over ~300 ms across every
+ Hellion-rendered surface — sidebar, title, buttons, tabs,
+ scrollbar, separators. The window background snaps deliberately
+ so the per-window opacity override from Dalamud's pinning menu
+ stays untouched.
+ - New header quick-picker: a palette button left of the cog opens
+ a compact popup with two sections — every built-in and custom
+ theme, and every tab. The active entry carries a check glyph;
+ clicking another switches without closing the popup.
+ - Sidebar icons ease their opacity on hover, and card-mode message
+ borders highlight per tab while the cursor is over their rows.
+ Framerate-independent, so a stalled Wine frame cannot overshoot
+ the animation.
+ - New "Reduce motion" toggle in Theme & Layout disables the
+ crossfade, the hover animations and the unread-tab pulse for
+ users who prefer a static UI.
+
+ Under the hood:
+
+ - Two pure-helper lerp paths (ThemeAbgrCacheLerp, FrameLerp) with
+ xUnit coverage in the Build Suite, plus a ColourUtil.ApplyAlpha
+ alpha modulator. Two new /xlperf self-test steps pin the
+ crossfade and quick-picker contracts.
+
+ No schema bump, no migration. Migration v17 stays.
+
+ Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
+
+ ---
+
**v1.5.3 — Localisation Wave + Bundled-Font Overhaul (2026-05-19)**
Multi-language pass plus a long-standing first-frame HITCH lands
@@ -194,52 +232,4 @@ changelog: |-
---
- **v1.5.0 — DI Foundation and Service Refactor (2026-05-17)**
-
- Major architecture cycle. The plugin bootstrap moves to a
- generic-host DI container (Microsoft.Extensions.Hosting +
- IServiceCollection) modelled on Lightless Sync. Service logging
- moves from a static Plugin.LogProxy locator to typed
- Microsoft.Extensions.Logging.ILogger via constructor injection,
- bridged over Dalamud's IPluginLog by a custom DalamudLogger trio.
-
- What changes under the hood:
-
- - 18 instance-class services migrate to ILogger via constructor
- injection across four slices: data layer (MessageStore,
- MessageManager, AutoTellTabsService), IPC and integrations
- (HonorificService, IpcManager, TypingIpc, ExtraChat, the three
- GameFunctions classes), UI window layer (ChatLogWindow,
- DbViewer, Popout, three settings tabs), and root (Commands,
- ThemeRegistry, PayloadHandler).
- - Plugin.LogProxy stays in place for the eight buckets ctor
- injection cannot reach: static helpers (EmoteCache,
- AutoTranslate, MemoryUtil, WrapperUtil), Dalamud-reflected
- types (Configuration), the Message data class, and instance
- classes that only log from static methods (FontManager, one
- GameFunctions site).
- - Plugin.cs finishes at 1012 lines — virtually identical to the
- pre-cycle 1013. The new Phase-1 host build and Plugin.X bridge
- wiring trade out exactly the service and window allocations
- that previously lived in LoadAsync.
- - Cross-plugin baseline confirms no performance penalty against
- Chat 2: HellionChat first-frame HITCH 77 ms median, Chat 2
- 74 ms median. Lightless and XIVInstantMessenger sit around
- 7 ms by deferring their font-atlas build past Finished
- loading — that pattern is the v1.5.1 follow-up.
-
- User-visible:
-
- - Slash-command insert fix: pasting a slash command into the
- chat input (Friend List "/tell" action, plugin-driven inserts
- from Artisan, AllaganTools etc.) now replaces the existing
- input instead of concatenating. Cherry-picked from ChatTwo
- upstream ee7768ac with namespace adaptation.
-
- Migration v17 stays (no schema bump).
-
- Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
-
- ---
-
Full history: https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases
diff --git a/HellionChat/Ui/ChatLogWindow.cs b/HellionChat/Ui/ChatLogWindow.cs
index 758b965..1fbb088 100644
--- a/HellionChat/Ui/ChatLogWindow.cs
+++ b/HellionChat/Ui/ChatLogWindow.cs
@@ -515,8 +515,7 @@ public sealed class ChatLogWindow : Window
$"{theme.Name}##quick-theme-{theme.Slug}",
isActive,
ImGuiSelectableFlags.DontClosePopups
- )
- && !isActive
+ ) && !isActive
)
Plugin.ThemeRegistry.Switch(theme.Slug);
}
@@ -547,8 +546,7 @@ public sealed class ChatLogWindow : Window
$"{tabs[i].Name}##quick-tab-{i}",
isActive,
ImGuiSelectableFlags.DontClosePopups
- )
- && !isActive
+ ) && !isActive
)
ChangeTab(i);
}
diff --git a/HellionChat/Ui/HellionStyle.cs b/HellionChat/Ui/HellionStyle.cs
index 4e6481b..aa8f797 100644
--- a/HellionChat/Ui/HellionStyle.cs
+++ b/HellionChat/Ui/HellionStyle.cs
@@ -49,10 +49,7 @@ internal static class HellionStyle
// per-window opacity override and must not fade. See
// feedback_dalamud_pinning_override.
ThemeAbgrCache a;
- if (
- !Plugin.Config.ReduceMotion
- && registry.TryGetActiveCrossfade(out var lerped)
- )
+ if (!Plugin.Config.ReduceMotion && registry.TryGetActiveCrossfade(out var lerped))
{
a = lerped;
}
diff --git a/README.md b/README.md
index 3272d59..76ea8bb 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
[](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/actions/workflows/build.yml)
[](LICENSE)
-[](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/latest)
+[](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/latest)
[](https://github.com/goatcorp/Dalamud)
[](https://dotnet.microsoft.com/)
[](https://www.finalfantasyxiv.com/)
@@ -11,7 +11,7 @@
-**Version 1.5.3** — Privacy-first chat plugin for FINAL FANTASY XIV / Dalamud, built on
+**Version 1.5.4** — Privacy-first chat plugin for FINAL FANTASY XIV / Dalamud, built on
[Chat 2](https://github.com/Infiziert90/ChatTwo) (EUPL-1.2).
Hellion Chat is a privacy-first plugin built on the Chat 2 foundation. The majority of the engine
@@ -299,6 +299,22 @@ An optional submission to the Dalamud main plugin repo (in addition to the custo
## Project Status
+**Version 1.5.4** — Polish and Motion. Theme switches now crossfade smoothly over
+~300 ms across every Hellion-rendered surface — sidebar, title, buttons, tabs,
+scrollbar, separators. The window background snaps deliberately so the per-window
+opacity override from Dalamud's pinning menu stays intact. A new header quick-picker —
+a palette button left of the cog — opens a compact popup that switches themes and tabs
+without opening Settings; the active entry carries a check glyph and the popup stays
+open between picks. Sidebar icons ease their opacity on hover and card-mode message
+borders highlight per tab, both framerate-independent so a stalled Wine frame cannot
+overshoot. A new "Reduce motion" toggle in Theme & Layout disables the crossfade, the
+hover animations and the unread-tab pulse for users who prefer a static UI. No schema
+bump, migration v17 stays.
+
+---
+
+### Project status (pre-v1.5.4, kept for context)
+
**Version 1.5.3** — Localisation Wave + Bundled-Font Overhaul. Twenty-four selectable UI languages
(Catalan, Czech, Danish, Dutch, English, Finnish, French, German, Greek, Hungarian, Italian,
Japanese, Korean, Norsk bokmål, Polish, Portuguese (Brazil), Portuguese (Portugal), Romanian,
@@ -319,8 +335,6 @@ EN/DE/FR/JA — other languages may garble when typed in-game. Migration v17 sta
---
-### Project status (pre-v1.5.3, kept for context)
-
**Version 1.5.2** — First-Run Wizard Rework. The single-page wizard becomes a four-step
staged-commit flow (Welcome → Privacy → Power Settings → Done). The privacy picker becomes a 2×2
grid with a fourth profile "Roleplay" that extends Privacy-First with `Say` and both emote types
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index cb58978..2f1056c 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -11,6 +11,17 @@ releases as an overview and links to the release pages for details.
---
+## Hellion Chat 1.5.4 — Polish and Motion (2026-05-20)
+
+A polish cycle of three P3 items. Theme switches now crossfade smoothly over ~300 ms
+across every Hellion-rendered surface; the window background snaps deliberately so the
+per-window opacity override from Dalamud's pinning menu stays intact. A new header
+quick-picker — a palette button left of the cog — opens a compact popup for switching
+themes and tabs without opening Settings. Sidebar icons and card-mode message borders
+gain framerate-independent hover animations. A new "Reduce motion" toggle in Theme &
+Layout disables the crossfade, hover animations and unread-tab pulse for accessibility.
+No schema bump, migration v17 stays.
+
## Hellion Chat 1.5.3 — Localisation Wave + Bundled-Font Overhaul (2026-05-19)
Multi-language pass plus a long-standing first-frame HITCH lands as a side effect of a font-stack
diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md
index 55c4dd8..1a1acaa 100644
--- a/docs/ROADMAP.md
+++ b/docs/ROADMAP.md
@@ -22,6 +22,18 @@ parallel as a continuous correction pass, gathered via the Hellion Forge Discord
---
+## v1.5.4 — Polish and Motion (released 2026-05-20)
+
+A polish cycle of three P3 items. Theme switches crossfade over ~300 ms across every
+Hellion-rendered surface; the window background snaps deliberately to preserve the
+per-window opacity override from Dalamud's pinning menu. A header quick-picker — a
+palette button left of the cog — switches themes and tabs from a compact popup without
+opening Settings. Sidebar icons and card-mode borders gain framerate-independent hover
+animations. A new "Reduce motion" toggle in Theme & Layout covers accessibility. No
+schema bump; migration v17 stays.
+
+---
+
## v1.5.3 — Localisation Wave + Bundled-Font Overhaul (released 2026-05-19)
Twenty-four selectable UI languages: from FR-only as the original plan scope, the cycle expanded to
diff --git a/repo.json b/repo.json
index 6f8ece9..e32f36f 100644
--- a/repo.json
+++ b/repo.json
@@ -3,7 +3,7 @@
"Author": "Jon Kazama (Hellion Forge)",
"Name": "Hellion Chat",
"InternalName": "HellionChat",
- "AssemblyVersion": "1.5.3.0",
+ "AssemblyVersion": "1.5.4.0",
"Description": "A Hellion Forge plugin — privacy-focused chat replacement for FINAL FANTASY XIV, built for EU, US and JP data rules.\n\nBy default only your own conversations are stored. Public chat, NPC dialogue, system messages and battle logs are discarded at the storage layer unless you opt in. Retention windows are configurable per channel, history can be wiped retroactively, and everything can be exported on demand.\n\nFeatures:\n- Channel whitelist with a Privacy-First default\n- Per-channel retention with a daily background sweep\n- Retroactive cleanup with preview and Ctrl+Shift confirm\n- Export to Markdown, JSON or CSV\n- First-run wizard with four profiles: Privacy-First, Casual, Roleplay, Full History\n- Multi-language UI (24 locales) with live language switching\n- Own config and database — no shared state with other plugins\n\nBased on Chat 2 by Infi and Anna (EUPL-1.2).\nSupport: https://discord.gg/X9V7Kcv5gR",
"ApplicableVersion": "any",
"RepoUrl": "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat",
@@ -20,12 +20,12 @@
"CanUnloadAsync": false,
"LoadPriority": 0,
"Punchline": "A Hellion Forge plugin. Privacy-first chat for FFXIV, built to stay out of your way.",
- "Changelog": "**v1.5.3 — Localisation Wave + Bundled-Font Overhaul (2026-05-19)**\n\nMulti-language pass plus a long-standing first-frame HITCH lands\nas a side effect of a font-stack rewrite.\n\nUser-visible:\n\n- 24 selectable UI languages (was 2). Catalan, Czech, Danish,\n Dutch, English, Finnish, French, German, Greek, Hungarian,\n Italian, Japanese, Korean, Norsk bokmål, Polish, Portuguese\n (BR + PT), Romanian, Russian, Spanish, Swedish, Turkish,\n Ukrainian, Simplified + Traditional Chinese. Sorted by endonym,\n \"None\" pinned first. Non-native locales are AI-assisted and\n flagged for native-speaker review via the Forge Discord.\n- Bundled Inter Light replaces Exo 2 (SIL OFL 1.1, 343 KB). The\n Inter font ships Latin Extended-A/B, Greek polytonic and\n Cyrillic Supplement coverage; NotoSansCjkRegular joins as a\n third merge layer for Hangul and Simplified-Han glyphs the\n FFXIV Japanese game font does not ship.\n- First-frame HITCH dropped from ~74 ms (v1.5.2 baseline that\n held since v1.4.x) to a median of ~20 ms (5-reload sample\n 17.9-23.6 ms, Linux/Wine). The bundled-font path silently\n fell back to the FFXIV Axis font for the entire v1.5.x series\n because of an early-return in the draw loop. The fix that\n routes RegularFont through draw also lands the defer-pattern\n win the v1.5.1 cycle was reaching for.\n- ExtraGlyphRanges auto-activates on language change. Korean,\n ChineseFull and the two new flags (LatinExtended, Greek) toggle\n on without a manual visit to Fonts and Colours.\n- New WarningText under the language dropdown notes FFXIV's\n chat input only fully supports EN/DE/FR/JA character sets.\n Other languages render in HellionChat but may garble when\n typed into in-game chat.\n\nUnder the hood:\n\n- Three-layer font stack: Inter Light primary, FFXIV\n JapaneseFont merge 1 for kana/kanji style, NotoSansCjkRegular\n merge 2 for everything else CJK.\n- LanguageOverride enum gains ten locales plus three previously\n commented out (Italian, Korean, Norwegian as `nb`). New\n values append to the enum so existing config integers stay\n stable across update.\n- Crowdin gap closed: four post-sync ChatTwo keys backfilled\n into 13 legacy locales with per-key AI markers.\n- Plugin.LoadAsync runs a one-shot migration that ORs in the\n matching ExtraGlyphRanges flag for users already on a\n non-default language. Settings.Apply auto-activates on\n change going forward.\n- Em-dash sweep across the EN source and 18 translations to the\n house style. Russian and Ukrainian keep the typographic norm.\n\nMigration v17 stays. UseHellionFont users transition from Exo 2\nto Inter Light transparently on first reload.\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n---\n\n**v1.5.2 — First-Run Wizard Rework (2026-05-18)**\n\nUX patch. The first-run wizard becomes a four-step flow with a\nnew Roleplay privacy profile and a power-settings step that\nsurfaces previously-hidden defaults. Existing v1.5.1 users see\nthe new wizard once on first v1.5.2 boot.\n\nWhat changes user-visible:\n\n- Wizard navigation: Welcome → Privacy profile → Power settings\n → Done. Forge-Bronze pagination dots, dedicated stage for the\n power settings so they are no longer buried in Settings.\n- Fourth privacy profile \"Roleplay\": Privacy-First plus Say and\n both emote types, with a 30-day window for Say and a 90-day\n window for emotes. Shout, Yell and Novice Network stay out.\n- Privacy picker becomes a 2x2 grid. Casual stays the\n recommended option with a ★ marker.\n- Power-settings step covers Load Previous Session, Filter\n Include Previous Sessions, Auto-Tell-Tabs History Preload,\n Compact Density, Prettier Timestamps and a built-in theme\n picker. All six map to existing Configuration fields — no new\n settings introduced.\n- Staged commit: the wizard only writes to Config on the Finish\n step. Decide-later or X-close at any point leaves the existing\n config untouched.\n- Inline test hint on the done step: \"type /tell \n into chat\" surfaces the auto-tell-tab spawn mechanism.\n- Window starts at 720x480 (was 900x560) and can shrink to\n 600x400; Step 1 keeps the fox banner in a folded TreeNode so\n the onboarding copy stays primary.\n- Existing users get the new wizard surfaced once on first boot\n after the update via the new WizardLastShownVersion config\n field. Future cycles bump the constant only when the wizard\n itself changes shape.\n\nUnder the hood:\n\n- WizardStateSmokeStep added to /xlperf alongside the FontManager\n and ThemeSwitch self-tests.\n- Twelve new pure-helper xUnit Facts in the Build Suite cover\n all four privacy profile sets and their retention overrides.\n\nMigration v17 stays (no schema bump). The Configuration grows\none optional string field (WizardLastShownVersion) which\ndefaults to empty for legacy users.\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n---\n\n**v1.5.1 — FontAtlas Refactor and Hellion Forge Signature (2026-05-17)**\n\nHybrid FontManager refactor plus an embedded provenance mark.\n\nWhat changes under the hood:\n\n- FontManager handle creation moves into the ctor inside a single\n atlas.SuppressAutoRebuild() block. The font atlas now builds once\n per plugin load instead of four to five times — less CPU and GPU\n pressure in the first seconds after a reload, less atlas texture\n memory churn.\n- Hybrid property model: Axis, AxisItalic and FontAwesome become\n init-only handles. RegularFont and ItalicFont stay mutable because\n the eight font settings still need to replace them at runtime —\n that path is funnelled through RebuildDelegateFonts() now and\n runs without a plugin reload.\n- FontAwesome reuses Dalamud's UiBuilder.IconFontFixedWidthHandle\n instead of building its own atlas slot. One delegate-build step\n less in the ctor.\n- BuildFontsAsync and BuildFonts are removed; the live mutation\n path is RebuildDelegateFonts() now.\n- Two FontManager self-test steps registered with /xlperf: ctor\n smoke (every handle non-null after Phase-1 resolve, no atlas\n load-exception) and push smoke (Push() returns without throwing).\n\nHonorific full-gradient port (originally the v1.5.1 main item) was\ndropped: Honorific 3.2 exposes no IPC for the rendered gradient\nframe, and an in-plugin port of the colour palette was declined.\nThe integration stays at the v1.4.7 glow-only shape.\n\nUser-visible:\n\n- Hellion Forge signature: a small fox-head ASCII silhouette is\n emitted to /xllog on every plugin load, and a full fox banner\n with \"Hellion Forge\" set inside the body is available as a\n folded TreeNode in the First-Run Wizard and Settings ->\n Information tab. Drawn by Julia Moon, embedded in the plugin DLL.\n- No settings changes, no migration. v17 stays.\n\nNote on performance: the cross-plugin baseline target from v1.5.0\n(matching Lightless and XIVInstantMessenger at ~7 ms HITCH) did\nnot land this cycle. HITCH stays around 80 ms because the cost is\nin the UiBuilder first-frame render path, not in the atlas build\n(which this cycle did reduce from 4-5 builds per load to 1). A\nfirst-frame render investigation is reserved for a later cycle.\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n---\n\n**v1.5.0 — DI Foundation and Service Refactor (2026-05-17)**\n\nMajor architecture cycle. The plugin bootstrap moves to a\ngeneric-host DI container (Microsoft.Extensions.Hosting +\nIServiceCollection) modelled on Lightless Sync. Service logging\nmoves from a static Plugin.LogProxy locator to typed\nMicrosoft.Extensions.Logging.ILogger via constructor injection,\nbridged over Dalamud's IPluginLog by a custom DalamudLogger trio.\n\nWhat changes under the hood:\n\n- 18 instance-class services migrate to ILogger via constructor\n injection across four slices: data layer (MessageStore,\n MessageManager, AutoTellTabsService), IPC and integrations\n (HonorificService, IpcManager, TypingIpc, ExtraChat, the three\n GameFunctions classes), UI window layer (ChatLogWindow,\n DbViewer, Popout, three settings tabs), and root (Commands,\n ThemeRegistry, PayloadHandler).\n- Plugin.LogProxy stays in place for the eight buckets ctor\n injection cannot reach: static helpers (EmoteCache,\n AutoTranslate, MemoryUtil, WrapperUtil), Dalamud-reflected\n types (Configuration), the Message data class, and instance\n classes that only log from static methods (FontManager, one\n GameFunctions site).\n- Plugin.cs finishes at 1012 lines — virtually identical to the\n pre-cycle 1013. The new Phase-1 host build and Plugin.X bridge\n wiring trade out exactly the service and window allocations\n that previously lived in LoadAsync.\n- Cross-plugin baseline confirms no performance penalty against\n Chat 2: HellionChat first-frame HITCH 77 ms median, Chat 2\n 74 ms median. Lightless and XIVInstantMessenger sit around\n 7 ms by deferring their font-atlas build past Finished\n loading — that pattern is the v1.5.1 follow-up.\n\nUser-visible:\n\n- Slash-command insert fix: pasting a slash command into the\n chat input (Friend List \"/tell\" action, plugin-driven inserts\n from Artisan, AllaganTools etc.) now replaces the existing\n input instead of concatenating. Cherry-picked from ChatTwo\n upstream ee7768ac with namespace adaptation.\n\nMigration v17 stays (no schema bump).\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n---\n\nFull history: https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases",
+ "Changelog": "**v1.5.4 — Polish and Motion (2026-05-20)**\n\nA polish cycle: smoother theme switching, faster theme and tab\naccess, and subtle hover motion. Three P3 items plus an\naccessibility toggle.\n\nUser-visible:\n\n- Theme switches now crossfade smoothly over ~300 ms across every\n Hellion-rendered surface — sidebar, title, buttons, tabs,\n scrollbar, separators. The window background snaps deliberately\n so the per-window opacity override from Dalamud's pinning menu\n stays untouched.\n- New header quick-picker: a palette button left of the cog opens\n a compact popup with two sections — every built-in and custom\n theme, and every tab. The active entry carries a check glyph;\n clicking another switches without closing the popup.\n- Sidebar icons ease their opacity on hover, and card-mode message\n borders highlight per tab while the cursor is over their rows.\n Framerate-independent, so a stalled Wine frame cannot overshoot\n the animation.\n- New \"Reduce motion\" toggle in Theme & Layout disables the\n crossfade, the hover animations and the unread-tab pulse for\n users who prefer a static UI.\n\nUnder the hood:\n\n- Two pure-helper lerp paths (ThemeAbgrCacheLerp, FrameLerp) with\n xUnit coverage in the Build Suite, plus a ColourUtil.ApplyAlpha\n alpha modulator. Two new /xlperf self-test steps pin the\n crossfade and quick-picker contracts.\n\nNo schema bump, no migration. Migration v17 stays.\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n---\n\n**v1.5.3 — Localisation Wave + Bundled-Font Overhaul (2026-05-19)**\n\nMulti-language pass plus a long-standing first-frame HITCH lands\nas a side effect of a font-stack rewrite.\n\nUser-visible:\n\n- 24 selectable UI languages (was 2). Catalan, Czech, Danish,\n Dutch, English, Finnish, French, German, Greek, Hungarian,\n Italian, Japanese, Korean, Norsk bokmål, Polish, Portuguese\n (BR + PT), Romanian, Russian, Spanish, Swedish, Turkish,\n Ukrainian, Simplified + Traditional Chinese. Sorted by endonym,\n \"None\" pinned first. Non-native locales are AI-assisted and\n flagged for native-speaker review via the Forge Discord.\n- Bundled Inter Light replaces Exo 2 (SIL OFL 1.1, 343 KB). The\n Inter font ships Latin Extended-A/B, Greek polytonic and\n Cyrillic Supplement coverage; NotoSansCjkRegular joins as a\n third merge layer for Hangul and Simplified-Han glyphs the\n FFXIV Japanese game font does not ship.\n- First-frame HITCH dropped from ~74 ms (v1.5.2 baseline that\n held since v1.4.x) to a median of ~20 ms (5-reload sample\n 17.9-23.6 ms, Linux/Wine). The bundled-font path silently\n fell back to the FFXIV Axis font for the entire v1.5.x series\n because of an early-return in the draw loop. The fix that\n routes RegularFont through draw also lands the defer-pattern\n win the v1.5.1 cycle was reaching for.\n- ExtraGlyphRanges auto-activates on language change. Korean,\n ChineseFull and the two new flags (LatinExtended, Greek) toggle\n on without a manual visit to Fonts and Colours.\n- New WarningText under the language dropdown notes FFXIV's\n chat input only fully supports EN/DE/FR/JA character sets.\n Other languages render in HellionChat but may garble when\n typed into in-game chat.\n\nUnder the hood:\n\n- Three-layer font stack: Inter Light primary, FFXIV\n JapaneseFont merge 1 for kana/kanji style, NotoSansCjkRegular\n merge 2 for everything else CJK.\n- LanguageOverride enum gains ten locales plus three previously\n commented out (Italian, Korean, Norwegian as `nb`). New\n values append to the enum so existing config integers stay\n stable across update.\n- Crowdin gap closed: four post-sync ChatTwo keys backfilled\n into 13 legacy locales with per-key AI markers.\n- Plugin.LoadAsync runs a one-shot migration that ORs in the\n matching ExtraGlyphRanges flag for users already on a\n non-default language. Settings.Apply auto-activates on\n change going forward.\n- Em-dash sweep across the EN source and 18 translations to the\n house style. Russian and Ukrainian keep the typographic norm.\n\nMigration v17 stays. UseHellionFont users transition from Exo 2\nto Inter Light transparently on first reload.\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n---\n\n**v1.5.2 — First-Run Wizard Rework (2026-05-18)**\n\nUX patch. The first-run wizard becomes a four-step flow with a\nnew Roleplay privacy profile and a power-settings step that\nsurfaces previously-hidden defaults. Existing v1.5.1 users see\nthe new wizard once on first v1.5.2 boot.\n\nWhat changes user-visible:\n\n- Wizard navigation: Welcome → Privacy profile → Power settings\n → Done. Forge-Bronze pagination dots, dedicated stage for the\n power settings so they are no longer buried in Settings.\n- Fourth privacy profile \"Roleplay\": Privacy-First plus Say and\n both emote types, with a 30-day window for Say and a 90-day\n window for emotes. Shout, Yell and Novice Network stay out.\n- Privacy picker becomes a 2x2 grid. Casual stays the\n recommended option with a ★ marker.\n- Power-settings step covers Load Previous Session, Filter\n Include Previous Sessions, Auto-Tell-Tabs History Preload,\n Compact Density, Prettier Timestamps and a built-in theme\n picker. All six map to existing Configuration fields — no new\n settings introduced.\n- Staged commit: the wizard only writes to Config on the Finish\n step. Decide-later or X-close at any point leaves the existing\n config untouched.\n- Inline test hint on the done step: \"type /tell \n into chat\" surfaces the auto-tell-tab spawn mechanism.\n- Window starts at 720x480 (was 900x560) and can shrink to\n 600x400; Step 1 keeps the fox banner in a folded TreeNode so\n the onboarding copy stays primary.\n- Existing users get the new wizard surfaced once on first boot\n after the update via the new WizardLastShownVersion config\n field. Future cycles bump the constant only when the wizard\n itself changes shape.\n\nUnder the hood:\n\n- WizardStateSmokeStep added to /xlperf alongside the FontManager\n and ThemeSwitch self-tests.\n- Twelve new pure-helper xUnit Facts in the Build Suite cover\n all four privacy profile sets and their retention overrides.\n\nMigration v17 stays (no schema bump). The Configuration grows\none optional string field (WizardLastShownVersion) which\ndefaults to empty for legacy users.\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n---\n\n**v1.5.1 — FontAtlas Refactor and Hellion Forge Signature (2026-05-17)**\n\nHybrid FontManager refactor plus an embedded provenance mark.\n\nWhat changes under the hood:\n\n- FontManager handle creation moves into the ctor inside a single\n atlas.SuppressAutoRebuild() block. The font atlas now builds once\n per plugin load instead of four to five times — less CPU and GPU\n pressure in the first seconds after a reload, less atlas texture\n memory churn.\n- Hybrid property model: Axis, AxisItalic and FontAwesome become\n init-only handles. RegularFont and ItalicFont stay mutable because\n the eight font settings still need to replace them at runtime —\n that path is funnelled through RebuildDelegateFonts() now and\n runs without a plugin reload.\n- FontAwesome reuses Dalamud's UiBuilder.IconFontFixedWidthHandle\n instead of building its own atlas slot. One delegate-build step\n less in the ctor.\n- BuildFontsAsync and BuildFonts are removed; the live mutation\n path is RebuildDelegateFonts() now.\n- Two FontManager self-test steps registered with /xlperf: ctor\n smoke (every handle non-null after Phase-1 resolve, no atlas\n load-exception) and push smoke (Push() returns without throwing).\n\nHonorific full-gradient port (originally the v1.5.1 main item) was\ndropped: Honorific 3.2 exposes no IPC for the rendered gradient\nframe, and an in-plugin port of the colour palette was declined.\nThe integration stays at the v1.4.7 glow-only shape.\n\nUser-visible:\n\n- Hellion Forge signature: a small fox-head ASCII silhouette is\n emitted to /xllog on every plugin load, and a full fox banner\n with \"Hellion Forge\" set inside the body is available as a\n folded TreeNode in the First-Run Wizard and Settings ->\n Information tab. Drawn by Julia Moon, embedded in the plugin DLL.\n- No settings changes, no migration. v17 stays.\n\nNote on performance: the cross-plugin baseline target from v1.5.0\n(matching Lightless and XIVInstantMessenger at ~7 ms HITCH) did\nnot land this cycle. HITCH stays around 80 ms because the cost is\nin the UiBuilder first-frame render path, not in the atlas build\n(which this cycle did reduce from 4-5 builds per load to 1). A\nfirst-frame render investigation is reserved for a later cycle.\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n---\n\nFull history: https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases",
"AcceptsFeedback": true,
- "DownloadLinkInstall": "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/download/v1.5.3/latest.zip",
- "DownloadLinkUpdate": "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/download/v1.5.3/latest.zip",
- "DownloadLinkTesting": "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/download/v1.5.3/latest.zip",
- "TestingAssemblyVersion": "1.5.3.0",
+ "DownloadLinkInstall": "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/download/v1.5.4/latest.zip",
+ "DownloadLinkUpdate": "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/download/v1.5.4/latest.zip",
+ "DownloadLinkTesting": "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/download/v1.5.4/latest.zip",
+ "TestingAssemblyVersion": "1.5.4.0",
"IconUrl": "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/raw/branch/main/HellionChat/images/icon.png",
"ImageUrls": [
"https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/raw/branch/main/HellionChat/images/chatWindow.png",
@@ -39,4 +39,4 @@
"social"
]
}
-]
\ No newline at end of file
+]