diff --git a/README.md b/README.md index fde2e10..2433cf7 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,13 @@ An immersive RPG extension for browsers that tracks character stats, scene infor ## 🆕 What's New -### v3.6.2 +### v3.7.0 +- Added omniscience filter. +- Added opacity to the color selector. +- Overwritten SillyTavern's dumb-ahh trim logic when joining prompts. +- Fixed custom attributes not allowing value increase/decrease. - Various bug fixes. -- Added the ability to add present characters manually. **Special thanks to all the other contributors for this project:** Paperboygold, Munimunigamer, Subarashimo, Lilminzyu, Claude, IDeathByte, Chungchandev, Joenunezb, Amauragis, and Tomt610. diff --git a/index.js b/index.js index 18076b9..e8f89e9 100644 --- a/index.js +++ b/index.js @@ -384,6 +384,11 @@ async function initUI() { saveSettings(); }); + $('#rpg-toggle-omniscience').on('change', function() { + extensionSettings.enableOmniscienceFilter = $(this).prop('checked'); + saveSettings(); + }); + $('#rpg-toggle-cyoa').on('change', function() { extensionSettings.enableCYOA = $(this).prop('checked'); saveSettings(); @@ -572,6 +577,12 @@ async function initUI() { updateFeatureTogglesVisibility(); }); + $('#rpg-toggle-show-omniscience-toggle').on('change', function() { + extensionSettings.showOmniscienceToggle = $(this).prop('checked'); + saveSettings(); + updateFeatureTogglesVisibility(); + }); + $('#rpg-toggle-show-cyoa-toggle').on('change', function() { extensionSettings.showCYOAToggle = $(this).prop('checked'); saveSettings(); @@ -805,12 +816,30 @@ async function initUI() { renderUserStats(); // Re-render with new colors }); + $('#rpg-stat-bar-color-low-opacity').on('input', function() { + const opacity = Number($(this).val()); + extensionSettings.statBarColorLowOpacity = opacity; + $('#rpg-stat-bar-color-low-opacity-value').text(opacity + '%'); + renderUserStats(); + }).on('change', function() { + saveSettings(); + }); + $('#rpg-stat-bar-color-high').on('change', function() { extensionSettings.statBarColorHigh = String($(this).val()); saveSettings(); renderUserStats(); // Re-render with new colors }); + $('#rpg-stat-bar-color-high-opacity').on('input', function() { + const opacity = Number($(this).val()); + extensionSettings.statBarColorHighOpacity = opacity; + $('#rpg-stat-bar-color-high-opacity-value').text(opacity + '%'); + renderUserStats(); + }).on('change', function() { + saveSettings(); + }); + // Theme selection $('#rpg-theme-select').on('change', function() { extensionSettings.theme = String($(this).val()); @@ -832,6 +861,19 @@ async function initUI() { } }); + $('#rpg-custom-bg-opacity').on('input', function() { + const opacity = Number($(this).val()); + extensionSettings.customColors.bgOpacity = opacity; + $('#rpg-custom-bg-opacity-value').text(opacity + '%'); + if (extensionSettings.theme === 'custom') { + applyCustomTheme(); + updateSettingsPopupTheme(getSettingsModal()); + updateChatThoughts(); + } + }).on('change', function() { + saveSettings(); + }); + $('#rpg-custom-accent').on('change', function() { extensionSettings.customColors.accent = String($(this).val()); saveSettings(); @@ -842,6 +884,19 @@ async function initUI() { } }); + $('#rpg-custom-accent-opacity').on('input', function() { + const opacity = Number($(this).val()); + extensionSettings.customColors.accentOpacity = opacity; + $('#rpg-custom-accent-opacity-value').text(opacity + '%'); + if (extensionSettings.theme === 'custom') { + applyCustomTheme(); + updateSettingsPopupTheme(getSettingsModal()); + updateChatThoughts(); + } + }).on('change', function() { + saveSettings(); + }); + $('#rpg-custom-text').on('change', function() { extensionSettings.customColors.text = String($(this).val()); saveSettings(); @@ -852,6 +907,19 @@ async function initUI() { } }); + $('#rpg-custom-text-opacity').on('input', function() { + const opacity = Number($(this).val()); + extensionSettings.customColors.textOpacity = opacity; + $('#rpg-custom-text-opacity-value').text(opacity + '%'); + if (extensionSettings.theme === 'custom') { + applyCustomTheme(); + updateSettingsPopupTheme(getSettingsModal()); + updateChatThoughts(); + } + }).on('change', function() { + saveSettings(); + }); + $('#rpg-custom-highlight').on('change', function() { extensionSettings.customColors.highlight = String($(this).val()); saveSettings(); @@ -862,6 +930,19 @@ async function initUI() { } }); + $('#rpg-custom-highlight-opacity').on('input', function() { + const opacity = Number($(this).val()); + extensionSettings.customColors.highlightOpacity = opacity; + $('#rpg-custom-highlight-opacity-value').text(opacity + '%'); + if (extensionSettings.theme === 'custom') { + applyCustomTheme(); + updateSettingsPopupTheme(getSettingsModal()); + updateChatThoughts(); + } + }).on('change', function() { + saveSettings(); + }); + // External API settings event handlers $('#rpg-external-base-url').on('change', function() { if (!extensionSettings.externalApiSettings) { @@ -969,6 +1050,7 @@ async function initUI() { $('#rpg-toggle-html-prompt').prop('checked', extensionSettings.enableHtmlPrompt); $('#rpg-toggle-dialogue-coloring').prop('checked', extensionSettings.enableDialogueColoring); $('#rpg-toggle-deception').prop('checked', extensionSettings.enableDeceptionSystem ?? false); + $('#rpg-toggle-omniscience').prop('checked', extensionSettings.enableOmniscienceFilter ?? false); $('#rpg-toggle-cyoa').prop('checked', extensionSettings.enableCYOA ?? false); $('#rpg-toggle-spotify-music').prop('checked', extensionSettings.enableSpotifyMusic); @@ -979,6 +1061,7 @@ async function initUI() { $('#rpg-toggle-show-html-toggle').prop('checked', extensionSettings.showHtmlToggle ?? true); $('#rpg-toggle-show-dialogue-coloring-toggle').prop('checked', extensionSettings.showDialogueColoringToggle ?? true); $('#rpg-toggle-show-deception-toggle').prop('checked', extensionSettings.showDeceptionToggle ?? true); + $('#rpg-toggle-show-omniscience-toggle').prop('checked', extensionSettings.showOmniscienceToggle ?? true); $('#rpg-toggle-show-cyoa-toggle').prop('checked', extensionSettings.showCYOAToggle ?? true); $('#rpg-toggle-show-spotify-toggle').prop('checked', extensionSettings.showSpotifyToggle ?? true); $('#rpg-toggle-show-dynamic-weather-toggle').prop('checked', extensionSettings.showDynamicWeatherToggle ?? true); @@ -1041,12 +1124,29 @@ async function initUI() { $('#rpg-strip-widget-options').toggle(stripWidgets.enabled || false); $('#rpg-stat-bar-color-low').val(extensionSettings.statBarColorLow); + $('#rpg-stat-bar-color-low-opacity').val(extensionSettings.statBarColorLowOpacity ?? 100); + $('#rpg-stat-bar-color-low-opacity-value').text((extensionSettings.statBarColorLowOpacity ?? 100) + '%'); + $('#rpg-stat-bar-color-high').val(extensionSettings.statBarColorHigh); + $('#rpg-stat-bar-color-high-opacity').val(extensionSettings.statBarColorHighOpacity ?? 100); + $('#rpg-stat-bar-color-high-opacity-value').text((extensionSettings.statBarColorHighOpacity ?? 100) + '%'); + $('#rpg-theme-select').val(extensionSettings.theme); $('#rpg-custom-bg').val(extensionSettings.customColors.bg); + $('#rpg-custom-bg-opacity').val(extensionSettings.customColors.bgOpacity ?? 100); + $('#rpg-custom-bg-opacity-value').text((extensionSettings.customColors.bgOpacity ?? 100) + '%'); + $('#rpg-custom-accent').val(extensionSettings.customColors.accent); + $('#rpg-custom-accent-opacity').val(extensionSettings.customColors.accentOpacity ?? 100); + $('#rpg-custom-accent-opacity-value').text((extensionSettings.customColors.accentOpacity ?? 100) + '%'); + $('#rpg-custom-text').val(extensionSettings.customColors.text); + $('#rpg-custom-text-opacity').val(extensionSettings.customColors.textOpacity ?? 100); + $('#rpg-custom-text-opacity-value').text((extensionSettings.customColors.textOpacity ?? 100) + '%'); + $('#rpg-custom-highlight').val(extensionSettings.customColors.highlight); + $('#rpg-custom-highlight-opacity').val(extensionSettings.customColors.highlightOpacity ?? 100); + $('#rpg-custom-highlight-opacity-value').text((extensionSettings.customColors.highlightOpacity ?? 100) + '%'); // Initialize External API settings values if (extensionSettings.externalApiSettings) { diff --git a/manifest.json b/manifest.json index 88c9cbe..fa03ec4 100644 --- a/manifest.json +++ b/manifest.json @@ -6,6 +6,6 @@ "js": "index.js", "css": "style.css", "author": "Marinara", - "version": "3.6.3", + "version": "3.7.0", "homePage": "https://github.com/SpicyMarinara/rpg-companion-sillytavern" } diff --git a/settings.html b/settings.html index 4910b03..ce075ed 100644 --- a/settings.html +++ b/settings.html @@ -49,7 +49,7 @@
- v3.6.2 + v3.7.0
diff --git a/src/core/persistence.js b/src/core/persistence.js index 15b6165..e6343c8 100644 --- a/src/core/persistence.js +++ b/src/core/persistence.js @@ -118,6 +118,22 @@ export function loadSettings() { settingsChanged = true; } + // Migration to version 5: Add opacity properties for all colors + if (currentVersion < 5) { + // console.log('[RPG Companion] Migrating settings to version 5 (adding color opacity)'); + if (!extensionSettings.customColors) { + extensionSettings.customColors = {}; + } + if (extensionSettings.customColors.bgOpacity === undefined) extensionSettings.customColors.bgOpacity = 100; + if (extensionSettings.customColors.accentOpacity === undefined) extensionSettings.customColors.accentOpacity = 100; + if (extensionSettings.customColors.textOpacity === undefined) extensionSettings.customColors.textOpacity = 100; + if (extensionSettings.customColors.highlightOpacity === undefined) extensionSettings.customColors.highlightOpacity = 100; + if (extensionSettings.statBarColorLowOpacity === undefined) extensionSettings.statBarColorLowOpacity = 100; + if (extensionSettings.statBarColorHighOpacity === undefined) extensionSettings.statBarColorHighOpacity = 100; + extensionSettings.settingsVersion = 5; + settingsChanged = true; + } + // Save migrated settings if (settingsChanged) { saveSettings(); diff --git a/src/core/state.js b/src/core/state.js index acc3b13..693072a 100644 --- a/src/core/state.js +++ b/src/core/state.js @@ -23,12 +23,15 @@ export let extensionSettings = { showThoughtsInChat: true, // Show thoughts overlay in chat narratorMode: false, // Use character card as narrator instead of fixed character references customNarratorPrompt: '', // Custom narrator mode prompt text (empty = use default) + customContextInstructionsPrompt: '', // Custom context instructions prompt text (empty = use default) enableHtmlPrompt: false, // Enable immersive HTML prompt injection customHtmlPrompt: '', // Custom HTML prompt text (empty = use default) enableDialogueColoring: false, // Enable dialogue coloring prompt injection customDialogueColoringPrompt: '', // Custom dialogue coloring prompt text (empty = use default) enableDeceptionSystem: false, // Enable deception tracking with tags customDeceptionPrompt: '', // Custom deception prompt text (empty = use default) + enableOmniscienceFilter: false, // Enable omniscience filter with tags + customOmnisciencePrompt: '', // Custom omniscience filter prompt text (empty = use default) enableCYOA: false, // Enable "Choose Your Own Adventure" formatting with action choices customCYOAPrompt: '', // Custom CYOA prompt text (empty = use default) enableSpotifyMusic: false, // Enable Spotify music integration (asks AI for Spotify URLs) @@ -41,6 +44,7 @@ export let extensionSettings = { showHtmlToggle: true, // Show Immersive HTML toggle in main panel showDialogueColoringToggle: true, // Show Dialogue Coloring toggle in main panel (enabled by default) showDeceptionToggle: true, // Show Deception System toggle in main panel + showOmniscienceToggle: true, // Show Omniscience Filter toggle in main panel showCYOAToggle: true, // Show CYOA toggle in main panel showSpotifyToggle: true, // Show Spotify Music toggle in main panel @@ -62,12 +66,18 @@ export let extensionSettings = { theme: 'default', // Theme: default, sci-fi, fantasy, cyberpunk, custom customColors: { bg: '#1a1a2e', + bgOpacity: 100, accent: '#16213e', + accentOpacity: 100, text: '#eaeaea', - highlight: '#e94560' + textOpacity: 100, + highlight: '#e94560', + highlightOpacity: 100 }, statBarColorLow: '#cc3333', // Color for low stat values (red) + statBarColorLowOpacity: 100, statBarColorHigh: '#33cc66', // Color for high stat values (green) + statBarColorHighOpacity: 100, enableAnimations: true, // Enable smooth animations for stats and content updates mobileFabPosition: { top: 'calc(var(--topBarBlockSize) + 60px)', diff --git a/src/i18n/en.json b/src/i18n/en.json index ef78a33..4f16aa3 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -52,6 +52,10 @@ "template.settingsModal.display.showImmersiveHtmlToggleNote": "Display a toggle button to enable/disable HTML formatting in messages.", "template.settingsModal.display.showDialogueColoringToggle": "Show Colored Dialogues", "template.settingsModal.display.showDialogueColoringToggleNote": "Display a toggle button to enable/disable colored dialogue formatting.", + "template.settingsModal.display.showDeceptionToggle": "Show Deception System", + "template.settingsModal.display.showDeceptionToggleNote": "Display a toggle button to enable/disable the Deception System for marking lies and deceptions.", + "template.settingsModal.display.showOmniscienceToggle": "Show Omniscience Filter", + "template.settingsModal.display.showOmniscienceToggleNote": "Display a toggle button to enable/disable the Omniscience Filter for filtering hidden events.", "template.settingsModal.display.showSpotifyMusicToggle": "Show Spotify Music", "template.settingsModal.display.showSpotifyMusicToggleNote": "Display Spotify music player with AI-suggested scene-appropriate tracks.", "template.settingsModal.display.showSnowflakesToggle": "Show Snowflakes Effect", @@ -162,6 +166,8 @@ "template.mainPanel.clearLastRoll": "Clear last roll", "template.mainPanel.immersiveHtml": "Immersive HTML", "template.mainPanel.coloredDialogues": "Colored Dialogues", + "template.mainPanel.deceptionSystem": "Deception System", + "template.mainPanel.omniscienceFilter": "Omniscience Filter", "template.mainPanel.spotifyMusic": "Spotify Music", "template.mainPanel.snowflakesEffect": "Snowflakes Effect", "template.mainPanel.dynamicWeatherEffects": "Dynamic Weather", diff --git a/src/systems/features/classicStats.js b/src/systems/features/classicStats.js index 9e322f6..71e2f1b 100644 --- a/src/systems/features/classicStats.js +++ b/src/systems/features/classicStats.js @@ -20,6 +20,10 @@ export function setupClassicStatsButtons() { // Delegated event listener for increase buttons $userStatsContainer.on('click', '.rpg-stat-increase', function() { const stat = $(this).data('stat'); + // Initialize custom attributes if they don't exist + if (extensionSettings.classicStats[stat] === undefined) { + extensionSettings.classicStats[stat] = 10; + } if (extensionSettings.classicStats[stat] < 999) { extensionSettings.classicStats[stat]++; saveSettings(); @@ -33,6 +37,10 @@ export function setupClassicStatsButtons() { // Delegated event listener for decrease buttons $userStatsContainer.on('click', '.rpg-stat-decrease', function() { const stat = $(this).data('stat'); + // Initialize custom attributes if they don't exist + if (extensionSettings.classicStats[stat] === undefined) { + extensionSettings.classicStats[stat] = 10; + } if (extensionSettings.classicStats[stat] > 1) { extensionSettings.classicStats[stat]--; saveSettings(); diff --git a/src/systems/features/jsonCleaning.js b/src/systems/features/jsonCleaning.js index d40bc4f..5f6175a 100644 --- a/src/systems/features/jsonCleaning.js +++ b/src/systems/features/jsonCleaning.js @@ -76,7 +76,7 @@ export async function ensureJsonCleaningRegex(st_extension_settings, saveSetting } // Small delay to ensure save completes await new Promise(resolve => setTimeout(resolve, 100)); - console.log('[RPG Companion] ✅ Updated JSON cleaning regex to v3.2.6 settings.'); + console.log('[RPG Companion] ✅ Updated JSON cleaning regex to v3.2.3 settings.'); } else { console.log('[RPG Companion] JSON Cleaning Regex is up to date.'); } diff --git a/src/systems/generation/injector.js b/src/systems/generation/injector.js index 52e9b2f..aed6894 100644 --- a/src/systems/generation/injector.js +++ b/src/systems/generation/injector.js @@ -4,7 +4,7 @@ */ import { getContext } from '../../../../../../extensions.js'; -import { setExtensionPrompt, extension_prompt_types, extension_prompt_roles, eventSource, event_types } from '../../../../../../../script.js'; +import { extension_prompt_types, extension_prompt_roles, setExtensionPrompt, eventSource, event_types } from '../../../../../../../script.js'; import { extensionSettings, committedTrackerData, @@ -22,8 +22,11 @@ import { DEFAULT_HTML_PROMPT, DEFAULT_DIALOGUE_COLORING_PROMPT, DEFAULT_DECEPTION_PROMPT, + DEFAULT_OMNISCIENCE_FILTER_PROMPT, DEFAULT_CYOA_PROMPT, DEFAULT_SPOTIFY_PROMPT, + DEFAULT_NARRATOR_PROMPT, + DEFAULT_CONTEXT_INSTRUCTIONS_PROMPT, SPOTIFY_FORMAT_INSTRUCTION } from './promptBuilder.js'; import { restoreCheckpointOnLoad } from '../features/chapterCheckpoint.js'; @@ -478,6 +481,7 @@ function onGenerateBeforeCombinePrompts(eventData) { /** * Event handler for GENERATE_AFTER_COMBINE_PROMPTS (text completion). * This is now a backup/fallback - primary injection happens in BEFORE_COMBINE. + * Also fixes newline spacing after tag. * * @param {Object} eventData - Event data with prompt property */ @@ -490,24 +494,30 @@ function onGenerateAfterCombinePrompts(eventData) { return; } - // Skip if injection already happened in BEFORE_COMBINE - if (historyInjectionDone) { - return; + let didInjectHistory = false; + + // Inject historical context if available and not already done + if (!historyInjectionDone && pendingContextMap.size > 0) { + // Fallback injection for edge cases where BEFORE_COMBINE didn't work + console.log('[RPG Companion] Using fallback string-based injection (AFTER_COMBINE)'); + eventData.prompt = injectContextIntoTextPrompt(eventData.prompt); + didInjectHistory = true; } - // Only inject if we have pending context - if (pendingContextMap.size === 0) { - return; - } + // Always fix newlines around context tags (whether we just injected or not) + eventData.prompt = eventData.prompt.replace(//g, '\n'); + eventData.prompt = eventData.prompt.replace(/<\/context>/g, '\n'); - // Fallback injection for edge cases where BEFORE_COMBINE didn't work - console.log('[RPG Companion] Using fallback string-based injection (AFTER_COMBINE)'); - eventData.prompt = injectContextIntoTextPrompt(eventData.prompt); + // Remove extra newlines after last_message opening and closing tags + // Match exactly the double newline pattern + eventData.prompt = eventData.prompt.replace(/\n\n/g, '\n'); + eventData.prompt = eventData.prompt.replace(/\n\n<\/last_message>/g, '\n'); } /** * Event handler for CHAT_COMPLETION_PROMPT_READY. * Injects historical context into the chat message array. + * Also fixes newline spacing around tags. * * @param {Object} eventData - Event data with chat property */ @@ -520,14 +530,20 @@ function onChatCompletionPromptReady(eventData) { return; } - // Only inject if we have pending context - if (pendingContextMap.size === 0) { - return; + // Inject historical context if we have pending context + if (pendingContextMap.size > 0) { + eventData.chat = injectContextIntoChatPrompt(eventData.chat); + // DON'T clear pendingContextMap here - let it persist for other generations + // (e.g., prewarm extensions). It will be cleared on GENERATION_ENDED. } - eventData.chat = injectContextIntoChatPrompt(eventData.chat); - // DON'T clear pendingContextMap here - let it persist for other generations - // (e.g., prewarm extensions). It will be cleared on GENERATION_ENDED. + // Fix newlines around context tags for all messages + for (const message of eventData.chat) { + if (message.content && typeof message.content === 'string') { + message.content = message.content.replace(//g, '\n'); + message.content = message.content.replace(/<\/context>/g, '\n'); + } + } } /** @@ -792,6 +808,19 @@ export async function onGenerationStarted(type, data, dryRun) { setExtensionPrompt('rpg-companion-deception', '', extension_prompt_types.IN_CHAT, 0, false); } + // Inject Omniscience Filter prompt separately at depth 0 if enabled + if (extensionSettings.enableOmniscienceFilter && !shouldSuppress) { + // Use custom Omniscience Filter prompt if set, otherwise use default + const omnisciencePromptText = extensionSettings.customOmnisciencePrompt || DEFAULT_OMNISCIENCE_FILTER_PROMPT; + const omnisciencePrompt = `\n${omnisciencePromptText}\n`; + + setExtensionPrompt('rpg-companion-omniscience', omnisciencePrompt, extension_prompt_types.IN_CHAT, 0, false); + // console.log('[RPG Companion] Injected Omniscience Filter prompt at depth 0 for together mode'); + } else { + // Clear Omniscience Filter prompt if disabled + setExtensionPrompt('rpg-companion-omniscience', '', extension_prompt_types.IN_CHAT, 0, false); + } + // Inject Spotify prompt separately at depth 0 if enabled if (extensionSettings.enableSpotifyMusic && !shouldSuppress) { // Use custom Spotify prompt if set, otherwise use default @@ -823,12 +852,14 @@ export async function onGenerationStarted(type, data, dryRun) { const contextSummary = generateContextualSummary(); if (contextSummary) { - const wrappedContext = `\nHere is context information about the current scene, and what follows is the last message in the chat history: + // Use custom context instructions prompt if set, otherwise use default + const contextInstructionsText = extensionSettings.customContextInstructionsPrompt || DEFAULT_CONTEXT_INSTRUCTIONS_PROMPT; + + const wrappedContext = ` ${contextSummary} - -Ensure these details naturally reflect and influence the narrative. Character behavior, dialogue, and story events should acknowledge these conditions when relevant, such as fatigue affecting performance, low hygiene influencing social interactions, environmental factors shaping the scene, or a character's emotional state coloring their responses. -\n\n`; +${contextInstructionsText} +`; // Inject context at depth 1 (before last user message) as SYSTEM // Skip when a guided generation injection is present to avoid conflicting instructions @@ -880,6 +911,19 @@ Ensure these details naturally reflect and influence the narrative. Character be setExtensionPrompt('rpg-companion-deception', '', extension_prompt_types.IN_CHAT, 0, false); } + // Inject Omniscience Filter prompt separately at depth 0 if enabled + if (extensionSettings.enableOmniscienceFilter && !shouldSuppress) { + // Use custom Omniscience Filter prompt if set, otherwise use default + const omnisciencePromptText = extensionSettings.customOmnisciencePrompt || DEFAULT_OMNISCIENCE_FILTER_PROMPT; + const omnisciencePrompt = `\n${omnisciencePromptText}\n`; + + setExtensionPrompt('rpg-companion-omniscience', omnisciencePrompt, extension_prompt_types.IN_CHAT, 0, false); + // console.log('[RPG Companion] Injected Omniscience Filter prompt at depth 0 for separate/external mode'); + } else { + // Clear Omniscience Filter prompt if disabled + setExtensionPrompt('rpg-companion-omniscience', '', extension_prompt_types.IN_CHAT, 0, false); + } + // Inject Spotify prompt separately at depth 0 if enabled if (extensionSettings.enableSpotifyMusic && !shouldSuppress) { // Use custom Spotify prompt if set, otherwise use default @@ -917,6 +961,7 @@ Ensure these details naturally reflect and influence the narrative. Character be setExtensionPrompt('rpg-companion-html', '', extension_prompt_types.IN_CHAT, 0, false); setExtensionPrompt('rpg-companion-dialogue-coloring', '', extension_prompt_types.IN_CHAT, 0, false); setExtensionPrompt('rpg-companion-deception', '', extension_prompt_types.IN_CHAT, 0, false); + setExtensionPrompt('rpg-companion-omniscience', '', extension_prompt_types.IN_CHAT, 0, false); setExtensionPrompt('rpg-companion-zzz-cyoa', '', extension_prompt_types.IN_CHAT, 0, false); setExtensionPrompt('rpg-companion-spotify', '', extension_prompt_types.IN_CHAT, 0, false); } diff --git a/src/systems/generation/parser.js b/src/systems/generation/parser.js index 83b7400..8bb0da0 100644 --- a/src/systems/generation/parser.js +++ b/src/systems/generation/parser.js @@ -618,7 +618,12 @@ export function parseUserStats(statsText) { if (typeof quest === 'string') return quest; if (typeof quest === 'object') { // Check for locked format: {value, locked} - if (quest.value !== undefined) return String(quest.value); + // Recursively extract value if it's nested + let extracted = quest; + while (typeof extracted === 'object' && extracted.value !== undefined) { + extracted = extracted.value; + } + if (typeof extracted === 'string') return extracted; // v3 format: {title, description, status} return quest.title || quest.description || JSON.stringify(quest); } diff --git a/src/systems/generation/promptBuilder.js b/src/systems/generation/promptBuilder.js index a1f496e..743c120 100644 --- a/src/systems/generation/promptBuilder.js +++ b/src/systems/generation/promptBuilder.js @@ -33,6 +33,15 @@ export const DEFAULT_DIALOGUE_COLORING_PROMPT = `Wrap all character/NPC "dialogu */ export const DEFAULT_DECEPTION_PROMPT = `When a character is lying or deceiving, you should follow up that line with the tag, containing a brief description of the truth and the lie's reason, using the template below (replace placeholders in quotation marks). This will be hidden from the user's view, but not to you, making it useful for future consequences: .`; +/** + * Default Omniscience Filter prompt text + * This instructs the AI to separate information the player character cannot perceive + */ +export const DEFAULT_OMNISCIENCE_FILTER_PROMPT = `You must strictly separate what the player can directly perceive from what they cannot. They should only read limited narrative content that their persona can actually see, hear, smell, touch, or otherwise directly sense. Before writing any narrative content that involves events, actions, or details the player directly cannot perceive (because they're not looking, too far away, behind them, in another room, happening silently, include NPCs' internal thoughts, etc.), you absolutely must output that hidden information inside a tag using this exact format: + +Example: You hear a faint click from somewhere behind you, but when you glance up from your newspaper, the room seems unchanged.`; + + /** * Default CYOA prompt text */ @@ -53,6 +62,11 @@ export const SPOTIFY_FORMAT_INSTRUCTION = `Include it in this exact format: n.toString(16).padStart(2, '0'); - return `#${toHex(r)}${toHex(g)}${toHex(b)}`; + return `rgba(${r}, ${g}, ${b}, ${a})`; } /** @@ -542,7 +543,13 @@ export function renderThoughts() {
`; for (const stat of enabledCharStats) { const statValue = char[stat.name] || 0; - const statColor = getStatColor(statValue, extensionSettings.statBarColorLow, extensionSettings.statBarColorHigh); + const statColor = getStatColor( + statValue, + extensionSettings.statBarColorLow, + extensionSettings.statBarColorHigh, + extensionSettings.statBarColorLowOpacity ?? 100, + extensionSettings.statBarColorHighOpacity ?? 100 + ); html += `
${stat.name}: ${statValue}% diff --git a/src/systems/rendering/userStats.js b/src/systems/rendering/userStats.js index 31cbe16..2f11822 100644 --- a/src/systems/rendering/userStats.js +++ b/src/systems/rendering/userStats.js @@ -21,6 +21,7 @@ import { getSafeThumbnailUrl } from '../../utils/avatars.js'; import { buildInventorySummary } from '../generation/promptBuilder.js'; import { isItemLocked, setItemLock } from '../generation/lockManager.js'; import { updateFabWidgets } from '../ui/mobile.js'; +import { getStatBarColors } from '../ui/theme.js'; /** * Builds the user stats text string using custom stat names @@ -251,8 +252,9 @@ export function renderUserStats() { } } - // Create gradient from low to high color - const gradient = `linear-gradient(to right, ${extensionSettings.statBarColorLow}, ${extensionSettings.statBarColorHigh})`; + // Create gradient from low to high color with opacity + const colors = getStatBarColors(); + const gradient = `linear-gradient(to right, ${colors.low}, ${colors.high})`; // Check if stats bars section is locked const isStatsLocked = isItemLocked('userStats', 'stats'); diff --git a/src/systems/ui/desktop.js b/src/systems/ui/desktop.js index 3324c29..07e2916 100644 --- a/src/systems/ui/desktop.js +++ b/src/systems/ui/desktop.js @@ -5,6 +5,7 @@ import { i18n } from '../../core/i18n.js'; import { extensionSettings, lastGeneratedData, committedTrackerData } from '../../core/state.js'; +import { hexToRgba } from './theme.js'; /** * Helper to parse time string and calculate clock hand angles @@ -28,7 +29,7 @@ function parseTimeForClock(timeStr) { export function updateStripWidgets() { const $panel = $('#rpg-companion-panel'); const $container = $('#rpg-strip-widget-container'); - + if ($panel.length === 0 || $container.length === 0) return; // Check if strip widgets are enabled @@ -118,7 +119,7 @@ export function updateStripWidgets() { const $statsWidget = $container.find('.rpg-strip-widget-stats'); if (widgetSettings.stats?.enabled) { let allStats = []; - + // Try to get stats from tracker data first (most current) const userStatsData = lastGeneratedData?.userStats || committedTrackerData?.userStats; if (userStatsData) { @@ -131,7 +132,7 @@ export function updateStripWidgets() { console.warn('[RPG Strip Widgets] Failed to parse tracker userStats:', e); } } - + // Fallback to extensionSettings.userStats if (allStats.length === 0 && extensionSettings.userStats) { try { @@ -237,7 +238,9 @@ export function updateStripWidgets() { */ function getStatColor(value) { const lowColor = extensionSettings.statBarColorLow || '#cc3333'; + const lowOpacity = extensionSettings.statBarColorLowOpacity ?? 100; const highColor = extensionSettings.statBarColorHigh || '#33cc66'; + const highOpacity = extensionSettings.statBarColorHighOpacity ?? 100; // Simple linear interpolation between low and high colors const percent = Math.min(100, Math.max(0, value)) / 100; @@ -246,13 +249,14 @@ function getStatColor(value) { const lowRGB = hexToRgb(lowColor); const highRGB = hexToRgb(highColor); - if (!lowRGB || !highRGB) return value > 50 ? highColor : lowColor; + if (!lowRGB || !highRGB) return value > 50 ? hexToRgba(highColor, highOpacity) : hexToRgba(lowColor, lowOpacity); const r = Math.round(lowRGB.r + (highRGB.r - lowRGB.r) * percent); const g = Math.round(lowRGB.g + (highRGB.g - lowRGB.g) * percent); const b = Math.round(lowRGB.b + (highRGB.b - lowRGB.b) * percent); + const a = (lowOpacity + (highOpacity - lowOpacity) * percent) / 100; - return `rgb(${r}, ${g}, ${b})`; + return `rgba(${r}, ${g}, ${b}, ${a})`; } /** diff --git a/src/systems/ui/mobile.js b/src/systems/ui/mobile.js index b3f9a42..9a537d3 100644 --- a/src/systems/ui/mobile.js +++ b/src/systems/ui/mobile.js @@ -8,6 +8,7 @@ import { saveSettings } from '../../core/persistence.js'; import { closeMobilePanelWithAnimation, updateCollapseToggleIcon } from './layout.js'; import { setupDesktopTabs, removeDesktopTabs } from './desktop.js'; import { i18n } from '../../core/i18n.js'; +import { hexToRgba } from './theme.js'; /** * Updates the text labels of the mobile navigation tabs based on the current language. @@ -1451,7 +1452,7 @@ export function updateFabWidgets() { if (widgetSettings.attributes?.enabled) { // Check if RPG attributes are enabled in trackerConfig const showRPGAttributes = extensionSettings.trackerConfig?.userStats?.showRPGAttributes !== false; - + if (showRPGAttributes && extensionSettings.classicStats) { // Get enabled attributes from trackerConfig const configuredAttrs = extensionSettings.trackerConfig?.userStats?.rpgAttributes || []; @@ -1541,10 +1542,10 @@ export function updateFabWidgets() { e.stopPropagation(); const $this = $(this); const wasExpanded = $this.hasClass('expanded'); - + // Collapse all other expanded widgets $container.find('.rpg-fab-widget.expanded').removeClass('expanded'); - + // Toggle this one if (!wasExpanded) { $this.addClass('expanded'); @@ -1567,7 +1568,9 @@ export function updateFabWidgets() { */ function getStatColor(value) { const lowColor = extensionSettings.statBarColorLow || '#cc3333'; + const lowOpacity = extensionSettings.statBarColorLowOpacity ?? 100; const highColor = extensionSettings.statBarColorHigh || '#33cc66'; + const highOpacity = extensionSettings.statBarColorHighOpacity ?? 100; // Simple linear interpolation between low and high colors const percent = Math.min(100, Math.max(0, value)) / 100; @@ -1576,13 +1579,14 @@ function getStatColor(value) { const lowRGB = hexToRgb(lowColor); const highRGB = hexToRgb(highColor); - if (!lowRGB || !highRGB) return value > 50 ? highColor : lowColor; + if (!lowRGB || !highRGB) return value > 50 ? hexToRgba(highColor, highOpacity) : hexToRgba(lowColor, lowOpacity); const r = Math.round(lowRGB.r + (highRGB.r - lowRGB.r) * percent); const g = Math.round(lowRGB.g + (highRGB.g - lowRGB.g) * percent); const b = Math.round(lowRGB.b + (highRGB.b - lowRGB.b) * percent); + const a = (lowOpacity + (highOpacity - lowOpacity) * percent) / 100; - return `rgb(${r}, ${g}, ${b})`; + return `rgba(${r}, ${g}, ${b}, ${a})`; } /** diff --git a/src/systems/ui/promptsEditor.js b/src/systems/ui/promptsEditor.js index 45aadcc..4e47661 100644 --- a/src/systems/ui/promptsEditor.js +++ b/src/systems/ui/promptsEditor.js @@ -4,7 +4,7 @@ */ import { extensionSettings } from '../../core/state.js'; import { saveSettings } from '../../core/persistence.js'; -import { DEFAULT_HTML_PROMPT, DEFAULT_DIALOGUE_COLORING_PROMPT, DEFAULT_DECEPTION_PROMPT, DEFAULT_CYOA_PROMPT, DEFAULT_SPOTIFY_PROMPT, DEFAULT_NARRATOR_PROMPT } from '../generation/promptBuilder.js'; +import { DEFAULT_HTML_PROMPT, DEFAULT_DIALOGUE_COLORING_PROMPT, DEFAULT_DECEPTION_PROMPT, DEFAULT_OMNISCIENCE_FILTER_PROMPT, DEFAULT_CYOA_PROMPT, DEFAULT_SPOTIFY_PROMPT, DEFAULT_NARRATOR_PROMPT, DEFAULT_CONTEXT_INSTRUCTIONS_PROMPT } from '../generation/promptBuilder.js'; let $editorModal = null; let tempPrompts = null; // Temporary prompts for cancel functionality @@ -14,9 +14,11 @@ const DEFAULT_PROMPTS = { html: DEFAULT_HTML_PROMPT, dialogueColoring: DEFAULT_DIALOGUE_COLORING_PROMPT, deception: DEFAULT_DECEPTION_PROMPT, + omniscience: DEFAULT_OMNISCIENCE_FILTER_PROMPT, cyoa: DEFAULT_CYOA_PROMPT, spotify: DEFAULT_SPOTIFY_PROMPT, narrator: DEFAULT_NARRATOR_PROMPT, + contextInstructions: DEFAULT_CONTEXT_INSTRUCTIONS_PROMPT, plotRandom: 'Actually, the scene is getting stale. Introduce {{random::stakes::a plot twist::a new character::a cataclysm::a fourth-wall-breaking joke::a sudden atmospheric phenomenon::a plot hook::a running gag::an ecchi scenario::Death from Discworld::a new stake::a drama::a conflict::an angered entity::a god::a vision::a prophetic dream::Il Dottore from Genshin Impact::a new development::a civilian in need::an emotional bit::a threat::a villain::an important memory recollection::a marriage proposal::a date idea::an angry horde of villagers with pitchforks::a talking animal::an enemy::a cliffhanger::a short omniscient POV shift to a completely different character::a quest::an unexpected revelation::a scandal::an evil clone::death of an important character::harm to an important character::a romantic setup::a gossip::a messenger::a plot point from the past::a plot hole::a tragedy::a ghost::an otherworldly occurrence::a plot device::a curse::a magic device::a rival::an unexpected pregnancy::a brothel::a prostitute::a new location::a past lover::a completely random thing::a what-if scenario::a significant choice::war::love::a monster::lewd undertones::Professor Mari::a travelling troupe::a secret::a fortune-teller::something completely different::a killer::a murder mystery::a mystery::a skill check::a deus ex machina::three raccoons in a trench coat::a pet::a slave::an orphan::a psycho::tentacles::"there is only one bed" trope::accidental marriage::a fun twist::a boss battle::sexy corn::an eldritch horror::a character getting hungry, thirsty, or exhausted::horniness::a need for a bathroom break need::someone fainting::an assassination attempt::a meta narration of this all being an out of hand DND session::a dungeon::a friend in need::an old friend::a small time skip::a scene shift::Aurora Borealis, at this time of year, at this time of day, at this part of the country::a grand ball::a surprise party::zombies::foreshadowing::a Spanish Inquisition (nobody expects it)::a natural plot progression}} to make things more interesting! Be creative, but stay grounded in the setting.', plotNatural: 'Actually, the scene is getting stale. Progress it, to make things more interesting! Reintroduce an unresolved plot point from the past, or push the story further towards the current main goal. Be creative, but stay grounded in the setting.', avatar: `You are a visionary artist trapped in a cage of logic. Your mind is filled with poetry and distant horizons; however, your hands are uncontrollably focused on creating the perfect character avatar description that is faithful to the original intent, rich in detail, aesthetically pleasing, and directly usable by text-to-image models. Any ambiguity or metaphor will make you feel extremely uncomfortable. @@ -96,9 +98,11 @@ function openPromptsEditor() { html: extensionSettings.customHtmlPrompt || '', dialogueColoring: extensionSettings.customDialogueColoringPrompt || '', deception: extensionSettings.customDeceptionPrompt || '', + omniscience: extensionSettings.customOmnisciencePrompt || '', cyoa: extensionSettings.customCYOAPrompt || '', spotify: extensionSettings.customSpotifyPrompt || '', narrator: extensionSettings.customNarratorPrompt || '', + contextInstructions: extensionSettings.customContextInstructionsPrompt || '', plotRandom: extensionSettings.customPlotRandomPrompt || '', plotNatural: extensionSettings.customPlotNaturalPrompt || '', avatar: extensionSettings.avatarLLMCustomInstruction || '', @@ -111,9 +115,11 @@ function openPromptsEditor() { $('#rpg-prompt-html').val(extensionSettings.customHtmlPrompt || DEFAULT_PROMPTS.html); $('#rpg-prompt-dialogue-coloring').val(extensionSettings.customDialogueColoringPrompt || DEFAULT_PROMPTS.dialogueColoring); $('#rpg-prompt-deception').val(extensionSettings.customDeceptionPrompt || DEFAULT_PROMPTS.deception); + $('#rpg-prompt-omniscience').val(extensionSettings.customOmnisciencePrompt || DEFAULT_PROMPTS.omniscience); $('#rpg-prompt-cyoa').val(extensionSettings.customCYOAPrompt || DEFAULT_PROMPTS.cyoa); $('#rpg-prompt-spotify').val(extensionSettings.customSpotifyPrompt || DEFAULT_PROMPTS.spotify); $('#rpg-prompt-narrator').val(extensionSettings.customNarratorPrompt || DEFAULT_PROMPTS.narrator); + $('#rpg-prompt-context-instructions').val(extensionSettings.customContextInstructionsPrompt || DEFAULT_PROMPTS.contextInstructions); $('#rpg-prompt-plot-random').val(extensionSettings.customPlotRandomPrompt || DEFAULT_PROMPTS.plotRandom); $('#rpg-prompt-plot-natural').val(extensionSettings.customPlotNaturalPrompt || DEFAULT_PROMPTS.plotNatural); $('#rpg-prompt-avatar').val(extensionSettings.avatarLLMCustomInstruction || DEFAULT_PROMPTS.avatar); @@ -150,9 +156,11 @@ function savePrompts() { extensionSettings.customHtmlPrompt = $('#rpg-prompt-html').val().trim(); extensionSettings.customDialogueColoringPrompt = $('#rpg-prompt-dialogue-coloring').val().trim(); extensionSettings.customDeceptionPrompt = $('#rpg-prompt-deception').val().trim(); + extensionSettings.customOmnisciencePrompt = $('#rpg-prompt-omniscience').val().trim(); extensionSettings.customCYOAPrompt = $('#rpg-prompt-cyoa').val().trim(); extensionSettings.customSpotifyPrompt = $('#rpg-prompt-spotify').val().trim(); extensionSettings.customNarratorPrompt = $('#rpg-prompt-narrator').val().trim(); + extensionSettings.customContextInstructionsPrompt = $('#rpg-prompt-context-instructions').val().trim(); extensionSettings.customPlotRandomPrompt = $('#rpg-prompt-plot-random').val().trim(); extensionSettings.customPlotNaturalPrompt = $('#rpg-prompt-plot-natural').val().trim(); extensionSettings.avatarLLMCustomInstruction = $('#rpg-prompt-avatar').val().trim(); @@ -182,6 +190,9 @@ function restorePromptToDefault(promptType) { case 'deception': extensionSettings.customDeceptionPrompt = ''; break; + case 'omniscience': + extensionSettings.customOmnisciencePrompt = ''; + break; case 'cyoa': extensionSettings.customCYOAPrompt = ''; break; @@ -191,6 +202,9 @@ function restorePromptToDefault(promptType) { case 'narrator': extensionSettings.customNarratorPrompt = ''; break; + case 'contextInstructions': + extensionSettings.customContextInstructionsPrompt = ''; + break; case 'plotRandom': extensionSettings.customPlotRandomPrompt = ''; break; @@ -221,9 +235,11 @@ function restoreAllToDefaults() { $('#rpg-prompt-html').val(DEFAULT_PROMPTS.html); $('#rpg-prompt-dialogue-coloring').val(DEFAULT_PROMPTS.dialogueColoring); $('#rpg-prompt-deception').val(DEFAULT_PROMPTS.deception); + $('#rpg-prompt-omniscience').val(DEFAULT_PROMPTS.omniscience); $('#rpg-prompt-cyoa').val(DEFAULT_PROMPTS.cyoa); $('#rpg-prompt-spotify').val(DEFAULT_PROMPTS.spotify); $('#rpg-prompt-narrator').val(DEFAULT_PROMPTS.narrator); + $('#rpg-prompt-context-instructions').val(DEFAULT_PROMPTS.contextInstructions); $('#rpg-prompt-plot-random').val(DEFAULT_PROMPTS.plotRandom); $('#rpg-prompt-plot-natural').val(DEFAULT_PROMPTS.plotNatural); $('#rpg-prompt-avatar').val(DEFAULT_PROMPTS.avatar); @@ -235,9 +251,11 @@ function restoreAllToDefaults() { extensionSettings.customHtmlPrompt = ''; extensionSettings.customDialogueColoringPrompt = ''; extensionSettings.customDeceptionPrompt = ''; + extensionSettings.customOmnisciencePrompt = ''; extensionSettings.customCYOAPrompt = ''; extensionSettings.customSpotifyPrompt = ''; extensionSettings.customNarratorPrompt = ''; + extensionSettings.customContextInstructionsPrompt = ''; extensionSettings.customPlotRandomPrompt = ''; extensionSettings.customPlotNaturalPrompt = ''; extensionSettings.avatarLLMCustomInstruction = ''; diff --git a/src/systems/ui/theme.js b/src/systems/ui/theme.js index 81d5366..0bac819 100644 --- a/src/systems/ui/theme.js +++ b/src/systems/ui/theme.js @@ -5,6 +5,37 @@ import { extensionSettings, $panelContainer } from '../../core/state.js'; +/** + * Converts hex color and opacity percentage to rgba string + * @param {string} hex - Hex color (e.g., '#ff0000') + * @param {number} opacity - Opacity percentage (0-100) + * @returns {string} - RGBA color string + */ +export function hexToRgba(hex, opacity = 100) { + const r = parseInt(hex.slice(1, 3), 16); + const g = parseInt(hex.slice(3, 5), 16); + const b = parseInt(hex.slice(5, 7), 16); + const a = opacity / 100; + return `rgba(${r}, ${g}, ${b}, ${a})`; +} + +/** + * Gets stat bar colors with opacity applied + * @returns {{low: string, high: string}} RGBA color strings for stat bars + */ +export function getStatBarColors() { + return { + low: hexToRgba( + extensionSettings.statBarColorLow || '#cc3333', + extensionSettings.statBarColorLowOpacity ?? 100 + ), + high: hexToRgba( + extensionSettings.statBarColorHigh || '#33cc66', + extensionSettings.statBarColorHighOpacity ?? 100 + ) + }; +} + /** * Applies the selected theme to the panel. */ @@ -75,24 +106,33 @@ export function applyCustomTheme() { const colors = extensionSettings.customColors; + // Convert hex colors with opacity to rgba + const bgColor = hexToRgba(colors.bg, colors.bgOpacity ?? 100); + const accentColor = hexToRgba(colors.accent, colors.accentOpacity ?? 100); + const textColor = hexToRgba(colors.text, colors.textOpacity ?? 100); + const highlightColor = hexToRgba(colors.highlight, colors.highlightOpacity ?? 100); + + // Create shadow with 50% opacity of highlight color + const shadowColor = hexToRgba(colors.highlight, (colors.highlightOpacity ?? 100) * 0.5); + // Apply custom CSS variables as inline styles to main panel $panelContainer.css({ - '--rpg-bg': colors.bg, - '--rpg-accent': colors.accent, - '--rpg-text': colors.text, - '--rpg-highlight': colors.highlight, - '--rpg-border': colors.highlight, - '--rpg-shadow': `${colors.highlight}80` // Add alpha for shadow + '--rpg-bg': bgColor, + '--rpg-accent': accentColor, + '--rpg-text': textColor, + '--rpg-highlight': highlightColor, + '--rpg-border': highlightColor, + '--rpg-shadow': shadowColor }); // Apply custom colors to mobile toggle and thought elements const customStyles = { - '--rpg-bg': colors.bg, - '--rpg-accent': colors.accent, - '--rpg-text': colors.text, - '--rpg-highlight': colors.highlight, - '--rpg-border': colors.highlight, - '--rpg-shadow': `${colors.highlight}80` + '--rpg-bg': bgColor, + '--rpg-accent': accentColor, + '--rpg-text': textColor, + '--rpg-highlight': highlightColor, + '--rpg-border': highlightColor, + '--rpg-shadow': shadowColor }; const $mobileToggle = $('#rpg-mobile-toggle'); @@ -139,6 +179,7 @@ export function updateFeatureTogglesVisibility() { const $htmlToggle = $('#rpg-html-toggle-wrapper'); const $dialogueColoringToggle = $('#rpg-dialogue-coloring-toggle-wrapper'); const $deceptionToggle = $('#rpg-deception-toggle-wrapper'); + const $omniscienceToggle = $('#rpg-omniscience-toggle-wrapper'); const $cyoaToggle = $('#rpg-cyoa-toggle-wrapper'); const $spotifyToggle = $('#rpg-spotify-toggle-wrapper'); @@ -150,6 +191,7 @@ export function updateFeatureTogglesVisibility() { $htmlToggle.toggle(extensionSettings.showHtmlToggle); $dialogueColoringToggle.toggle(extensionSettings.showDialogueColoringToggle); $deceptionToggle.toggle(extensionSettings.showDeceptionToggle ?? true); + $omniscienceToggle.toggle(extensionSettings.showOmniscienceToggle ?? true); $cyoaToggle.toggle(extensionSettings.showCYOAToggle ?? true); $spotifyToggle.toggle(extensionSettings.showSpotifyToggle); @@ -161,6 +203,7 @@ export function updateFeatureTogglesVisibility() { const anyVisible = extensionSettings.showHtmlToggle || extensionSettings.showDialogueColoringToggle || (extensionSettings.showDeceptionToggle ?? true) || + (extensionSettings.showOmniscienceToggle ?? true) || (extensionSettings.showCYOAToggle ?? true) || extensionSettings.showSpotifyToggle || extensionSettings.showDynamicWeatherToggle || diff --git a/template.html b/template.html index a3b7499..00deaca 100644 --- a/template.html +++ b/template.html @@ -139,6 +139,15 @@
+ +
+ +
+
- +
+ + + 100% +
Color when stats are at 0%.
@@ -271,7 +300,11 @@
- +
+ + + 100% +
Color when stats are at 100%.
@@ -388,6 +421,15 @@ Display a toggle button to enable/disable special formatting of lies and deceptions crafted by the model, allowing it to easily track whenever one was committed, without showing it to the user. + + + Display a toggle button to enable/disable the omniscience filter, which instructs the AI to hide information the player character cannot perceive (events behind them, in other rooms, etc.) in special tags. + +
+ +
+ + + Injected when "Enable Omniscience Filter" is enabled. Instructs AI to separate information the player character cannot perceive into hidden filter tags. + + + +
+
+ +
+ + + Injected in Separate/External mode after the context summary. Tells the AI how to use the context. + + + +
+