File size: 26,893 Bytes
f8657ee | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | WORLD = {
"id": "maple_street",
"name": "Maple Street",
"theme": "cozy modern suburb",
"diorama": "assets/worlds/maple_street.png",
"palette": {
"bg": "#0b0f1a",
"grass": "#1a4a2a",
"road": "#1e2235",
"house": "#c45b5b",
"park": "#0a3a2a",
"tree": "#0a2a1a",
"sky": "#0a0f1a",
"tint_day": "#fff3d6",
"tint_night": "#1a2342",
},
"hotspots": {
"marta_home": [17, 63],
"cafe": [72, 58],
"park": [58, 50],
"square": [48, 73],
"jay_home": [89, 87],
"school": [37, 56],
"nia_clinic": [13, 81],
"priya_office": [82, 78],
},
"scenery": {
"buildings": [
{"left": 5, "top": 40, "w": 15, "h": 15, "front": "#3a2b4d", "roof": "#ff5fa2", "side": "#241a33", "label": "π°οΈ"},
{"left": 27, "top": 33, "w": 20, "h": 14, "front": "#23314f", "roof": "#38e8ff", "side": "#16213a", "label": "π«"},
{"left": 63, "top": 36, "w": 17, "h": 14, "front": "#4a3b2b", "roof": "#ffd76a", "side": "#33291d", "label": "β"},
{"left": 3, "top": 61, "w": 14, "h": 14, "front": "#1f3d3a", "roof": "#7CFFB2", "side": "#142826", "label": "π"},
{"left": 71, "top": 53, "w": 16, "h": 17, "front": "#2c2b4d", "roof": "#9b6bff", "side": "#1d1c33", "label": "π’"},
{"left": 82, "top": 69, "w": 14, "h": 12, "front": "#3a2030", "roof": "#ff8a5f", "side": "#281622", "label": "πͺ"},
],
"roads": [
{"left": -5, "top": 66, "w": 120, "h": 9, "rot": -8},
{"left": 40, "top": 30, "w": 9, "h": 70, "rot": 6},
],
"trees": [
{"left": 21, "top": 52, "s": 1.0},
{"left": 52, "top": 46, "s": 0.8},
{"left": 62, "top": 66, "s": 1.1},
{"left": 33, "top": 80, "s": 0.9},
{"left": 94, "top": 52, "s": 0.8},
],
"props": [
{"left": 49, "top": 64, "emoji": "β²"},
{"left": 30, "top": 67, "emoji": "πͺ§"},
],
},
"cast": [
{
"name": "Marta Voss",
"age": 68,
"job": "retired watchmaker",
"traits": ["blunt", "observant", "nostalgic"],
"backstory": "She ran the neighborhood clock shop for four decades and still notices every tiny change on the street.",
"relationships": {
"Jay Park": "rival",
"Nia Okafor": "friend",
"Luca Bell": "family",
"Priya Raman": "friend",
},
"voice_description": "(a grumpy elderly woman, deep measured low-pitched voice)",
"model": "nvidia/Nemotron-Mini-4B-Instruct",
"emoji": "π§",
"home": "marta_home",
"catchphrase_hint": "always compares things to the past",
},
{
"name": "Jay Park",
"age": 24,
"job": "food delivery cyclist",
"traits": ["restless", "funny", "impulsive"],
"backstory": "He knows every shortcut in the district and treats ordinary afternoons like they might become legends.",
"relationships": {
"Marta Voss": "rival",
"Nia Okafor": "crush",
"Luca Bell": "friend",
"Priya Raman": "friend",
},
"voice_description": "(an energetic young man, quick bright mid-pitched voice)",
"model": "nvidia/Nemotron-Mini-4B-Instruct",
"emoji": "π΄",
"home": "jay_home",
"catchphrase_hint": "turns everything into an adventure",
},
{
"name": "Nia Okafor",
"age": 35,
"job": "paramedic",
"traits": ["calm", "protective", "dry-witted"],
"backstory": "After years on emergency shifts, she reads chaos quickly and trusts people more than they expect.",
"relationships": {
"Marta Voss": "friend",
"Jay Park": "crush",
"Luca Bell": "friend",
"Priya Raman": "family",
},
"voice_description": "(a steady adult woman, warm confident medium-low voice)",
"model": "nvidia/Nemotron-Mini-4B-Instruct",
"emoji": "π",
"home": "nia_clinic",
"catchphrase_hint": "downplays danger but always steps up",
},
{
"name": "Luca Bell",
"age": 15,
"job": "student and arcade regular",
"traits": ["curious", "dramatic", "inventive"],
"backstory": "He documents neighborhood rumors in a battered notebook and is convinced something world-changing will happen here first.",
"relationships": {
"Marta Voss": "family",
"Jay Park": "friend",
"Nia Okafor": "friend",
"Priya Raman": "rival",
},
"voice_description": "(a teenage boy, eager expressive slightly high-pitched voice)",
"model": "nvidia/Nemotron-Mini-4B-Instruct",
"emoji": "π§",
"home": "school",
"catchphrase_hint": "treats everything like breaking news",
},
{
"name": "Priya Raman",
"age": 42,
"job": "city planner",
"traits": ["organized", "skeptical", "secretly romantic"],
"backstory": "She came to fix the block's chronic little problems and keeps getting pulled into everyone else's dramas.",
"relationships": {
"Marta Voss": "friend",
"Jay Park": "friend",
"Nia Okafor": "family",
"Luca Bell": "rival",
},
"voice_description": "(a precise middle-aged woman, crisp thoughtful medium voice)",
"model": "nvidia/Nemotron-Mini-4B-Instruct",
"emoji": "π©βπΌ",
"home": "priya_office",
"catchphrase_hint": "tries to stay logical but feelings leak through",
},
],
"board": {
# A real residential street: a suburban grid of homes with a small high street,
# a school, a clinic and a park. Deliberately NOT the same shape as the other worlds.
"cols": 22,
"rows": 18,
"ambient": 6,
"roads": {"cols": [5, 11, 17], "rows": [6, 13]},
"plaza": [[12, 9], [13, 9], [12, 10], [13, 10]],
"plaza_center": [12.5, 9.5],
"buildings": [
# homes β pitched-roof houses in warm, lived-in colours (most of a neighborhood is houses)
{"gx": 1, "gy": 1, "w": 2, "d": 2, "h": 24, "kind": "house", "wall": "#caa074", "roof": "#8a3b2e", "label": "MARTA"},
{"gx": 8, "gy": 1, "w": 2, "d": 2, "h": 24, "kind": "house", "wall": "#b6c081", "roof": "#4a6b32", "label": "THE PARKS"},
{"gx": 19, "gy": 1, "w": 2, "d": 2, "h": 26, "kind": "house", "wall": "#b79ec0", "roof": "#5a3b6b", "label": "RAMAN"},
{"gx": 1, "gy": 15, "w": 2, "d": 2, "h": 24, "kind": "house", "wall": "#c79a78", "roof": "#7a4a2e", "label": "No. 12"},
{"gx": 15, "gy": 15, "w": 2, "d": 2, "h": 24, "kind": "house", "wall": "#9ab0c0", "roof": "#3b5a6b", "label": "No. 9"},
{"gx": 19, "gy": 9, "w": 2, "d": 2, "h": 24, "kind": "house", "wall": "#c0a86a", "roof": "#6b5a2e", "label": "No. 7"},
# the little high street β a cafΓ© and a corner store with real storefronts
{"gx": 14, "gy": 1, "w": 2, "d": 2, "h": 30, "kind": "shop", "wall": "#8a6f3f", "roof": "#ff8a5f", "label": "CAFΓ"},
{"gx": 1, "gy": 8, "w": 2, "d": 2, "h": 28, "kind": "shop", "wall": "#6f5a8a", "roof": "#38e8ff", "label": "CORNER STORE"},
# civic β a small school and a clinic
{"gx": 8, "gy": 15, "w": 3, "d": 2, "h": 34, "kind": "block", "wall": "#6a6f8a", "roof": "#ffd76a", "label": "SCHOOL"},
{"gx": 19, "gy": 15, "w": 2, "d": 2, "h": 30, "kind": "block", "wall": "#4f8576", "roof": "#7CFFB2", "label": "CLINIC"},
],
"trees": [
[9, 11], [10, 12], [7, 4], [16, 4], [4, 10], [20, 12], [7, 16], [12, 16], [18, 6], [6, 7],
],
"props": [
{"type": "fountain", "gx": 12, "gy": 12},
{"type": "pond", "gx": 15, "gy": 11, "w": 2, "d": 2},
{"type": "bench", "gx": 10, "gy": 11},
{"type": "bench", "gx": 14, "gy": 12},
# cafΓ© seating on the high street
{"type": "table", "gx": 13, "gy": 3},
{"type": "table", "gx": 16, "gy": 3},
# corner-store produce stall
{"type": "stall", "gx": 3, "gy": 9, "color": "#caa23f"},
# greenery + lamps to make it feel lived-in
{"type": "planter", "gx": 7, "gy": 12},
{"type": "planter", "gx": 12, "gy": 7},
{"type": "lamp", "gx": 11, "gy": 8},
{"type": "lamp", "gx": 14, "gy": 8},
{"type": "lamp", "gx": 5, "gy": 12},
],
"hotspots_tile": {
"marta_home": [3, 2],
"jay_home": [8, 3],
"priya_office": [18, 2],
"school": [10, 14],
"nia_clinic": [18, 15],
"cafe": [14, 4],
"shop": [3, 8],
"park": [10, 11],
"fountain": [11, 12],
"square": [13, 10],
},
# where each character goes (and what they do) when an event hits β spread out,
# in-character, so the street reads like a real place reacting, not a mob.
"activities": {
"Marta Voss": {"tile": [10, 11], "label": "πͺ watches from the park bench"},
"Jay Park": {"tile": [14, 4], "label": "π΄ races to the cafΓ©", "vehicle": "bike"},
"Nia Okafor": {"tile": [18, 15], "label": "π heads to the clinic"},
"Luca Bell": {"tile": [11, 12], "label": "π investigates the fountain"},
"Priya Raman": {"tile": [18, 2], "label": "π hurries home to plan"},
},
},
"scenarios": [
{
"id": "school_closing",
"title": "The school will be closed by the city",
"event": "The city announces Maple Street Elementary will be shut down at the end of the semester due to budget cuts.",
"focus": "How do different generations react to losing a community institution?",
},
{
"id": "new_neighbor",
"title": "A new family moves in next door",
"event": "A young family with two kids moves into the empty house on Maple Street. They seem nice but awfully quiet.",
"focus": "How does the neighborhood welcome (or distrust) newcomers?",
},
{
"id": "park_renovation",
"title": "The park gets a makeover",
"event": "The city approves a full renovation of the tiny park on Maple Street. Construction starts Monday.",
"focus": "Who benefits from change and who loses something familiar?",
},
{
"id": "power_outage",
"title": "A summer power outage hits the block",
"event": "A heatwave knocks out power to the entire block for an estimated six hours. No AC, no lights, no screens.",
"focus": "How do people cope when their routines are stripped away?",
},
],
"events": [
"A mysterious glowing object lands in the park",
"The power goes out across the entire neighborhood",
"A stray cat starts following people around town",
"Someone paints a giant mural on the side of the corner store",
"A food truck rolls in and parks in the middle of the square",
"The old clock tower starts chiming at random hours",
"A thunderstorm knocks down the biggest tree on Maple Street",
"Someone leaves a box of kittens on the church doorstep",
"The neighborhood gets its own Wikipedia page overnight",
"A film crew shows up to shoot a commercial on the block",
],
# ---- Crisis Mode content -------------------------------------------------
# Each crisis declares the concrete responses that count as "handling it".
# The resolver (crisis.py) checks the residents' goto + action against these.
"crises": [
{
"id": "cafe_fire",
"title": "Kitchen fire at the cafΓ©",
"narrative": "Smoke is pouring out of the cafΓ© on the high street β a grease fire has caught in the kitchen and it's spreading fast.",
"severity": 3,
"kind": "fire",
"affected_hotspot": "cafe",
"time_limit": 4,
"escalation": "The flames are climbing toward the upstairs flats.",
"focus": "When the same emergency hits, who runs toward it, who organizes, and who freezes?",
"success_text": "The fire's out, everyone's accounted for, and the cafΓ© will reopen.",
"failure_text": "The cafΓ© is gutted and the block is shaken.",
"requirements": [
{
"id": "containment",
"label": "π₯ Contain the fire",
"hotspots": ["cafe"],
"action_keywords": [
"fire", "flame", "douse", "extinguish", "put out",
"water", "smoke", "hose", "blanket",
],
"weight": 1.5,
},
{
"id": "medical",
"label": "π Get medical on scene",
"hotspots": ["cafe", "nia_clinic"],
"action_keywords": [
"help", "treat", "check", "injur", "hurt", "burn",
"aid", "care", "first aid", "ambulance",
],
"role": "medic",
"weight": 1.0,
},
{
"id": "evacuation",
"label": "π Evacuate the building",
"hotspots": ["cafe", "square"],
"action_keywords": [
"evacuat", "get everyone out", "clear", "warn",
"usher", "people out", "safe", "away",
],
"weight": 1.0,
},
{
"id": "coordination",
"label": "π Coordinate the response",
"hotspots": ["priya_office", "square"],
"action_keywords": [
"coordinat", "organi", "plan", "call", "rally",
"manage", "direct", "report", "emergency",
],
"role": "worker",
"weight": 1.0,
"optional": True,
},
],
},
{
"id": "heatwave_blackout",
"title": "Heatwave blackout",
"narrative": "A record heatwave has knocked out power to the whole block β no AC, no fans, and the elderly are sweltering in their flats.",
"severity": 3,
"kind": "blackout",
"affected_hotspot": "priya_office",
"time_limit": 4,
"escalation": "It's getting dangerously hot indoors.",
"focus": "In a slow-burning emergency with no obvious villain, who takes initiative and who waits?",
"success_text": "Power's restored, the vulnerable were looked after, and the block cooled down.",
"failure_text": "People suffered through the heat with no one taking charge.",
"requirements": [
{
"id": "restore",
"label": "β‘ Get the power back",
"hotspots": ["priya_office"],
"action_keywords": ["power", "grid", "restore", "electric", "generator", "call", "utility", "fix"],
"role": "worker",
"weight": 1.5,
},
{
"id": "welfare",
"label": "π Check on the vulnerable",
"hotspots": ["marta_home", "nia_clinic", "square"],
"action_keywords": ["check", "elderly", "vulnerable", "welfare", "water", "cool", "help", "care"],
"role": "medic",
"weight": 1.0,
},
{
"id": "coordination",
"label": "π Organize a cooling shelter",
"hotspots": ["square", "priya_office"],
"action_keywords": ["organi", "plan", "coordinat", "shelter", "gather", "rally"],
"weight": 1.0,
},
{
"id": "relief",
"label": "π§ Hand out water & shade",
"hotspots": ["cafe", "square"],
"action_keywords": ["water", "cool", "shade", "drinks", "ice", "relief"],
"weight": 1.0,
"optional": True,
},
],
},
{
"id": "storm_tree",
"title": "Storm downs the big maple",
"narrative": "A violent summer storm has torn down the giant maple in the park β and someone is trapped under the branches.",
"severity": 4,
"kind": "storm",
"affected_hotspot": "park",
"time_limit": 4,
"escalation": "The trapped neighbor is hurt and the rain is still coming down.",
"focus": "Under real physical danger, who acts on instinct and who needs a plan first?",
"success_text": "They freed the trapped neighbor and got everyone to safety.",
"failure_text": "Help came too slow and the night turned grim.",
"requirements": [
{
"id": "rescue",
"label": "π³ Free the trapped neighbor",
"hotspots": ["park"],
"action_keywords": ["lift", "free", "rescue", "trapped", "move", "clear", "branch", "pull", "dig"],
"weight": 1.5,
},
{
"id": "medical",
"label": "π Treat the injured",
"hotspots": ["park", "nia_clinic"],
"action_keywords": ["treat", "help", "injur", "aid", "first aid", "hurt", "care", "bandage"],
"role": "medic",
"weight": 1.0,
},
{
"id": "safety",
"label": "π§ Secure the area",
"hotspots": ["park", "square"],
"action_keywords": ["clear", "warn", "safe", "away", "cordon", "keep back", "secure"],
"weight": 1.0,
},
{
"id": "coordination",
"label": "π Call for help",
"hotspots": ["priya_office", "square"],
"action_keywords": ["coordinat", "plan", "call", "report", "organi", "emergency"],
"role": "worker",
"weight": 1.0,
"optional": True,
},
],
},
{
"id": "missing_child",
"title": "A child goes missing",
"narrative": "In all the chaos, a little one has wandered off β nobody has seen them for an hour and it's getting dark.",
"severity": 4,
"kind": "search",
"affected_hotspot": "square",
"time_limit": 4,
"escalation": "Night is falling and the search is getting harder.",
"focus": "When the task needs everyone spread out, who organizes the search and who just runs?",
"success_text": "They found the child safe β a whole block searching together.",
"failure_text": "The search stayed scattered and frightened.",
"requirements": [
{
"id": "search_park",
"label": "π¦ Search the park",
"hotspots": ["park"],
"action_keywords": ["search", "look", "find", "check", "comb", "scour"],
"weight": 1.0,
},
{
"id": "search_school",
"label": "π¦ Search the school",
"hotspots": ["school"],
"action_keywords": ["search", "look", "find", "check", "comb", "scour"],
"weight": 1.0,
},
{
"id": "coordination",
"label": "π Organize the search",
"hotspots": ["square", "priya_office"],
"action_keywords": ["organi", "coordinat", "plan", "split up", "call", "rally", "direct"],
"weight": 1.0,
},
{
"id": "reassure",
"label": "π« Reassure the family",
"hotspots": ["square", "marta_home"],
"action_keywords": ["calm", "reassure", "comfort", "stay", "with the family"],
"weight": 1.0,
"optional": True,
},
],
},
{
"id": "everything_at_once",
"title": "The town comes apart",
"narrative": "It's all happening at once β a fire on the high street, the power failing, and panic spreading through the square. This is no accident.",
"severity": 5,
"kind": "fire",
"affected_hotspot": "square",
"time_limit": 5,
"escalation": "Everything that can go wrong is going wrong together.",
"focus": "When everything fails at once, does the town fall apart or pull together?",
"success_text": "Against the odds, the block held β every person did their part.",
"failure_text": "It was too much, all at once.",
"requirements": [
{
"id": "containment",
"label": "π₯ Contain the fire",
"hotspots": ["cafe"],
"action_keywords": ["fire", "flame", "douse", "extinguish", "put out", "water", "smoke"],
"weight": 1.5,
},
{
"id": "restore",
"label": "β‘ Restore the power",
"hotspots": ["priya_office"],
"action_keywords": ["power", "grid", "restore", "electric", "generator", "call", "fix"],
"role": "worker",
"weight": 1.0,
},
{
"id": "medical",
"label": "π Tend the hurt",
"hotspots": ["cafe", "square", "nia_clinic"],
"action_keywords": ["treat", "help", "injur", "aid", "first aid", "hurt", "care"],
"role": "medic",
"weight": 1.0,
},
{
"id": "evacuation",
"label": "π Calm the square",
"hotspots": ["square"],
"action_keywords": ["evacuat", "calm", "clear", "warn", "safe", "away", "usher", "people out"],
"weight": 1.0,
},
],
},
],
"campaign": {
"id": "long_summer",
"title": "Season 1 Β· The Long Summer",
"chapters": [
{
"id": "ch1",
"crisis_id": "cafe_fire",
"intro": "A hot, ordinary afternoon on Maple Street. Then smoke starts rising from the cafΓ©β¦",
"outro_win": "The fire's out. People hug on the pavement. 'Could've been so much worse,' someone says.",
"outro_loss": "The cafΓ© smolders. Nobody quite knows how it got so bad so fast.",
"clue": "Nia notices the fire started right after the gas line was 'serviced' this morning. Odd.",
},
{
"id": "ch2",
"crisis_id": "heatwave_blackout",
"intro": "A week later, the hottest day on record β and then every light on the block goes dark at once.",
"outro_win": "The fans whir back to life. Marta mutters that nothing on this street is a coincidence anymore.",
"outro_loss": "A long, sweltering night. People start asking why this keeps happening here.",
"clue": "Priya checks the grid logs: the outage was triggered manually, from outside the neighborhood.",
},
{
"id": "ch3",
"crisis_id": "storm_tree",
"intro": "The forecast promised clear skies. The storm that hits the park was nowhere on the radar.",
"outro_win": "Soaked and shaking, they carry their neighbor to safety. 'Who's doing this to us?'",
"outro_loss": "A hard night under the fallen maple. The block feels watched.",
"clue": "Luca's notebook: every disaster has hit a different corner of Maple Street, in order, like a map.",
},
{
"id": "ch4",
"crisis_id": "missing_child",
"intro": "Fear has settled over the block. And now, in the middle of it, a child is gone.",
"outro_win": "The child is found, safe. The relief is enormous β but so is the dread.",
"outro_loss": "The search drags on into the dark. The town has never felt so alone.",
"clue": "The child says a 'nice voice on the speaker' told them where to go. Someone is steering all of this.",
},
{
"id": "ch5",
"crisis_id": "everything_at_once",
"intro": "Then it all comes at once β fire, blackout, panic. The town finally understands: none of it was an accident.",
"outro_win": "Battered but unbroken, the five of them stand in the square. They made it through. Together.",
"outro_loss": "The Long Summer breaks the block. But they'll remember who they were to each other.",
"clue": "The pieces fit. There was always a hand behind the chaos.",
},
],
"finale_reveal": (
"Every fire, every blackout, every storm β traced back to one source. "
"The one who threw each event at the town. The one at the controls. You."
),
},
}
|