A SillyTavern extension that extracts structured game state from AI responses and displays it in a glassmorphic side panel. Built for tabletop RPG and interactive fiction campaigns.
Campaign Studio creates a bidirectional data loop between you and your AI — it parses campaign data from bot messages (inventory, world state, faction standings) into an at-a-glance panel, and injects the current game state back into the conversation so the AI always knows where things stand.
- Automatic data extraction — Parses
<campaign_data>YAML blocks from AI responses (with<details><summary>fallback for legacy bots) - Dockable side panel — Right, left, or bottom positioning with slide animations. Dynamically fills the gap between the chat column and viewport edge
- Preset system — JSON-configurable presets define what data to track and how to display it. Ships with 5 built-in presets: Universal (genre-agnostic default), Vigil Falls (gothic estate), Forgotten Realms (D&D 5e), Cyberpunk (neon-noir), and Cozy Life (slice-of-life)
- Inventory tracker — Item lists with tag pills, currency notes, NEW/removed indicators
- World state display — Key-value data with specialized renderers: location breadcrumbs, character pills, atmosphere text, diary quotes
- Faction standing bars — Center-zero bidirectional bars with delta indicators showing change direction and magnitude
- Location tracker — Breadcrumb display of current location path with recent location history
- Session timeline — Scrollable event log showing all state changes (items gained/lost, faction shifts, location moves)
- Dice roller — Standard RPG dice notation (2d6+3), preset buttons, roll history, context labels
- AI prompt injection — Automatically injects YAML schema instructions and current game state into the AI's context
- Toggleable game rules — Each preset ships with categorized rule snippet cards (combat, inventory, factions, tone, etc.) that you can toggle on/off. Add your own custom rules via a separate textarea
- Visual preset editor — Full-screen modal for creating and editing presets. Paste a sample bot message to auto-detect fields, assign them to sections, and preview the result live — no JSON editing required. Includes a rules editor for adding/editing rule snippets and injection config for system prompt tuning
- Dark glass design — König-inspired glassmorphic dark palette with Space Grotesk sans-serif and JetBrains Mono monospace typography, decorative section dividers, noise texture overlays, customizable accent colors per preset
-
Navigate to your SillyTavern installation's extensions directory:
cd SillyTavern/data/default-user/extensions/ -
Clone the repository:
git clone https://github.com/hype-hosting/SillyTavern-Campaign-Studio.git
-
Restart SillyTavern or reload the page.
-
Enable Campaign Studio in Extensions > Campaign Studio > check Enable Extension.
Open the SillyTavern Extensions panel (puzzle piece icon) and find the Campaign Studio section.
| Setting | Description |
|---|---|
| Enable Extension | Master toggle for the entire extension |
| Active Preset | Which campaign preset to use for parsing and display |
| Edit / New / Import | Buttons next to the preset dropdown — edit the active preset, create a new one, or import a .json preset file |
| Panel Position | Right (default), Left, or Bottom |
| Setting | Description |
|---|---|
| Accent Color | Color picker for the accent color used throughout the panel UI |
| Setting | Description |
|---|---|
| Dice Roller | Show/hide the dice roller in the panel's bottom toolbar |
| Setting | Description |
|---|---|
| Prompt Injection | Inject YAML format instructions into the system prompt so the AI knows how to output structured data |
| State Context | Send current game state to the AI before each message generation |
| Output Format | YAML Drawers (recommended), Details Blocks (legacy), or Both |
| Game Rules | Toggleable rule snippet cards shipped with each preset. Enable/disable individual rules, expand to read them, and add custom rules below |
| Preset | Genre | Tracks |
|---|---|---|
| Universal | Genre-agnostic (default) | Inventory, character status (health, conditions, resources, currency), world state (location, time, atmosphere, NPCs, objectives), relationships |
| Vigil Falls | Gothic estate mystery | Items, world state (weather, path, characters, diary), Order standings |
| Forgotten Realms | D&D 5e high fantasy | Inventory, character status (HP, Level, XP, Gold, conditions, spell slots), ability scores (STR, DEX, CON, INT, WIS, CHA), world state, faction standings (Harpers, Zhentarim, etc.) |
| Cyberpunk | Neon-noir dystopia | Gear & cyberware, status (HP, humanity, eddies), world state (districts, threat level), reputation (fixers, corpos, gangs) |
| Cozy Life | Modern slice-of-life | Belongings, social world (location, mood, people), vibes (energy, social battery, stress, happiness, hunger) |
Each preset includes ready-to-use game rule snippets — toggle them on/off in the settings panel. You can also add your own custom rules per preset.
Campaign Studio instructs the AI to output game state in YAML inside <campaign_data> XML tags, wrapped in a collapsed HTML drawer:
<details><summary>⬡</summary><campaign_data> items:
- Ladonian Gloves (worn)
- Iron Skeleton Key (quest)
- Tattered Journal world: Weather: Cold rain, fog rolling in Intent: Investigate the old mine Path: Ravenwood Castle → Harbottle (The Black Boar) Characters: Barmaid, Drunk Miner, Hooded Stranger Vigil Falls's Diary: The air in Harbottle tastes of copper and lies. Affinity Level: 0 Affinity Notes: Neutral orders: Weaver: 0.00 Shroud: 0.00 Physik: 0.00 Bloom: 0.00 </campaign_data>
</details>
When Prompt Injection is enabled, the extension automatically adds format instructions to the system prompt — you don't need to put formatting rules in your character card.
Note: The section IDs in
<campaign_data>vary by preset. The example above shows Vigil Falls (items,world,orders). Forgotten Realms usesinventory,character,world,factions. Cyberpunk usesgear,status,world,rep. The AI is told the correct schema automatically.
When State Context is enabled, the extension sends the current game state (all tracked sections + any pending dice rolls) to the AI before each generation. This means the AI always has access to current inventory, location, faction standings, and recent dice rolls.
The easiest way to create or customize a preset is through the built-in visual editor:
- Edit an existing preset: Click the pencil button (✎) next to the preset dropdown. Built-in presets are automatically cloned as a "(Custom)" copy so the originals stay untouched.
- Create from scratch: Click the + button to open a blank editor.
- Import a file: Click the ↑ button to load a
.jsonpreset file.
The editor has two columns:
- Left — Configuration: Set the preset name, description, marker prefix, and accent color. Add/remove/reorder sections, configure their match patterns, types, field renderers (with separator inputs for breadcrumbs/pills), and display options (colors, range, delta, inverted keys for numeric bars). Below sections: a rules editor for adding/editing/reordering rule snippets, and an injection config panel for system prompt, schema/state toggles, and state depth.
- Right — Field Mapper: Paste a raw bot message (HTML or plain text) and click Parse Sample. The extension detects all trackable fields and lets you assign each one to a section with a dropdown. YAML fields are auto-assigned to matching sections when possible. Fields are auto-assigned a renderer based on their name (e.g., "Location" gets breadcrumb, "Weather" gets atmospheric text, "Strength" gets numeric-badge). A live preview at the bottom shows how the data will render in the panel.
Click Save to validate, persist, and activate the preset. Click Export to download the preset as a .json file you can share.
For advanced users, presets are JSON files that define what data to extract and how to display it. Place custom presets in src/presets/builtin/ or save them via the editor/API.
{
"id": "my-campaign",
"name": "My Campaign",
"version": "1.0.0",
"description": "Description of your campaign",
"author": "your-name",
"marker": {
"type": "details-summary",
"prefix": "❖"
},
"sections": [
{
"id": "items",
"match": "Items",
"matchMode": "endsWith",
"type": "inventory",
"icon": "backpack",
"parse": {
"format": "markdown-list",
"tagPattern": "\\(([^)]+)\\)"
}
},
{
"id": "world",
"match": "World",
"matchMode": "exact",
"type": "key-value",
"icon": "globe",
"parse": {
"format": "key-value",
"separator": ":"
},
"fields": {
"Location": { "renderer": "breadcrumb", "separator": "→" },
"NPCs": { "renderer": "character-pills", "separator": "," },
"Weather": { "renderer": "text-atmosphere" },
"Journal": { "renderer": "quote-block" }
}
},
{
"id": "factions",
"match": "Faction Standing",
"matchMode": "exact",
"type": "numeric-bars",
"icon": "shield",
"parse": {
"format": "key-value-numeric",
"separator": ":",
"range": [-1.0, 1.0]
},
"display": {
"colorNegative": "#e05555",
"colorPositive": "#7c6bde",
"showDelta": true
}
}
],
"rules": [
{
"id": "combat",
"name": "Combat & Dice",
"icon": "⚔",
"enabled": true,
"content": "Rules text injected into the AI prompt when this snippet is enabled..."
}
],
"injection": {
"systemPrompt": "Base output instruction — track game state using <campaign_data> YAML blocks...",
"includeSchema": true,
"includeCurrentState": true,
"stateDepth": 1
},
"theme": {
"accentColor": "#7c6bde"
}
}| Type | Purpose | Data format |
|---|---|---|
inventory |
Item/equipment lists | Array of items with optional tags in parentheses |
key-value |
World state, character info | Key-value pairs with string values |
numeric-bars |
Faction standings, skill scores | Key-value pairs with numeric values |
| Format | Purpose |
|---|---|
markdown-list |
Inventory items — - Item Name (tag1, tag2) |
key-value |
Key-value pairs — Key: Value |
key-value-numeric |
Numeric pairs — Faction: 0.25 |
stat-block |
Emoji-labeled stats — ❤️ HP: 25/30 or pipe-separated `⚔️ STR 14 |
| Mode | Behavior |
|---|---|
exact |
Summary text must exactly match the pattern |
contains |
Summary text must contain the pattern (default) |
endsWith |
Summary text must end with the pattern |
regex |
Pattern is treated as a regular expression |
| Renderer | Description |
|---|---|
text |
Plain text (default) |
text-atmosphere |
Styled atmospheric/flavor text |
breadcrumb |
Path segments separated by a configurable separator |
character-pills |
Names displayed as clickable-looking pill buttons |
quote-block |
Blockquote styling for diary entries, quotes |
numeric-badge |
Colored positive/negative numeric badge |
backpack, globe, shield, scroll, clock, map
The rules array defines toggleable game mechanic instructions that ship with your preset. Each snippet appears as a card in the settings panel that users can enable/disable.
| Field | Type | Description |
|---|---|---|
id |
string | Unique identifier for the rule |
name |
string | Display name shown on the card |
icon |
string | Emoji icon shown next to the name |
enabled |
boolean | Whether the rule is on by default |
content |
string | The actual rule text injected into the AI prompt |
Users can override the default enabled/disabled state per rule. Their overrides persist across sessions.
Click the Dice button at the bottom of the panel to open the roller.
- Preset buttons: d4, d6, d8, d10, d12, d20, d100
- Custom notation: Type any standard notation like
2d6+3,1d20-1,3d8 - Context label: Optionally describe the roll (e.g., "Perception check") — this is included when the state is sent to the AI
- Roll history: Last 10 rolls displayed below the result
Dice rolls are automatically included in the state context sent to the AI on the next generation.
- SillyTavern: Requires a recent version with extension support and the
setExtensionPromptAPI - Browsers: Modern browsers with ES module and
backdrop-filtersupport - AI models: Works with any model that can follow structured output instructions. Best results with Claude, GPT-4, and other instruction-following models
- Author: hype-hosting
- Design: Glassmorphism panel inspired by SillyTavern-Lovense-Cloud panel patterns
- Architecture: Data extraction patterns informed by RPG Companion