Files
rpg-companion-sillytavern/CHARACTER_TRACKING_README.md
Claude 0440159089 Add comprehensive character state tracking system for {{char}}
This implements a complete Katherine RPG-based character state tracking
system that tracks the AI character ({{char}}) instead of the user.

Features:
- 40+ primary personality traits (dominance, honesty, empathy, etc.)
- 70+ secondary emotional states (happy, horny, anxious, playful, etc.)
- Physical stats tracking (energy, hunger, arousal, health, pain, etc.)
- Relationship tracking per-NPC (trust, love, attraction, thoughts, etc.)
- Clothing/outfit dynamic tracking
- Internal thoughts and contextual awareness
- LLM-driven automatic state updates based on responses
- Full UI rendering with tabbed interface

New Files:
- src/core/characterState.js (528 lines) - Core state data structure
- src/systems/generation/characterPromptBuilder.js (407 lines) - LLM prompts
- src/systems/generation/characterParser.js (456 lines) - Response parsing
- src/systems/rendering/characterStateRenderer.js (401 lines) - UI rendering
- CHARACTER_TRACKING_README.md - Complete documentation
- INTEGRATION_EXAMPLE.js - Step-by-step integration guide
- IMPLEMENTATION_SUMMARY.md - System overview and deliverables

System tracks 150+ individual stats per character with full LLM integration
for contextual, realistic character simulation.

All code is production-ready and copy-paste complete.
2025-12-05 04:39:53 +00:00

13 KiB

Character State Tracking System for SillyTavern RPG Companion

📖 Overview

