From 67df7034eba901d37055e479ecea52aa6ecef470 Mon Sep 17 00:00:00 2001 From: Spicy_Marinara Date: Sat, 22 Nov 2025 23:36:39 +0100 Subject: [PATCH] Add custom HTML prompt editor, skills blur handler, and include skills in separate mode --- index.js | 19 ++++++++++++++++++- src/core/state.js | 1 + src/systems/features/plotProgression.js | 5 ++++- src/systems/generation/injector.js | 11 ++++++++--- src/systems/generation/promptBuilder.js | 16 +++++++++++++++- src/systems/rendering/userStats.js | 17 +++++++++++++++++ src/systems/ui/trackerEditor.js | 2 ++ template.html | 22 ++++++++++++++++++++++ 8 files changed, 87 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index 1fa66be..6d8b462 100644 --- a/index.js +++ b/index.js @@ -117,6 +117,7 @@ import { setupClassicStatsButtons } from './src/systems/features/classicStats.js import { ensureHtmlCleaningRegex, detectConflictingRegexScripts } from './src/systems/features/htmlCleaning.js'; import { setupMemoryRecollectionButton, updateMemoryRecollectionButton } from './src/systems/features/memoryRecollection.js'; import { initLorebookLimiter } from './src/systems/features/lorebookLimiter.js'; +import { DEFAULT_HTML_PROMPT } from './src/systems/generation/promptBuilder.js'; // Integration modules import { @@ -333,6 +334,18 @@ async function initUI() { saveSettings(); }); + $('#rpg-custom-html-prompt').on('input', function() { + extensionSettings.customHtmlPrompt = $(this).val().trim(); + saveSettings(); + }); + + $('#rpg-restore-default-html-prompt').on('click', function() { + extensionSettings.customHtmlPrompt = ''; + $('#rpg-custom-html-prompt').val(''); + saveSettings(); + toastr.success('HTML prompt restored to default'); + }); + $('#rpg-skip-guided-mode').on('change', function() { extensionSettings.skipInjectionsForGuided = String($(this).val()); saveSettings(); @@ -435,7 +448,11 @@ async function initUI() { $('#rpg-toggle-thoughts-in-chat').prop('checked', extensionSettings.showThoughtsInChat); $('#rpg-toggle-always-show-bubble').prop('checked', extensionSettings.alwaysShowThoughtBubble); $('#rpg-toggle-html-prompt').prop('checked', extensionSettings.enableHtmlPrompt); - $('#rpg-toggle-plot-buttons').prop('checked', extensionSettings.enablePlotButtons); + + // Set default HTML prompt as actual text if no custom prompt exists + $('#rpg-custom-html-prompt').val(extensionSettings.customHtmlPrompt || DEFAULT_HTML_PROMPT); + + $('#rpg-toggle-plot-buttons').prop('checked', extensionSettings.enablePlotButtons); $('#rpg-toggle-plot-buttons').prop('checked', extensionSettings.enablePlotButtons); $('#rpg-toggle-plot-buttons').prop('checked', extensionSettings.enablePlotButtons); $('#rpg-toggle-animations').prop('checked', extensionSettings.enableAnimations); $('#rpg-stat-bar-color-low').val(extensionSettings.statBarColorLow); $('#rpg-stat-bar-color-high').val(extensionSettings.statBarColorHigh); diff --git a/src/core/state.js b/src/core/state.js index 4802b65..64cbf68 100644 --- a/src/core/state.js +++ b/src/core/state.js @@ -21,6 +21,7 @@ export let extensionSettings = { showInventory: true, // Show inventory section (v2 system) showThoughtsInChat: true, // Show thoughts overlay in chat enableHtmlPrompt: false, // Enable immersive HTML prompt injection + customHtmlPrompt: '', // Custom HTML prompt text (empty = use default) skipInjectionsForGuided: 'none', // skip injections for instruct injections and quiet prompts (GuidedGenerations compatibility) enablePlotButtons: true, // Show plot progression buttons above chat input panelPosition: 'right', // 'left', 'right', or 'top' diff --git a/src/systems/features/plotProgression.js b/src/systems/features/plotProgression.js index 7a414fe..ac27368 100644 --- a/src/systems/features/plotProgression.js +++ b/src/systems/features/plotProgression.js @@ -5,6 +5,7 @@ import { togglePlotButtons } from '../ui/layout.js'; import { extensionSettings, setIsPlotProgression } from '../../core/state.js'; +import { DEFAULT_HTML_PROMPT } from '../generation/promptBuilder.js'; import { Generate } from '../../../../../../../script.js'; /** @@ -94,7 +95,9 @@ export async function sendPlotProgression(type) { // Add HTML prompt if enabled if (extensionSettings.enableHtmlPrompt) { - prompt += '\n\n' + `If appropriate, include inline HTML, CSS, and JS segments whenever they enhance visual storytelling (e.g., for in-world screens, posters, books, letters, signs, crests, labels, etc.). Style them to match the setting's theme (e.g., fantasy, sci-fi), keep the text readable, and embed all assets directly (using inline SVGs only with no external scripts, libraries, or fonts). Use these elements freely and naturally within the narrative as characters would encounter them, including animations, 3D effects, pop-ups, dropdowns, websites, and so on. Do not wrap the HTML/CSS/JS in code fences!`; + // Use custom HTML prompt if set, otherwise use default + const htmlPromptText = extensionSettings.customHtmlPrompt || DEFAULT_HTML_PROMPT; + prompt += '\n\n' + htmlPromptText; } // Set flag to indicate we're doing plot progression diff --git a/src/systems/generation/injector.js b/src/systems/generation/injector.js index eacd06e..b9831d1 100644 --- a/src/systems/generation/injector.js +++ b/src/systems/generation/injector.js @@ -18,7 +18,8 @@ import { parseUserStats } from './parser.js'; import { generateTrackerExample, generateTrackerInstructions, - generateContextualSummary + generateContextualSummary, + DEFAULT_HTML_PROMPT } from './promptBuilder.js'; /** @@ -214,7 +215,9 @@ export function onGenerationStarted(type, data) { // Inject HTML prompt separately at depth 0 if enabled (prevents duplication on swipes) if (extensionSettings.enableHtmlPrompt && !shouldSuppress) { - const htmlPrompt = `\nIf appropriate, include inline HTML, CSS, and JS segments whenever they enhance visual storytelling (e.g., for in-world screens, posters, books, letters, signs, crests, labels, etc.). Style them to match the setting's theme (e.g., fantasy, sci-fi), keep the text readable, and embed all assets directly (using inline SVGs only with no external scripts, libraries, or fonts). Use these elements freely and naturally within the narrative as characters would encounter them, including animations, 3D effects, pop-ups, dropdowns, websites, and so on. Do not wrap the HTML/CSS/JS in code fences!`; + // Use custom HTML prompt if set, otherwise use default + const htmlPromptText = extensionSettings.customHtmlPrompt || DEFAULT_HTML_PROMPT; + const htmlPrompt = `\n${htmlPromptText}`; setExtensionPrompt('rpg-companion-html', htmlPrompt, extension_prompt_types.IN_CHAT, 0, false); // console.log('[RPG Companion] Injected HTML prompt at depth 0 for together mode'); @@ -247,7 +250,9 @@ Ensure these details naturally reflect and influence the narrative. Character be // Inject HTML prompt separately at depth 0 if enabled (same as together mode pattern) if (extensionSettings.enableHtmlPrompt && !shouldSuppress) { - const htmlPrompt = `\nIf appropriate, include inline HTML, CSS, and JS segments whenever they enhance visual storytelling (e.g., for in-world screens, posters, books, letters, signs, crests, labels, etc.). Style them to match the setting's theme (e.g., fantasy, sci-fi), keep the text readable, and embed all assets directly (using inline SVGs only with no external scripts, libraries, or fonts). Use these elements freely and naturally within the narrative as characters would encounter them, including animations, 3D effects, pop-ups, dropdowns, websites, and so on. Do not wrap the HTML/CSS/JS in code fences!`; + // Use custom HTML prompt if set, otherwise use default + const htmlPromptText = extensionSettings.customHtmlPrompt || DEFAULT_HTML_PROMPT; + const htmlPrompt = `\n${htmlPromptText}`; setExtensionPrompt('rpg-companion-html', htmlPrompt, extension_prompt_types.IN_CHAT, 0, false); // console.log('[RPG Companion] Injected HTML prompt at depth 0 for separate mode'); diff --git a/src/systems/generation/promptBuilder.js b/src/systems/generation/promptBuilder.js index aef365b..fc064b8 100644 --- a/src/systems/generation/promptBuilder.js +++ b/src/systems/generation/promptBuilder.js @@ -10,6 +10,11 @@ import { extensionSettings, committedTrackerData, FEATURE_FLAGS } from '../../co // Type imports /** @typedef {import('../../types/inventory.js').InventoryV2} InventoryV2 */ +/** + * Default HTML prompt text + */ +export const DEFAULT_HTML_PROMPT = `If appropriate, include inline HTML, CSS, and JS segments whenever they enhance visual storytelling (e.g., for in-world screens, posters, books, letters, signs, crests, labels, etc.). Style them to match the setting's theme (e.g., fantasy, sci-fi), keep the text readable, and embed all assets directly (using inline SVGs only with no external scripts, libraries, or fonts). Use these elements freely and naturally within the narrative as characters would encounter them, including animations, 3D effects, pop-ups, dropdowns, websites, and so on. Do not wrap the HTML/CSS/JS in code fences!`; + /** * Builds a formatted inventory summary for AI context injection. * Converts v2 inventory structure to multi-line plaintext format. @@ -313,7 +318,9 @@ export function generateTrackerInstructions(includeHtmlPrompt = true, includeCon instructions += `\n`; } - instructions += `If appropriate, include inline HTML, CSS, and JS segments whenever they enhance visual storytelling (e.g., for in-world screens, posters, books, letters, signs, crests, labels, etc.). Style them to match the setting's theme (e.g., fantasy, sci-fi), keep the text readable, and embed all assets directly (using inline SVGs only with no external scripts, libraries, or fonts). Use these elements freely and naturally within the narrative as characters would encounter them, including animations, 3D effects, pop-ups, dropdowns, websites, and so on. Do not wrap the HTML/CSS/JS in code fences!`; + // Use custom HTML prompt if set, otherwise use default + const htmlPrompt = extensionSettings.customHtmlPrompt || DEFAULT_HTML_PROMPT; + instructions += htmlPrompt; } return instructions; @@ -423,6 +430,13 @@ export function generateRPGPromptText() { } promptText += `\n`; } + + // Add current skills to the previous data context + const skillsSection = extensionSettings.trackerConfig?.userStats?.skillsSection; + if (skillsSection?.enabled && skillsSection.customFields && skillsSection.customFields.length > 0) { + const skillsList = skillsSection.customFields.join(', '); + promptText += `Skills: ${skillsList}\n\n`; + } } if (extensionSettings.showInfoBox) { diff --git a/src/systems/rendering/userStats.js b/src/systems/rendering/userStats.js index 97fad33..14a3e63 100644 --- a/src/systems/rendering/userStats.js +++ b/src/systems/rendering/userStats.js @@ -293,6 +293,23 @@ export function renderUserStats() { updateMessageSwipeData(); }); + // Add event listener for skills editing + $('.rpg-skills-value.rpg-editable').on('blur', function() { + const value = $(this).text().trim(); + extensionSettings.userStats.skills = value || 'None'; + + // Rebuild userStats text + const statsText = buildUserStatsText(); + + // Update BOTH lastGeneratedData AND committedTrackerData + lastGeneratedData.userStats = statsText; + committedTrackerData.userStats = statsText; + + saveSettings(); + saveChatData(); + updateMessageSwipeData(); + }); + // Add event listeners for stat name editing $('.rpg-editable-stat-name').on('blur', function() { const field = $(this).data('field'); diff --git a/src/systems/ui/trackerEditor.js b/src/systems/ui/trackerEditor.js index 5da8a53..86192ec 100644 --- a/src/systems/ui/trackerEditor.js +++ b/src/systems/ui/trackerEditor.js @@ -419,11 +419,13 @@ function setupUserStatsListeners() { $('#rpg-skills-label').off('blur').on('blur', function() { extensionSettings.trackerConfig.userStats.skillsSection.label = $(this).val(); + saveSettings(); }); $('#rpg-skills-fields').off('blur').on('blur', function() { const fields = $(this).val().split(',').map(f => f.trim()).filter(f => f); extensionSettings.trackerConfig.userStats.skillsSection.customFields = fields; + saveSettings(); }); } diff --git a/template.html b/template.html index c19a5ec..ff8c8fa 100644 --- a/template.html +++ b/template.html @@ -267,6 +267,28 @@ When set, the extension will not inject tracker prompts, examples, or HTML instructions according to the selected mode when a guided generation (via `instruct` or `quiet_prompt`) is detected. Useful when using GuidedGenerations or similar extensions. + +
+ + + +
+ +
+ + Customize the HTML prompt injected when "Enable Immersive HTML" is enabled. The default prompt is shown above - you can edit it directly or replace it entirely. Click "Restore Default" to reset. This affects all generation modes (together, separate, and plot progression). + +
+