From 1d297aeecfa81f79514ba3bd01e3d5118d55afa8 Mon Sep 17 00:00:00 2001 From: Tremendoussly Date: Sun, 15 Mar 2026 16:51:20 +0100 Subject: [PATCH] Gate below-chat expression sync and localize inline thoughts --- index.js | 2 + src/i18n/en.json | 2 + src/i18n/fr.json | 2 + src/i18n/ru.json | 2 + src/i18n/zh-tw.json | 2 + src/systems/integration/expressionSync.js | 71 +++++++++++++++-------- template.html | 5 +- 7 files changed, 60 insertions(+), 26 deletions(-) diff --git a/index.js b/index.js index dfba6bb..5131fc2 100644 --- a/index.js +++ b/index.js @@ -139,6 +139,7 @@ import { initExpressionSync, queueExpressionCaptureForSpeaker, onExpressionSyncSettingChanged, + onAlternatePresentCharactersVisibilityChanged, onHideDefaultExpressionDisplaySettingChanged, clearExpressionSyncCache, onExpressionSyncChatChanged @@ -358,6 +359,7 @@ async function initUI() { extensionSettings.showAlternatePresentCharactersPanel = $(this).prop('checked'); saveSettings(); renderThoughts(); + onAlternatePresentCharactersVisibilityChanged(); }); $('#rpg-toggle-sync-expressions').on('change', function() { diff --git a/src/i18n/en.json b/src/i18n/en.json index 8f3a16e..bfe8c85 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -50,6 +50,8 @@ "template.settingsModal.display.showLockIconsNote": "Display lock/unlock icons on tracker items to prevent AI from modifying them.", "template.settingsModal.display.showThoughtsInChat": "Show Thoughts", "template.settingsModal.display.showThoughtsInChatNote": "Display character thoughts as overlay bubbles next to their messages.", + "template.settingsModal.display.showInlineThoughts": "Show Thoughts Below Message Text", + "template.settingsModal.display.showInlineThoughtsNote": "Switch between the default corner thought bubbles and thought cards below the message text.", "template.settingsModal.display.alwaysShowThoughtBubble": "Always Show Thought Bubble", "template.settingsModal.display.alwaysShowThoughtBubbleNote": "Auto-expand thought bubble without clicking the icon first", "template.settingsModal.display.enableAnimations": "Enable Animations", diff --git a/src/i18n/fr.json b/src/i18n/fr.json index 193cf21..31cee3f 100644 --- a/src/i18n/fr.json +++ b/src/i18n/fr.json @@ -51,6 +51,8 @@ "template.settingsModal.display.showLockIconsNote": "Afficher les icônes de verrouillage/déverrouillage sur les éléments de suivi pour empêcher l'IA de les modifier.", "template.settingsModal.display.showThoughtsInChat": "Afficher Pensées", "template.settingsModal.display.showThoughtsInChatNote": "Afficher les pensées des personnages sous forme de bulles superposées à côté de leurs messages.", + "template.settingsModal.display.showInlineThoughts": "Afficher les pensées sous le texte du message", + "template.settingsModal.display.showInlineThoughtsNote": "Basculer entre les bulles de pensée dans le coin par défaut et des cartes de pensée sous le texte du message.", "template.settingsModal.display.alwaysShowThoughtBubble": "Toujours Afficher Bulle Pensée", "template.settingsModal.display.alwaysShowThoughtBubbleNote": "Développer automatiquement la bulle de pensée sans cliquer sur l'icône d'abord", "template.settingsModal.display.enableAnimations": "Activer Animations", diff --git a/src/i18n/ru.json b/src/i18n/ru.json index f5a6399..447cfdd 100644 --- a/src/i18n/ru.json +++ b/src/i18n/ru.json @@ -50,6 +50,8 @@ "template.settingsModal.display.showLockIconsNote": "Отображать значки блокировки/разблокировки на элементах трекера, чтобы предотвратить их изменение ИИ.", "template.settingsModal.display.showThoughtsInChat": "Показывать мысли", "template.settingsModal.display.showThoughtsInChatNote": "Отображать мысли персонажей в виде всплывающих пузырьков рядом с их сообщениями.", + "template.settingsModal.display.showInlineThoughts": "Показывать мысли под текстом сообщения", + "template.settingsModal.display.showInlineThoughtsNote": "Переключает между стандартными угловыми пузырями мыслей и карточками мыслей под текстом сообщения.", "template.settingsModal.display.alwaysShowThoughtBubble": "Всегда показывать пузырь мыслей", "template.settingsModal.display.alwaysShowThoughtBubbleNote": "Автоматически раскрывать пузырь мыслей без предварительного нажатия на значок", "template.settingsModal.display.enableAnimations": "Включить анимации", diff --git a/src/i18n/zh-tw.json b/src/i18n/zh-tw.json index 92c2e32..07b2900 100644 --- a/src/i18n/zh-tw.json +++ b/src/i18n/zh-tw.json @@ -41,6 +41,8 @@ "template.settingsModal.display.showLockIconsNote": "在追蹤器項目上顯示鎖定/解鎖圖示,以防止 AI 修改它們。", "template.settingsModal.display.showThoughtsInChat": "在聊天中顯示想法", "template.settingsModal.display.showThoughtsInChatNote": "將角色想法顯示為其訊息旁的泡泡", + "template.settingsModal.display.showInlineThoughts": "在訊息文字下方顯示想法", + "template.settingsModal.display.showInlineThoughtsNote": "在預設角落想法泡泡與顯示在訊息文字下方的想法卡片之間切換。", "template.settingsModal.display.alwaysShowThoughtBubble": "始終顯示想法泡泡", "template.settingsModal.display.alwaysShowThoughtBubbleNote": "自動展開想法泡泡", "template.settingsModal.display.enableAnimations": "啟用動畫", diff --git a/src/systems/integration/expressionSync.js b/src/systems/integration/expressionSync.js index a700687..da25730 100644 --- a/src/systems/integration/expressionSync.js +++ b/src/systems/integration/expressionSync.js @@ -139,11 +139,14 @@ function shouldHideNativeExpressionDisplay() { return extensionSettings.enabled === true && extensionSettings.hideDefaultExpressionDisplay === true; } +function shouldSyncExpressionPortraits() { + return extensionSettings.enabled === true + && extensionSettings.syncExpressionsToPresentCharacters === true + && extensionSettings.showAlternatePresentCharactersPanel === true; +} + function shouldRunExpressionObservers() { - return extensionSettings.enabled === true && ( - extensionSettings.syncExpressionsToPresentCharacters === true - || extensionSettings.hideDefaultExpressionDisplay === true - ); + return shouldSyncExpressionPortraits() || shouldHideNativeExpressionDisplay(); } function isExpressionContainerNode(node) { @@ -392,8 +395,17 @@ function teardownExpressionObservers() { observedExpressionImage = null; } +function resetPendingExpressionCaptureState() { + clearScheduledCaptures(); + pendingCaptureRequestId += 1; + pendingSpeakerName = null; + pendingSpeakerBaselineSignature = null; + pendingSpeakerQueuedAt = 0; + lastCapturedExpressionSrc = null; +} + function captureExpressionForSpeaker(speakerName, expectedRequestId = null) { - if (!extensionSettings.enabled || !extensionSettings.syncExpressionsToPresentCharacters) { + if (!shouldSyncExpressionPortraits()) { return false; } if (expectedRequestId !== null && expectedRequestId !== pendingCaptureRequestId) { @@ -466,7 +478,8 @@ function ensureExpressionObservers() { if (!shouldRunExpressionObservers()) { teardownExpressionObservers(); - return; + resetPendingExpressionCaptureState(); + return false; } const currentImg = findExpressionImageElement(pendingSpeakerName); @@ -506,6 +519,8 @@ function ensureExpressionObservers() { childList: true, subtree: true }); + + return true; } function clearScheduledCaptures() { @@ -517,7 +532,7 @@ function clearScheduledCaptures() { } export function queueExpressionCaptureForSpeaker(speakerName) { - if (!extensionSettings.enabled || !extensionSettings.syncExpressionsToPresentCharacters) { + if (!shouldSyncExpressionPortraits()) { return; } @@ -543,7 +558,7 @@ export function queueExpressionCaptureForSpeaker(speakerName) { } export function syncExpressionFromLatestMessage() { - if (!extensionSettings.enabled || !extensionSettings.syncExpressionsToPresentCharacters) { + if (!shouldSyncExpressionPortraits()) { return; } @@ -557,7 +572,7 @@ export function initExpressionSync() { ensureExpressionObservers(); - if (extensionSettings.syncExpressionsToPresentCharacters) { + if (shouldSyncExpressionPortraits()) { syncExpressionFromLatestMessage(); } } @@ -578,7 +593,7 @@ export function onExpressionSyncChatChanged() { setTimeout(() => { ensureExpressionObservers(); syncNativeExpressionDisplayVisibility(); - if (extensionSettings.syncExpressionsToPresentCharacters) { + if (shouldSyncExpressionPortraits()) { syncExpressionFromLatestMessage(); } else { refreshExpressionConsumers(); @@ -594,18 +609,31 @@ export function onExpressionSyncSettingChanged(enabled) { if (!purged) { refreshExpressionConsumers(); } + if (shouldSyncExpressionPortraits()) { + syncExpressionFromLatestMessage(); + } + return; + } + + const observersActive = ensureExpressionObservers(); + if (observersActive) { + resetPendingExpressionCaptureState(); + } + refreshExpressionConsumers(); +} + +export function onAlternatePresentCharactersVisibilityChanged() { + const shouldSyncPortraits = shouldSyncExpressionPortraits(); + const observersActive = ensureExpressionObservers(); + + if (shouldSyncPortraits) { syncExpressionFromLatestMessage(); return; } - ensureExpressionObservers(); - clearScheduledCaptures(); - pendingCaptureRequestId += 1; - pendingSpeakerName = null; - pendingSpeakerBaselineSignature = null; - pendingSpeakerQueuedAt = 0; - lastCapturedExpressionSrc = null; - refreshExpressionConsumers(); + if (observersActive) { + resetPendingExpressionCaptureState(); + } } export function onHideDefaultExpressionDisplaySettingChanged(enabled) { @@ -617,12 +645,7 @@ export function onHideDefaultExpressionDisplaySettingChanged(enabled) { } export function clearExpressionSyncCache() { - clearScheduledCaptures(); - pendingCaptureRequestId += 1; - pendingSpeakerName = null; - pendingSpeakerBaselineSignature = null; - pendingSpeakerQueuedAt = 0; - lastCapturedExpressionSrc = null; + resetPendingExpressionCaptureState(); teardownExpressionObservers(); showNativeExpressionDisplay(); } diff --git a/template.html b/template.html index 7a49a1b..13d22af 100644 --- a/template.html +++ b/template.html @@ -396,9 +396,10 @@ - + Switch between the default corner thought bubbles and thought cards below the message text.