This is a comprehensive character state tracking system based on the Katherine RPG framework. Unlike traditional RPG companions that track {{user}} stats, this system tracks {{char}} (the AI character's) internal states, emotions, relationships, and physical condition.

What It Tracks

🧬 Primary Traits (Personality DNA)

  • 40+ personality traits that define who the character IS
  • Core disposition (dominance, introversion, emotional stability)
  • Sexual personality (perversion, exhibitionism, masochism, etc.)
  • Moral core (honesty, empathy, corruption, etc.)
  • Intellectual traits (intelligence, wisdom, creativity)
  • These change SLOWLY - only through sustained experiences over time

🌤️ Secondary States (Emotional Weather)

  • 70+ temporary emotional states that change frequently
  • Core emotions (happy, sad, angry, anxious, etc.)
  • Arousal & sexual states (horny, frustrated, seductive, etc.)
  • Social states (lonely, confident, playful, etc.)
  • Energy & altered states (drunk, exhausted, euphoric, etc.)
  • These change FAST - minute to hour timescales

💭 Beliefs & Worldview

  • Track character's beliefs with strength and stability
  • Moral beliefs, spiritual beliefs, self-concept
  • Relationship beliefs, sexual morality
  • Beliefs can fracture during pivotal moments

🏃 Physical Stats

  • Survival needs (hunger, thirst, bladder, energy, sleep)
  • Physical condition (health, pain, temperature, cleanliness)
  • Physical attributes (strength, stamina, agility)

👗 Outfit/Clothing System

  • Dynamic tracking of what character is wearing
  • Per-piece tracking (bra, panties, shirt, pants, etc.)
  • Status tracking (worn properly, shifted, removed, torn, wet)
  • Coverage calculation (0-100% body coverage)

❤️ Relationship Tracking

  • Per-NPC detailed relationship stats
  • Core metrics: Trust, Love, Loyalty, Attraction, Respect, Fear
  • Social dynamics: Closeness, Openness, Comfort, Dependency
  • Sexual dynamics: Flirtiness, Sexual Compatibility, Satisfaction
  • Power dynamics: Dominance, Submissiveness, Possessiveness
  • Current thoughts about each person

🎬 Contextual Information

  • Location, time of day, weather
  • Present characters in the scene
  • Recent events
  • Current activity

🔄 How It Works

The Flow

  1. LLM receives current character state as input before generating a response
  2. LLM generates the character's response based on their current emotional/physical state
  3. LLM updates character states based on what happened in the response
  4. Parser extracts and applies updates to the character state
  5. UI displays updated states for the user to see

Example

Before Response:

  • Character: Katherine
  • Emotional State: Lonely (70), Anxious (40), Horny (30)
  • Relationship with User: Trust 85, Love 60, Attraction 75
  • Physical: Energy 50%, Arousal 30%
  • Location: Katherine's apartment
  • Thoughts: "I wish {{user}} would stay longer..."

LLM generates response where Katherine invites {{user}} to stay for dinner

After Response:

  • Emotional State Changes:
    • Lonely: -20 (reason: {{user}} accepted invitation)
    • Happy: +25 (reason: spending time with {{user}})
    • Hopeful: +15 (reason: possibility of intimacy)
  • Relationship Updates:
    • Trust: +5 (reason: {{user}} agreed to stay)
    • Closeness: +10 (reason: intimate setting)
    • Thoughts: "Maybe tonight is finally the night..."
  • Physical Changes:
    • Energy: -5 (reason: cooking dinner)
    • Arousal: +15 (reason: anticipation of being alone with {{user}})

📁 File Structure

src/
├── core/
│   ├── characterState.js          # Character state data structure & management
│   └── state.js                    # Original extension state (keep for compatibility)
│
├── systems/
│   ├── generation/
│   │   ├── characterPromptBuilder.js   # Generates prompts for character tracking
│   │   ├── characterParser.js          # Parses LLM responses and updates states
│   │   ├── promptBuilder.js            # Original prompt builder (still used for user tracking)
│   │   └── parser.js                   # Original parser
│   │
│   └── rendering/
│       ├── characterStateRenderer.js   # Renders character state in UI
│       └── [other renderers...]
│
└── [other modules...]

🚀 Getting Started

1. Installation

Copy all the new files into your RPG Companion extension:

  • src/core/characterState.js
  • src/systems/generation/characterPromptBuilder.js
  • src/systems/generation/characterParser.js
  • src/systems/rendering/characterStateRenderer.js

2. Integration with Main Extension

You'll need to modify index.js to integrate the character tracking system:

// Import character tracking modules
import {
    getCharacterState,
    updateCharacterState,
    initializeRelationship
} from './src/core/characterState.js';

import {
    generateCharacterTrackingPrompt,
    generateSeparateCharacterTrackingPrompt
} from './src/systems/generation/characterPromptBuilder.js';

import {
    parseAndApplyCharacterStateUpdate,
    removeCharacterStateBlock
} from './src/systems/generation/characterParser.js';

import {
    renderCharacterStateOverview,
    updateCharacterStateDisplay
} from './src/systems/rendering/characterStateRenderer.js';

3. Hook into Message Received Event

// In your onMessageReceived handler
async function onMessageReceived(data) {
    if (!extensionSettings.enabled) return;

    // Parse character state update from the response
    const stateUpdate = parseAndApplyCharacterStateUpdate(data.mes);

    // Update UI
    updateCharacterStateDisplay();

    // Optionally remove the state block from the displayed message
    if (stateUpdate) {
        data.mes = removeCharacterStateBlock(data.mes);
    }
}

4. Hook into Generation Started Event

// In your onGenerationStarted handler
async function onGenerationStarted(data) {
    if (!extensionSettings.enabled) return;

    // Add character tracking prompt to the generation
    const characterPrompt = generateCharacterTrackingPrompt();

    // Inject into the prompt (method depends on your setup)
    // Example: use extension_prompts system
    setExtensionPrompt(
        'CHARACTER_STATE_TRACKING',
        characterPrompt,
        extension_prompt_types.AFTER_SCENARIO,
        0, // position
        false, // scan depth
        extension_prompt_roles.SYSTEM
    );
}

5. Add UI Container

Add this to your template.html:

<div id="rpg-character-state-container" class="rpg-section">
    <!-- Character state will be rendered here -->
</div>

🎨 Customization

Choosing Which States to Track

You can customize which states to track by modifying characterState.js:

// Focus on emotional tracking only
export let characterState = {
    characterName: null,
    secondaryStates: {
        happy: 50,
        sad: 0,
        angry: 0,
        horny: 0
        // Add only the emotions you care about
    },
    // Remove sections you don't need
};

Customizing the Prompt

Edit characterPromptBuilder.js to change how the LLM is instructed:

// Simplify the tracking instructions
instructions += `Update only these states:\n`;
instructions += `- Emotions: happy, sad, angry, aroused\n`;
instructions += `- Energy level\n`;
instructions += `- Thoughts about {{user}}\n`;

Styling the UI

Add custom CSS for the character state display:

.rpg-character-overview {
    background: rgba(0, 0, 0, 0.7);
    border-radius: 8px;
    padding: 15px;
}

.rpg-emotion-item {
    display: flex;
    align-items: center;
    margin-bottom: 8px;
}

.rpg-relationship-card {
    background: rgba(255, 255, 255, 0.05);
    padding: 10px;
    border-radius: 5px;
    margin-bottom: 10px;
}

💡 Advanced Features

Automatic Character Initialization

When starting a new chat, you can automatically initialize the character's personality traits from their character card:

import { generateCharacterInitializationPrompt } from './src/systems/generation/characterPromptBuilder.js';
import { parseCharacterInitialization } from './src/systems/generation/characterParser.js';

async function initializeCharacterFromCard() {
    const prompt = await generateCharacterInitializationPrompt();

    // Send to LLM (using your API client)
    const response = await generateRaw(messages, api, false);

    // Parse and apply
    const traits = parseCharacterInitialization(response);
    if (traits) {
        updateCharacterState({ primaryTraits: traits });
    }
}

Relationship Analysis

Automatically analyze relationships when new characters appear:

import { generateRelationshipAnalysisPrompt } from './src/systems/generation/characterPromptBuilder.js';
import { parseRelationshipAnalysis } from './src/systems/generation/characterParser.js';

async function analyzeRelationship(npcName) {
    const prompt = generateRelationshipAnalysisPrompt(npcName);

    // Send to LLM
    const response = await generateRaw([{role: 'user', content: prompt}], api, false);

    // Parse and apply
    const relationshipData = parseRelationshipAnalysis(response);
    if (relationshipData) {
        updateRelationship(npcName, relationshipData);
    }
}

Persistent State Storage

Save character state to chat metadata:

import { getCharacterState } from './src/core/characterState.js';

function saveCharacterState() {
    const charState = getCharacterState();

    // Save to SillyTavern chat metadata
    chat_metadata.rpg_character_state = charState;
    saveChatDebounced();
}

function loadCharacterState() {
    if (chat_metadata.rpg_character_state) {
        setCharacterState(chat_metadata.rpg_character_state);
    }
}

📊 State Change Guidelines

Emotional States (Secondary States)

Small changes (+/- 5-15):

  • Normal conversation
  • Minor events
  • Gradual mood shifts

Medium changes (+/- 20-40):

  • Significant events
  • Important revelations
  • Strong emotional moments

Large changes (+/- 50+):

  • Life-changing events
  • Trauma
  • Peak experiences

Relationship Changes

Trust:

  • Vulnerability rewarded: +5 to +15
  • Promise kept: +5
  • Betrayal: -30 to -60

Love:

  • Romantic moment: +5 to +20
  • Declaration of feelings: +20 to +40
  • Heartbreak: -40 to -80

Attraction:

  • Attractive behavior: +5 to +15
  • Sexual tension: +10 to +30
  • Turn-off: -10 to -30

🐛 Troubleshooting

Character state not updating

  1. Check console for parsing errors
  2. Verify the LLM is including the state update block in responses
  3. Make sure the format matches exactly what the parser expects

UI not displaying

  1. Check that the container #rpg-character-state-container exists
  2. Verify jQuery selectors are working
  3. Check browser console for JavaScript errors

LLM not following format

  1. Adjust the prompt to be more explicit
  2. Use a better model (Claude Sonnet 4.5, GPT-4, etc.)
  3. Increase temperature slightly for more creative state updates
  4. Add examples to the prompt

📚 Examples

Example Character State Update (from LLM)

Katherine's State Update
---

**Emotional Changes**:
- happy: +20 (reason: {{user}} complimented her cooking)
- confident: +10 (reason: successful dinner preparation)
- horny: +15 (reason: intimate candlelit atmosphere with {{user}})
- anxious: -15 (reason: {{user}}'s presence is comforting)

**Physical Changes**:
- Energy: -10 (reason: cooking and cleaning)
- Arousal: +20 (reason: anticipation of being alone with {{user}})

**Relationship Updates**:
- {{user}}:
  - Trust: +5 (reason: {{user}} was vulnerable about their past)
  - Closeness: +15 (reason: deep conversation during dinner)
  - Attraction: +10 (reason: {{user}} looked particularly attractive tonight)
  - Thoughts: "I want this moment to never end. Maybe I should make a move..."

**Scene Context**:
- Location: Katherine's apartment, dining room
- Time: 8:30 PM
- Present: {{user}}, Katherine

**Katherine's Thoughts**:
"This is perfect. The wine, the candlelight, {{user}} opening up to me... I can feel the tension between us. Should I reach across the table and touch their hand? My heart is racing just thinking about it."

🤝 Contributing

This system is based on the Katherine RPG Complete Master document. If you want to extend it:

  1. Add new state categories to characterState.js
  2. Update characterPromptBuilder.js to instruct the LLM about new states
  3. Update characterParser.js to parse new state formats
  4. Update characterStateRenderer.js to display new states

📄 License

This extends the RPG Companion SillyTavern extension. Follow the same license as the main extension.


🙏 Credits

  • Katherine RPG System: Original comprehensive character simulation framework
  • RPG Companion: Base extension by Marysia
  • Character State Tracking: Integration of Katherine RPG into SillyTavern

📞 Support

If you encounter issues:

  1. Check the console for error messages
  2. Verify your LLM model supports structured outputs
  3. Review the prompt and parsing logic
  4. Open an issue on GitHub with:
    • Error messages
    • LLM response example
    • What you expected vs what happened

Enjoy deep, realistic character simulation with full emotional and psychological tracking! 🎭