Files
interactive-story/backend/app/seed_data/04-rpg-world-state.json
T
parththakkar106andClaude Opus 5 57c24a07d8 Redesign the library UI and add scenario cover art
Rework the home page into a single landing surface and give the app a
consistent visual language, chosen as "illuminated tome" over two other
pitched directions because it builds on the existing Cinzel + gold identity
instead of replacing it.

Home is now Continue (up to 4 in-progress stories, each showing where you
left off) over a scenario shelf, each section with a "See all" link. The
full adventure list moves to /adventures.

Scenario cover art has three tiers, in precedence order: an uploaded picture
(downscaled client-side to 400px WebP before storing), an emoji, or gradient
art generated from a hash of the title so no card is ever an empty box.
Adventures inherit their scenario's art. Images live in the row rather than
on disk because Render's free tier has no persistent volume, and it keeps
export bundles self-contained; list responses carry a cacheable
/api/scenarios/{id}/image URL rather than the base64.

Also: ambient drifting motes behind the app, loading skeletons, staggered
card entrance, ornamental scene breaks and a drop cap in the story, a
"Weaving" thinking indicator, and a toast system replacing every alert().

Two fixes found along the way:

- Importing a scenario bundle with no "tags" key returned a 500. Column
  defaults are not applied until flush, so the attribute was still None
  when the width clamp sliced it.
- Anything meaning "the story's latest narration" was missing action type
  "start", which is the only text a freshly created adventure has, so new
  adventures looked empty. Collected as NARRATION_TYPES.

Migrations 30 and 31 add scenarios.image and scenarios.icon; both are
additive with a '' default and were verified against a database stamped at
29. vite.config.js now reads AIDND_API_PORT so the recurring port-8000
clash with another local app needs no file edit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FGY1yvzSeKgTtRfeVtDmx
2026-07-26 13:17:46 +05:30

91 lines
5.0 KiB
JSON

{
"title": "[Demo] The Bandit Camp (RPG world state)",
"description": "A short RPG scene showing the built-in world-state system: the AI tracks your HP and mana, an in-game day counter, an NPC ally's health and trust, and story milestones. No scripting — the engine keeps the numbers honest. Open the World State panel on the left to watch it change.",
"prompt": "Dawn breaks grey over the treeline as you and Gwen crouch at the edge of the bandit camp. Smoke curls from a dying fire; three bedrolls lie empty. Somewhere ahead, the stolen caravan strongbox waits.\n\nGwen checks her bowstring and looks to you. \"Quiet, or loud?\"",
"memory": "The player and Gwen, a loyal ranger ally, are raiding a bandit camp to recover a stolen strongbox. The player is a capable adventurer. This is a dangerous but winnable encounter.",
"authors_note": "Keep it tense and consequential. Reckless moves should cost health; clever ones should pay off. Gwen reacts to how the player treats her.",
"ai_instructions": "Write in second person, present tense. End each reply where the player can act. Let the world state guide the fiction — if the player is badly hurt, show it. Reflect what happens in the numbers each turn: change health when someone is hurt or healed, shift Gwen's trust based on how the player treats her, move the leader's aggression as the situation escalates or calms, and mark milestones as they are reached.",
"tags": "demo, rpg, world-state, combat, short",
"icon": "🏹",
"stat_schema": {
"world": {
"day": { "type": "counter", "min": 1, "initial": 1, "desc": "Which in-game day it is; only ever counts up." }
},
"player": {
"hp": {
"desc": "The player's physical health. At 0 they fall.",
"min": 0, "max": 100, "initial": 100, "max_delta_per_turn": 35,
"bands": [[0, 1, "dead"], [1, 25, "gravely wounded"], [25, 50, "hurt"],
[50, 80, "scratched"], [80, 100, "healthy"], [100, 101, "full health"]]
},
"mana": {
"desc": "Magical energy for spells; spent casting, restored by resting.",
"min": 0, "max": 50, "initial": 30, "max_delta_per_turn": 25,
"bands": [[0, 10, "drained"], [10, 30, "steady"], [30, 51, "brimming"]]
},
"outfit": {
"type": "text", "initial": "worn leather armor, travel-stained",
"desc": "What the player is currently wearing/carrying visibly; update it when gear is gained, lost, or changed."
}
},
"flags": {
"alarm_raised": { "desc": "True once the bandits know they're under attack; stealth is blown.", "initial": false },
"player_hidden": { "desc": "True while the player is out of sight in cover.", "initial": true }
},
"npcs": {
"gwen": {
"name": "Gwen",
"keys": "Gwen, ranger, her",
"desc": "A loyal ranger and the player's ally. Quick with a bow, dry-humoured, fiercely protective. Her trust rises when the player fights smart and watches her back, and falls when they are reckless with her life.",
"stats": {
"health": {
"desc": "Gwen's physical health.",
"min": 0, "max": 100, "initial": 100, "max_delta_per_turn": 35,
"bands": [[0, 1, "dead"], [1, 25, "gravely wounded"], [25, 50, "hurt"],
[50, 80, "scratched"], [80, 101, "healthy"]]
},
"trust": {
"desc": "How much Gwen trusts the player; rises with smart, loyal play and falls with recklessness.",
"min": -100, "max": 100, "initial": 20, "max_delta_per_turn": 20,
"bands": [[-100, -30, "hostile"], [-30, 30, "wary"], [30, 70, "friendly"],
[70, 101, "devoted"]]
}
}
},
"bandit_leader": {
"name": "Bandit Leader",
"keys": "leader, chief, boss, scarred",
"desc": "The scarred leader of the bandit camp, guarding the strongbox. Fights harder the more cornered he becomes.",
"stats": {
"health": {
"desc": "The leader's physical health.",
"min": 0, "max": 120, "initial": 120, "max_delta_per_turn": 40,
"bands": [[0, 1, "dead"], [1, 30, "near death"], [30, 70, "bloodied"],
[70, 121, "unhurt"]]
},
"aggression": {
"desc": "How aggressively the leader fights; climbs as the fight turns against him.",
"min": 0, "max": 100, "initial": 40, "max_delta_per_turn": 25,
"bands": [[0, 30, "cautious"], [30, 70, "fierce"], [70, 101, "berserk"]]
}
}
}
},
"milestones": {
"camp_cleared": { "desc": "Clear the bandit camp of enemies" },
"strongbox_found": { "desc": "Recover the stolen strongbox" },
"gwen_survives": { "desc": "Escape with Gwen still alive" }
}
},
"story_cards": [
{
"type": "location",
"name": "Bandit Camp",
"keys": "camp, bandits, strongbox",
"entry": "A rough camp of bandits in a forest clearing, holding a stolen caravan strongbox.",
"notes": ""
}
],
"scripts": []
}