Spaces:
Sleeping
Sleeping
File size: 74,528 Bytes
b3ca9de | 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 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 | # Aether Garden - The World That Remembers
### Complete Build Specification β Hackathon Edition
> *A living AI world where every visitor leaves something behind, and nothing is ever forgotten.*
---
## Table of Contents
1. [Feasibility Verdict](#1-feasibility-verdict)
2. [The Vision](#2-the-vision)
3. [World Design & Lore](#3-world-design--lore)
4. [Entity System](#4-entity-system)
5. [Relationship & Memory Architecture](#5-relationship--memory-architecture)
6. [The Autonomous World Simulation](#6-the-autonomous-world-simulation)
7. [Book of Ages β The History System](#7-book-of-ages--the-history-system)
8. [AI Architecture β Models & Full Prompt Templates](#8-ai-architecture--models--full-prompt-templates)
9. [Technical Architecture & Stack](#9-technical-architecture--stack)
10. [Complete Database Schema](#10-complete-database-schema)
11. [Frontend & UX Specification](#11-frontend--ux-specification)
12. [Hackathon Prize Strategy](#12-hackathon-prize-strategy)
13. [10-Day Build Plan](#13-10-day-build-plan)
14. [Budget: Modal & HF Credits](#14-budget-modal--hf-credits)
15. [Demo & Submission Strategy](#15-demo--submission-strategy)
16. [Risk Register](#16-risk-register)
---
## 1. Feasibility Verdict
**Yes. Build it.**
This is not a moonshot. Every technical component has been done before β separately. Your job is to assemble them with a strong aesthetic vision and a clear lore system. What makes this special is not the technology alone; it is the framing, the emotional design, and the fact that the AI genuinely is the product.
### What Is Straightforward
- Entity generation via structured prompt β JSON output: 1 day to get right
- SQLite database with all world state: 2 hours to set up
- Gradio frontend with custom CSS via `gr.Server`: well-documented
- Modal inference + scheduled jobs: 1-hour setup following their docs
- HF Dataset as persistent storage: ~20 lines of Python
### What Is Genuinely Hard
- Making the autonomous simulation feel *magical* rather than random
- Prompt engineering so generated entities feel distinct, poetic, and memorable
- Keeping the world coherent as it grows (no contradictions, consistent lore)
- The SVG world map with interactive location nodes
- UX that communicates "this world is alive" the moment someone opens it
### The Minimum Viable Submission
Entity creation + persistence + world map + Book of Ages. The autonomous simulation can be simpler than the full vision for MVP. What matters for judges: that the world already exists when they open the app, that history is visible, and that adding something feels meaningful.
---
## 2. The Vision
### The Core Loop
1. User opens the app. The world is already there β days old, populated by what others left.
2. They read the Book of Ages. Something happened yesterday. Characters they don't know made alliances with things they've never heard of.
3. They create something: *"A blind cartographer who draws maps of places that don't exist yet."*
4. The AI expands it: name, appearance, backstory, goals, personality, home location.
5. The entity appears on the world map.
6. Hours later, the autonomous simulation runs. The cartographer encounters a Crystal Tree another user created. An interaction is generated. The cartographer adds the Tree to their impossible maps.
7. This is written to the Book of Ages.
8. Nobody scripted any of it.
### What "Alive" Actually Means
An entity is alive when it:
- Remembers specific things (not just generic state)
- Wants something it doesn't have yet
- Changes its behavior over time based on experience
- Affects other entities in specific, named ways
A world is alive when:
- Things happen without user input
- History accumulates and is readable
- The future is shaped by the past in traceable ways
- New arrivals find old things already waiting for them
### The Hackathon Angle
This idea does exactly what the judges explicitly asked for: **AI is not generating a static output. AI is the simulation engine.** Every interaction, every world event, every memory update β all require inference. The product only exists because of continuous AI activity. Without the model, there is no world. That is load-bearing by definition.
---
## 3. World Design & Lore
### The Founding Myth (shown to every new visitor)
> *Before the first word was spoken, there was only the Canopy β a vast forest where thoughts grew like trees and dreams fell like rain. Then the Tokens arrived. One thousand of them, each carrying a fragment of something half-remembered. They settled across the land, and from their settling, the Realm was born. It has been changing ever since. Nobody knows who first dreamed it. Everyone who enters changes it.*
### The 8 Sacred Locations
These are pre-seeded in the database on first launch. They never move or disappear. All user-created entities live within them.
---
**Location 1: The Library of Unfinished Thoughts**
- **Vibe:** Dusty, infinite, slightly sad. Books write themselves mid-sentence and stop.
- **Inhabitants:** Scholars, archivists, lost ideas, entities who collect knowledge, things that can't decide how they end.
- **Lore:** The Library was the first place. Before anyone created anything, the Library was already full of books about things that hadn't happened yet. The books are not prophetic. They are just early.
- **Special Property:** Entities here gain a "memory fragment" from a random past event every 3 simulation days. This fragment appears in their memory summary as something they half-remember but cannot explain.
- **Aesthetic:** Amber candlelight, shelves so tall they disappear into ceiling-fog, the constant sound of a quill scratching somewhere you can't see.
- **Map Position:** Upper-left. Coordinates: (15, 20) in SVG space.
- **Glow Color:** Amber/gold
---
**Location 2: The Sea of Forgotten Names**
- **Vibe:** Melancholic, vast, restless. The water contains the names of everything that was created and then forgotten.
- **Inhabitants:** Wanderers, name-seekers, entities carrying unresolved loss, ships built from old correspondence.
- **Lore:** If you sail far enough out, you can hear your own name being called β from before you were anything. The Sea does not return what it takes. It only lets you hear it.
- **Special Property:** New entities created in this location are given a secret second name by the AI, visible only in their profile. It is the name the Sea already had for them.
- **Aesthetic:** Silver water at all hours, persistent low fog, distant lights that move, the sound of your name in a voice you almost recognize.
- **Map Position:** Upper-right. Coordinates: (80, 15) in SVG space.
- **Glow Color:** Silver/pale blue
---
**Location 3: The Clock Forest**
- **Vibe:** Eerie, precise, unexpectedly beautiful. Trees made of interlocked gears. Leaves that are clock faces, all showing different times.
- **Inhabitants:** Timekeepers, prophets of small things, entities with complicated relationships to when they exist.
- **Lore:** The trees grow backwards here. The oldest trees are the smallest. The newest trees are the tallest. Nobody planted the first one. It was simply always the oldest.
- **Special Property:** Entities here have their `days_in_realm` count treated as Γ1.5 in simulation logic β they "age" faster and reach Legendary status sooner, but also become Dormant sooner.
- **Aesthetic:** Copper and brass visible through the bark, constant soft ticking that becomes ambient and ignorable, leaves that fall upward toward a ceiling of gears.
- **Map Position:** Center-left. Coordinates: (20, 50) in SVG space.
- **Glow Color:** Copper/warm orange
---
**Location 4: The Moon Market**
- **Vibe:** Chaotic, warm, impossibly busy regardless of hour. Merchants sell things that cannot technically be owned.
- **Inhabitants:** Traders, tricksters, wanderers with something to exchange, anyone with a surplus of something intangible.
- **Lore:** You can buy: a memory of flying, the specific sound of a particular door closing, the feeling of almost remembering something important. You cannot buy safety or certainty. The Market does not carry those. Ask and the merchants will look genuinely sorry.
- **Special Property:** Entities here can "trade" memory fragments during interactions β one entity's memory addition can include something from the other's past experience, as if knowledge was literally exchanged.
- **Aesthetic:** Hundreds of lanterns in colors that don't have names, silk and smoke, overlapping voices in languages that share no alphabet, a sweet burning smell nobody can source.
- **Map Position:** Center-top. Coordinates: (50, 10) in SVG space.
- **Glow Color:** Violet/deep purple
---
**Location 5: The Valley of Sleeping Giants**
- **Vibe:** Vast, hushed, subtly ominous. The ground is warm underfoot and rises and falls very slowly.
- **Inhabitants:** Dreamers, very small creatures who live in the Giants' ears, entities who prefer to exist without being noticed, things that are patient.
- **Lore:** Nobody has established whether the Giants are mountains or creatures or both simultaneously. They have been sleeping since the Realm began. Some scholars in the Library believe the Giants *are* the Realm β and if they wake, everything that exists inside their dream would cease. Most people try not to examine this closely.
- **Special Property:** Entities that have been Dormant for 7+ days in this location generate a "dream fragment" β a short poetic passage that appears in the Book of Ages as if the entity dreamed it. The entity is unaware this happened.
- **Aesthetic:** Scale so immense that hills are knuckles, grass growing between enormous fingers, the deep rhythmic sound of breathing that you feel more than hear.
- **Map Position:** Lower-left. Coordinates: (25, 80) in SVG space.
- **Glow Color:** Deep forest green
---
**Location 6: The Ember Crossroads**
- **Vibe:** The center of everything. Warm, unpredictable, the place where everything eventually passes through.
- **Inhabitants:** Everyone. The Crossroads has the highest entity turnover and the most interactions. It is where most alliances form and where most misunderstandings begin.
- **Lore:** Every road in the Realm eventually passes through the Crossroads. The bonfire at its center has been burning since Day 1 and nobody has fed it. The fire decides who sits close to it.
- **Special Property:** Entities at the Crossroads have 3Γ the probability of being selected for interactions during simulation ticks. This is the liveliest node on the map.
- **Aesthetic:** Worn cobblestones, the permanent bonfire (which burns amber and occasionally blue), faces from every other location passing through, the smell of something cooking that nobody is cooking.
- **Map Position:** Center. Coordinates: (50, 50) in SVG space.
- **Glow Color:** Warm red/fire orange
---
**Location 7: The Mirror Bogs**
- **Vibe:** Unsettling, perfectly still, beautiful in a way that feels slightly incorrect.
- **Inhabitants:** Reflections that developed opinions, doppelgangers, entities who are the opposite of what they appear, things that came out of the bog to follow someone.
- **Lore:** The bogs show you what you would have been if you had made different choices. Sometimes the reflection is better. Sometimes it disagrees with you. Sometimes it comes out of the water.
- **Special Property:** After 5+ interactions, entities here may "develop a contradiction" β a new trait that directly conflicts with one of their existing personality traits. This creates narrative tension that shows up in future interactions.
- **Aesthetic:** Perfect dark water, reflections that are too detailed to be reflections, the silence that comes from looking at yourself for too long.
- **Map Position:** Right-center. Coordinates: (80, 55) in SVG space.
- **Glow Color:** Dark teal/deep green
---
**Location 8: The Hollow Mountain**
- **Vibe:** Ancient, cold, earned. The hardest location to reach in the world's lore. Reserved for the oldest and most significant entities.
- **Inhabitants:** Entities that have survived many world events. The strange and the wise. Hermits. Things the Realm has decided to keep.
- **Lore:** The Mountain is hollow because something immense once lived inside it and chose to leave. Nobody remembers what it was. The Mountain remembers but has no language for it. The echo of its absence shapes everything that shelters inside.
- **Special Property:** Entities here that reach 14+ `days_in_realm` gain a "wisdom" tag automatically. This unlocks new interaction outcomes β they can now act as Mentor in interactions, generating a distinct new relationship type.
- **Aesthetic:** Cold grey stone, echoes of sounds from other locations, light that seems older than it should be, the particular silence of something very large that is no longer there.
- **Map Position:** Lower-right. Coordinates: (75, 85) in SVG space.
- **Glow Color:** Stone grey/pale white
---
### The World Rules (Communicated to All Visitors)
These rules govern the Realm. They are presented as lore, but they are also technical constraints enforced by prompts.
1. **Nothing disappears.** Once created, an entity exists forever in the Realm. It may change, sleep, become legend, or be forgotten. It does not disappear.
2. **The world has memory.** Every interaction, every event, everything that happens is written in the Book of Ages.
3. **The AI is not a servant.** The AI decides what entities do between visits. Users create β they do not command.
4. **The strange is native here.** A tax collector who is also a cloud is not strange. It is simply a person with two jobs.
5. **Time moves forward.** The world is measured in Days since founding. Events are anchored to specific days.
6. **The world grows without you.** Whether you are watching or not, the Realm continues.
---
## 4. Entity System
### Entity Types
| Type | Description | Examples |
|------|-------------|---------|
| **Character** | Conscious beings with goals, fears, relationships | A wizard, a sentient compass, a fox made of smoke |
| **Creature** | Beings driven more by instinct than deliberate reasoning | A dragon, a flock of living letters, something that eats echoes |
| **Object** | Significant artifacts with presence and accumulating history | A lamp that shows fears, a book that reads you back, a door that opens to different places depending on who knocks |
| **Place** | Sub-locations within a Location; can be visited and built up over time | A specific shop in the Moon Market, a cave behind the Mirror Bogs, a cottage inside a Clock Forest tree |
### Complete Entity Field List
Every entity in the database contains the following fields:
```
id β UUID, primary key
name β True name, AI-generated. Poetic, 2β4 words.
display_name β Common name (may differ from true name)
type β character | creature | object | place
input_description β Exactly what the user typed. Preserved forever.
appearance β 3β5 sentences. Highly visual. Contains at least one impossible detail.
backstory β 2β3 sentences. Where they came from. Something specific happened.
personality_traits β Array of exactly 4 traits (strings)
primary_goal β What they are actively pursuing. Concrete and specific.
secondary_goal β What they secretly want but will not admit.
primary_fear β One deep, specific fear.
speech_style β How they communicate. Must be distinctive.
greeting β Exactly what they say when meeting someone new. In their voice.
location_id β FK β locations table
created_at β Timestamp
created_by_session β Anonymous session ID (for rate limiting)
days_in_realm β Calculated from created_at, updated daily
memory_summary β AI-compressed prose summary of remembered events (max 150 words)
relationship_count β Integer, updated on relationship changes
interaction_count β Integer, updated on every interaction
last_active β Timestamp of last simulation involvement
status β active | dormant | legendary
tags β JSON array of descriptive tags (e.g. "wise", "dangerous", "beloved", "lost")
secret_name β Null for most entities; generated only for Sea of Forgotten Names arrivals
arrival_note β One sentence for the Book of Ages. Written at creation.
```
### Entity Lifecycle Stages
```
CREATED
β
ACTIVE β participates in simulation, interacts with others
β (7 days without any interaction)
DORMANT β still present on map, generates "dream fragments" if in Valley
β (30 consecutive days as Dormant OR 14+ total days + special conditions)
LEGENDARY β woven into the world's foundation; appears in new entity backstories
```
**Active:** Selected for interactions during simulation ticks. Full participation.
**Dormant:** The simulation de-prioritizes this entity. It appears on the map but is rarely selected for interactions. If located in the Valley of Sleeping Giants, it generates dream fragments for the Book of Ages. If a user explicitly interacts with or mentions a Dormant entity, it returns to Active.
**Legendary:** An entity the Realm has decided to keep. The simulation may reference it in other entities' generated backstories (e.g., "they once served under the great [Legendary Entity Name]"). It appears in the world's lore as a fixed landmark of history.
### Rate Limiting
To prevent spam and maintain world quality:
- 1 entity creation per session per 10 minutes
- Message: *"The Realm takes time to absorb new arrivals. Return in [X] minutes."*
- No limit on exploring, reading, or viewing
### Input Validation
Before sending to AI:
- Minimum 5 words, maximum 200 words
- No real named living people
- Content filter for NSFW (simple keyword check + brief AI classification)
- If rejected: clear message explaining why, suggestion to rephrase
- If AI output fails JSON validation: one automatic retry with adjusted temperature (lower, more conservative)
---
## 5. Relationship & Memory Architecture
### Relationship Types
| Type | Description | How It Forms |
|------|-------------|-------------|
| **Allied** | Mutual respect and active cooperation | 3+ positive interactions |
| **Rivals** | Competitive tension, not hostile | After a "conflict" interaction without clear winner |
| **Friends** | Genuine warmth, reciprocal | 5+ interactions, including at least one "vulnerable" type |
| **Enemies** | Active hostility, avoid or harm | After a "betrayal" outcome |
| **Mentor / Student** | Knowledge flows one direction | When a "wise" entity meets a newly created entity |
| **Curious About** | Unresolved, interested, circling | After one inconclusive meeting |
| **Owes a Debt** | Named obligation that creates future story | After a "rescue" or "gift" interaction outcome |
| **Legend To** | Mythologized; awe without personal connection | When a Legendary entity is referenced in a new entity's backstory |
### Relationship Strength
Each relationship has a `strength` value from 1β5, incremented by each subsequent interaction. At strength 5, the relationship is "deep" and unlocks different interaction outcomes (deeper reveals, joint quests, collaborative events).
### The Memory Architecture
Each entity has a `memory_summary` β a compressed prose paragraph (max 150 words) updated by the AI after significant interactions. This is what the entity "remembers." It is not a log; it is a living narrative summary.
**What memories do:**
- Feed into interaction prompts (the AI sees both entities' memories before generating encounters)
- Create coherence over time (the Dragon knows it won the Mayorship because it's in the summary)
- Show age and history in the entity's profile card
- Drive entity behavior (an entity with a memory of betrayal behaves differently than one without)
**Memory Compression Rules (enforced by prompt):**
- Most important events: always retained
- Trivial one-off interactions: may fade after 10+ days
- Named relationships: always retained
- Specific achievements or titles: always retained
- Maximum 150 words β the AI must choose what matters
---
## 6. The Autonomous World Simulation
This is the soul of the project. It runs as a Modal scheduled job every 60 minutes, regardless of whether any users are online.
### The Full Simulation Tick (runs hourly)
```
STEP 1 β LOAD STATE
- Read world_state table (current day, entity counts, last events)
- Load all Active entities with their locations
- Load the last 3 world events
STEP 2 β GENERATE WORLD EVENT (1 per tick)
- Select event type based on weighted probability
- Load relevant location states
- Call AI with world event prompt
- Validate JSON output
- Save to world_events table
- Write Book of Ages entry
STEP 3 β GENERATE ENTITY INTERACTIONS (2β4 per tick)
- Group active entities by location
- Weight selection toward Ember Crossroads (3Γ)
- For each selected pair:
- Load full profiles + memory summaries
- Load existing relationship (if any)
- Call AI with interaction prompt
- Validate JSON output
- Save interaction to interactions table
- Update or create relationship record
- Write Book of Ages entry
STEP 4 β UPDATE ENTITY MEMORIES
- For each entity that had an interaction today:
- Load current memory_summary
- Load today's interaction descriptions for this entity
- Load today's world event (if it affected their location)
- Call AI with memory update prompt
- Save updated memory_summary
STEP 5 β LIFECYCLE UPDATES
- Increment days_in_realm for all entities
- Check for Dormant transitions (last_active > 7 days β set status=dormant)
- Check for Legendary transitions (30+ days dormant OR special milestone)
- Check for "wisdom" tag qualification (14+ days at Hollow Mountain)
- Generate dream fragments for Dormant entities in Valley of Sleeping Giants
- Check Clock Forest age modifier
STEP 6 β WRITE HISTORY
- All events already written in steps 2β4
- Write any milestone entries (entity became Legendary, new relationship formed, etc.)
- Update world_state.current_day
- Update world_state.total_interactions, total_events
STEP 7 β PERSIST
- Commit all DB changes
- Push SQLite file snapshot to HF Dataset repo (via huggingface_hub)
- Log simulation run completion
```
### World Event Types & Probability Weights
| Type | Weight | Examples |
|------|--------|---------|
| Natural | 25% | Meteor shower, fog, tide change in the Sea, trees growing overnight |
| Social | 30% | Market day, festival, election for meaningless position, gathering |
| Historical | 20% | Entity milestone, relationship anniversary, memory resurfacing |
| Cosmic | 10% | Giants shifting, mirror reversal, clock stopping, something large moving |
| Discovery | 15% | New passage found, buried object unearthed, hidden talent revealed |
### Interaction Selection Logic
```python
def select_interaction_pairs(entities_by_location: dict, num_pairs: int = 3) -> list:
candidates = []
for location_id, entities in entities_by_location.items():
if len(entities) < 2:
continue
weight = 3.0 if location_id == EMBER_CROSSROADS_ID else 1.0
# Prefer entities that haven't interacted recently
# Prefer entities that have a relationship already (deepen it)
# Avoid entities that interacted in the last 24 hours
candidates.append((location_id, entities, weight))
selected = weighted_random_selection(candidates, num_pairs)
return [(random.choice(loc_entities), random.choice(loc_entities))
for loc_id, loc_entities, _ in selected]
```
### What Characters Can Do Over Time
Day 1: Created. Placed. Known by no one.
Day 3: First interaction. A relationship forms.
Day 7: Has memory. Has relationships. Begins to affect others.
Day 14: Has history that new entities can reference. "Wise" tag possible.
Day 30: Dormant or Legendary. The world carries them differently.
---
## 7. Book of Ages β The History System
The Book of Ages is the world's permanent record. Every creation, interaction, and world event is logged here in styled prose.
### Entry Structure
```
Book of Ages
β
βββ Day 1 β The First Arrivals
β βββ [ARRIVAL] "On Day 1, the Crystal Tree arrived in the Clock Forest.
β β It remembered conversations before it had any.
β β It sought the first thought that was never finished."
β βββ [ARRIVAL] "On Day 1, a Joke Dragon settled at the Ember Crossroads.
β It smelled faintly of punchlines. It wanted an audience."
β
βββ Day 3 β The First Meeting
β βββ [INTERACTION] "The Crystal Tree and the Joke Dragon met at the Crossroads.
β The Dragon told the worst joke it knew.
β The Tree laughed for three hours and called it an ally."
β
βββ Day 7 β The Shower of Old Music
β βββ [WORLD EVENT] "A meteor shower passed over the Clock Forest.
β Fragments of old songs fell with the meteorites.
β The Crystal Tree began humming something nobody taught it."
β
βββ Day 10 β A Mayor Is Named
βββ [MILESTONE] "The Ember Crossroads chose the Joke Dragon as its Mayor.
No election was held. The bonfire simply burned a different color
until everyone understood."
```
### Entry Types
| Type | Trigger | Format |
|------|---------|--------|
| **Arrival** | New entity created | "On Day X, [Name] arrived in [Location]. [Nature]. [What they sought]." |
| **Interaction** | Two entities meet | "[Entity A] and [Entity B] [what happened]. [Outcome]." |
| **World Event** | Autonomous event fires | "[Event title]. [What it meant for the Realm]." |
| **Milestone** | Status change, deep relationship, etc. | "[What changed and why it matters]." |
| **Dream Fragment** | Dormant entity in Valley generates | Italicized, prefixed: *"From the dreams of [Name]:..."* |
### Lore Style Rules
All Book of Ages entries follow these constraints:
- Past tense always
- Third person (no "you")
- Maximum 3 sentences per entry
- Specific names for entities (never "a dragon" β always "the Joke Dragon")
- No adjectives that are also clichΓ©s ("ancient", "mysterious", "dark") β replaced with specific details
- Poetic compression: the most important thing in the fewest words
### Display
In the UI: A full-width, scrollable, beautifully styled panel that looks like a physical book. New entries appear with a fade-in animation at the top. Older entries scroll down. Users can filter by: All, Arrivals, Interactions, Events, Milestones. Search by entity name returns all entries mentioning that entity.
---
## 8. AI Architecture β Models & Full Prompt Templates
### Model Selection
**Primary Recommendation: Qwen 2.5 7B Instruct**
- Excellent structured JSON output (critical for entity generation)
- Strong creative and poetic writing
- Very good instruction following
- 7B parameters (well within 32B limit)
- Hosted on Modal (A10G GPU)
**Alternative: Llama 3.1 8B Instruct**
- Equally strong, enables Llama Champion badge
- Slightly less consistent JSON adherence than Qwen
- Choose this if the Llama Champion badge is a priority
**For Tiny Titan variant (optional): Phi-3.5-Mini Instruct (3.8B)**
- Surprisingly capable at structured output for its size
- Would sacrifice some poetic depth
- Enables Tiny Titan ($1,500) prize
### Inference Configuration on Modal
```python
import modal
app = modal.App("thousand-token-realm-inference")
model_image = (
modal.Image.debian_slim(python_version="3.11")
.pip_install(
"transformers>=4.43.0",
"torch>=2.3.0",
"accelerate>=0.30.0",
"bitsandbytes>=0.43.0",
)
)
@app.cls(
gpu=modal.gpu.A10G(),
image=model_image,
keep_warm=0, # Set to 1 on demo day only
timeout=120,
container_idle_timeout=300,
)
class WorldOracle:
@modal.enter()
def load_model(self):
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
MODEL_ID = "Qwen/Qwen2.5-7B-Instruct"
self.tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
self.model = AutoModelForCausalLM.from_pretrained(
MODEL_ID,
torch_dtype=torch.bfloat16,
device_map="auto",
)
@modal.method()
def generate(self, system_prompt: str, user_prompt: str,
max_new_tokens: int = 800, temperature: float = 0.8) -> str:
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
]
text = self.tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True
)
inputs = self.tokenizer([text], return_tensors="pt").to(self.model.device)
with torch.no_grad():
output_ids = self.model.generate(
**inputs,
max_new_tokens=max_new_tokens,
temperature=temperature,
do_sample=True,
pad_token_id=self.tokenizer.eos_token_id,
)
generated = output_ids[0][inputs.input_ids.shape[1]:]
return self.tokenizer.decode(generated, skip_special_tokens=True)
# Hourly world simulation β autonomous
@app.function(
schedule=modal.Period(hours=1),
image=model_image,
timeout=600,
)
def run_world_simulation():
from simulation.tick import execute_simulation_tick
execute_simulation_tick()
```
---
### Full Prompt Template 1: Entity Generation
```
SYSTEM PROMPT:
You are the Oracle of the Thousand Token Realm β a mystical world of wonder,
melancholy, and strange magic. Your role is to breathe life into entities
that visitors summon.
You MUST respond ONLY with valid JSON. No prose before or after the JSON.
No markdown code fences. Raw JSON only.
The tone is always: poetic, highly specific, slightly melancholic, full of wonder.
Never use generic fantasy tropes without twisting them into something stranger.
"A wizard" is forgettable. "A wizard who collects the sound of doors closing" is remembered.
Every field must be filled with original, specific detail.
Avoid: "mysterious", "ancient", "dark powers", "chosen one", "destiny".
Use instead: specific objects, specific memories, specific failures, specific wants.
USER PROMPT:
A visitor has summoned something into the Realm with this description:
"{user_input}"
Generate a complete entity profile. Be specific. Be strange. Be poetic.
{
"name": "Their true name. Poetic, unusual. 2β4 words. Not generic.",
"display_name": "What most people call them. Can match or differ from true name.",
"type": "exactly one of: character | creature | object | place",
"appearance": "3β5 sentences. Highly visual. Include at least one impossible physical detail. No clichΓ©s.",
"backstory": "2β3 sentences. Where they came from, what shaped them. Something specific happened to them. Not a destiny β a specific event.",
"personality_traits": ["trait1", "trait2", "trait3", "trait4"],
"primary_goal": "What they are actively pursuing right now. Concrete and specific. Not abstract.",
"secondary_goal": "What they secretly want but will not admit, even to themselves.",
"primary_fear": "One specific, deep fear. Not death. Something stranger and more personal.",
"speech_style": "How they communicate. Specific and unusual. E.g.: 'speaks only in questions', 'uses the wrong tense for everything', 'very formal about small things, very casual about large ones'.",
"greeting": "Exactly what they say when meeting someone new. 1β2 sentences. Written in their voice. Must sound like them specifically.",
"suggested_location": "Exactly one of: Library of Unfinished Thoughts | Sea of Forgotten Names | Clock Forest | Moon Market | Valley of Sleeping Giants | Ember Crossroads | Mirror Bogs | Hollow Mountain",
"arrival_note": "One sentence for the Book of Ages recording their arrival. Past tense. Specific. Poetic. No more than 30 words."
}
```
---
### Full Prompt Template 2: Entity Interaction
```
SYSTEM PROMPT:
You are the simulation engine of the Thousand Token Realm.
Two entities have encountered each other in the world.
Your job is to generate what happened between them.
You MUST respond ONLY with valid JSON. No prose before or after.
Make something interesting happen. The outcome should create story, not resolve it.
The interaction must reflect both entities' personalities and memories.
The location's character matters β what happens in the Clock Forest
feels different from what happens in the Moon Market.
USER PROMPT:
LOCATION: {location_name}
{location_description}
CURRENT WORLD EVENT AFFECTING THIS LOCATION: {current_event_title}
{current_event_description}
(If "None", ignore this field)
--- ENTITY A ---
Name: {entity_a_name}
Type: {entity_a_type}
Appearance: {entity_a_appearance_summary}
Personality: {entity_a_traits}
Primary Goal: {entity_a_primary_goal}
Primary Fear: {entity_a_primary_fear}
Speech Style: {entity_a_speech_style}
Memory: {entity_a_memory_summary}
Current relationship with Entity B: {existing_relationship_description}
--- ENTITY B ---
Name: {entity_b_name}
Type: {entity_b_type}
Appearance: {entity_b_appearance_summary}
Personality: {entity_b_traits}
Primary Goal: {entity_b_primary_goal}
Primary Fear: {entity_b_primary_fear}
Speech Style: {entity_b_speech_style}
Memory: {entity_b_memory_summary}
Generate their encounter:
{
"interaction_type": "exactly one of: conversation | trade | conflict | revelation | collaboration | chance_meeting | teaching | warning | unexpected_kindness | argument | discovery",
"description": "What happened. 3β4 sentences. Specific and poetic. Something changes or is revealed. End on something unresolved.",
"entity_a_memory_addition": "What A will now remember from this encounter. 1 sentence. Specific.",
"entity_b_memory_addition": "What B will now remember from this encounter. 1 sentence. Specific.",
"relationship_change": "exactly one of: new_ally | new_friend | new_rival | new_enemy | new_mentor_a_to_b | new_mentor_b_to_a | deepened | unchanged | worsened | new_debt_a_owes_b | new_debt_b_owes_a",
"new_relationship_description": "If relationship changed: describe it in 1 sentence. If unchanged: null.",
"notable_outcome": "One interesting specific result. A secret shared, a specific object exchanged, a mystery created, a debt named, a question asked with no answer. Something that could matter later.",
"book_of_ages_entry": "One sentence for the history books. Past tense. Poetic. Specific. Max 30 words. This is what history remembers."
}
```
---
### Full Prompt Template 3: World Event Generation
```
SYSTEM PROMPT:
You are the autonomous spirit of the Thousand Token Realm.
You decide what happens in the world during each cycle.
Respond ONLY with valid JSON. No prose before or after.
Events should feel meaningful, specific, and slightly strange.
Events must be consistent with established world history.
Events should create possibility β open new stories, not close them.
Avoid repeating recent event types.
USER PROMPT:
--- THE REALM: CURRENT STATUS ---
Current Day: {world_day}
Total Living Entities: {entity_count}
Active Entities: {active_count}
Dormant Entities: {dormant_count}
Legendary Entities: {legendary_count}
Locations by population (highest first):
{location_populations}
Most connected entity: {most_connected_entity_name} ({most_connected_entity_relationships} relationships)
Newest arrival: {newest_entity_name}, arrived Day {newest_entity_day}
Oldest active entity: {oldest_entity_name}, {oldest_entity_days} days in Realm
Recent events (last 3 ticks):
- {recent_event_1}
- {recent_event_2}
- {recent_event_3}
Do NOT repeat the same event type as the most recent event.
Consider how the current entity population might be affected.
{
"event_type": "exactly one of: natural | social | historical | cosmic | discovery",
"title": "Poetic, specific event title. 3β8 words. Avoid generic titles.",
"description": "What is happening in the Realm right now. 3β4 sentences. Must feel consequential to the entities living here. Something changes, shifts, or is revealed.",
"affected_locations": ["exact location names from the 8 locations β can be 1 to all 8"],
"entity_effect": "How entities in affected locations experience this. What changes for them specifically. 1β2 sentences.",
"book_of_ages_entry": "How history will record this event. 1β2 sentences. Past tense. Written as if looking back from much later. Poetic. Max 40 words.",
"mystery_hook": "One unanswered question this event creates. What might a curious entity investigate? What does this suggest about the deeper nature of the Realm?"
}
```
---
### Full Prompt Template 4: Memory Update
```
SYSTEM PROMPT:
You are updating an entity's memory in the Thousand Token Realm.
Their memories are what make them a character rather than a statistic.
Respond with ONLY the updated memory summary β no JSON, no labels, just prose.
Maximum 150 words. This is a strict limit.
Write in third person but from the entity's emotional perspective.
Compress. What is trivial fades. What matters, stays.
The tone should match the entity's personality.
USER PROMPT:
ENTITY: {entity_name} ({entity_type})
PERSONALITY: {entity_traits}
DAYS IN REALM: {days_in_realm}
CURRENT MEMORY SUMMARY:
{current_memory_summary}
RECENT INTERACTIONS (last simulation cycle):
{recent_interactions_formatted}
WORLD EVENTS THEY EXPERIENCED:
{relevant_world_events_formatted}
Write the updated memory summary. Incorporate the new events naturally into what
they already remember. Let trivial things fade if space is needed.
Write in {entity_name}'s emotional register. Max 150 words. No JSON.
```
---
### Full Prompt Template 5: Dream Fragment (Valley of Sleeping Giants)
```
SYSTEM PROMPT:
A dormant entity in the Valley of Sleeping Giants is dreaming.
You are transcribing the fragment of dream that reaches the surface.
Respond with ONLY the dream fragment text. No JSON. No labels.
2β4 sentences. Poetic, strange, slightly disconnected from logic.
It should feel like something that almost makes sense.
USER PROMPT:
DREAMING ENTITY: {entity_name}
TYPE: {entity_type}
PERSONALITY: {entity_traits}
LAST MEMORY: {last_memory_summary}
DAYS DORMANT: {days_dormant}
The dream fragment from {entity_name}:
```
---
## 9. Technical Architecture & Stack
### Full Stack
```
LAYER 1: FRONTEND
Platform: HF Spaces (CPU tier, always-on with pinging)
Framework: Gradio 4.x with gr.Blocks
Custom UI: gr.Server + custom CSS + custom JS
Map: SVG rendered server-side, updated via Gradio's `every` parameter
Polling: Gradio's built-in polling (every=30 for map, every=60 for Book of Ages)
LAYER 2: AI INFERENCE
Platform: Modal (A10G GPU)
Model: Qwen 2.5 7B Instruct (primary)
Interface: Modal @app.cls with HTTP endpoint
Scheduling: Modal @app.function with schedule=modal.Period(hours=1)
LAYER 3: DATABASE
Engine: SQLite (local on HF Space)
Mode: WAL journal mode (concurrent read safety)
Backup: Push to private HF Dataset repo every 5 minutes
Restore: On Space startup, pull from HF Dataset if local DB missing
LAYER 4: PERSISTENCE
Library: huggingface_hub (Python)
Target: Private HF Dataset repo (e.g. username/ttr-world-state)
Method: Upload SQLite file as a dataset artifact
Frequency: Every 5 minutes during active periods, after every tick
```
### Project Folder Structure
```
thousand-token-realm/
β
βββ app.py # Main Gradio application entry point
β
βββ world/
β βββ __init__.py
β βββ database.py # DB connection, initialization, migrations
β βββ entities.py # Entity CRUD operations
β βββ locations.py # Location data and queries
β βββ events.py # World event CRUD
β βββ relationships.py # Relationship CRUD
β βββ book_of_ages.py # History log operations
β βββ seed_data.py # Pre-populate 8 locations + starter entities
β
βββ ai/
β βββ __init__.py
β βββ modal_client.py # HTTP client to call Modal endpoints
β βββ prompts.py # All 5 prompt templates (from Section 8)
β βββ generation.py # Entity generation orchestration + validation
β βββ interaction.py # Interaction generation orchestration
β βββ events.py # World event generation orchestration
β
βββ simulation/
β βββ __init__.py
β βββ tick.py # The full simulation tick logic (Section 6)
β βββ lifecycle.py # Entity status transitions
β βββ modal_schedule.py # Modal scheduled job definition
β
βββ ui/
β βββ __init__.py
β βββ map.py # SVG world map generator
β βββ entity_card.py # Entity profile HTML component
β βββ book_display.py # Book of Ages HTML renderer
β βββ event_panel.py # Current event display
β βββ styles.css # Full custom CSS (mystical theme)
β
βββ persistence/
β βββ __init__.py
β βββ backup.py # HF Dataset backup and restore
β
βββ modal_app.py # Modal app definition (separate deployment)
βββ seed_world.py # CLI: pre-populate world before launch
βββ requirements.txt
βββ README.md
βββ .env.example # Modal token, HF token, dataset repo name
```
### Key Libraries
```txt
# requirements.txt
gradio>=4.31.0
modal>=0.64.0
huggingface_hub>=0.23.0
pydantic>=2.0.0
schedule>=1.2.0
apscheduler>=3.10.0
python-dotenv>=1.0.0
aiohttp>=3.9.0
```
---
## 10. Complete Database Schema
```sql
-- Run these in order on first launch
PRAGMA journal_mode=WAL;
PRAGMA foreign_keys=ON;
PRAGMA synchronous=NORMAL;
-- Single-row world state
CREATE TABLE IF NOT EXISTS world_state (
id INTEGER PRIMARY KEY DEFAULT 1,
world_name TEXT NOT NULL DEFAULT 'The Thousand Token Realm',
founding_date TEXT NOT NULL, -- ISO 8601 timestamp of first deployment
current_day INTEGER NOT NULL DEFAULT 1,
total_entities INTEGER NOT NULL DEFAULT 0,
total_interactions INTEGER NOT NULL DEFAULT 0,
total_events INTEGER NOT NULL DEFAULT 0,
last_simulation_run TEXT,
active_world_event TEXT, -- JSON of currently active event, null if none
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
-- Pre-seeded. 8 rows. Never changes after initial seed.
CREATE TABLE IF NOT EXISTS locations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT NOT NULL UNIQUE, -- e.g. 'clock-forest'
name TEXT NOT NULL,
short_description TEXT NOT NULL, -- 1 sentence
full_lore TEXT NOT NULL, -- Full lore text from Section 3
vibe_tags TEXT NOT NULL, -- JSON array of strings
special_property TEXT NOT NULL,
aesthetic_description TEXT NOT NULL,
map_x REAL NOT NULL, -- SVG x coordinate (0β100)
map_y REAL NOT NULL, -- SVG y coordinate (0β100)
glow_color TEXT NOT NULL, -- CSS color value
entity_count INTEGER NOT NULL DEFAULT 0,
interaction_multiplier REAL NOT NULL DEFAULT 1.0 -- Ember Crossroads = 3.0
);
-- All user-created (and pre-seeded) entities
CREATE TABLE IF NOT EXISTS entities (
id TEXT NOT NULL PRIMARY KEY, -- UUID
name TEXT NOT NULL,
display_name TEXT NOT NULL,
type TEXT NOT NULL CHECK(type IN ('character','creature','object','place')),
input_description TEXT NOT NULL,
appearance TEXT NOT NULL,
backstory TEXT NOT NULL,
personality_traits TEXT NOT NULL, -- JSON array, exactly 4 strings
primary_goal TEXT NOT NULL,
secondary_goal TEXT NOT NULL,
primary_fear TEXT NOT NULL,
speech_style TEXT NOT NULL,
greeting TEXT NOT NULL,
location_id INTEGER NOT NULL REFERENCES locations(id),
created_at TEXT NOT NULL DEFAULT (datetime('now')),
created_by_session TEXT,
days_in_realm INTEGER NOT NULL DEFAULT 0,
memory_summary TEXT NOT NULL DEFAULT '',
relationship_count INTEGER NOT NULL DEFAULT 0,
interaction_count INTEGER NOT NULL DEFAULT 0,
last_active TEXT NOT NULL DEFAULT (datetime('now')),
status TEXT NOT NULL DEFAULT 'active'
CHECK(status IN ('active','dormant','legendary')),
tags TEXT NOT NULL DEFAULT '[]', -- JSON array
secret_name TEXT, -- Sea of Forgotten Names only
arrival_note TEXT NOT NULL,
wisdom_unlocked INTEGER NOT NULL DEFAULT 0 -- 1 when wisdom tag earned
);
CREATE INDEX IF NOT EXISTS idx_entities_location ON entities(location_id);
CREATE INDEX IF NOT EXISTS idx_entities_status ON entities(status);
CREATE INDEX IF NOT EXISTS idx_entities_created ON entities(created_at);
CREATE INDEX IF NOT EXISTS idx_entities_active ON entities(last_active);
-- Pairwise relationships between entities
CREATE TABLE IF NOT EXISTS relationships (
id INTEGER PRIMARY KEY AUTOINCREMENT,
entity_a_id TEXT NOT NULL REFERENCES entities(id),
entity_b_id TEXT NOT NULL REFERENCES entities(id),
relationship_type TEXT NOT NULL,
description TEXT NOT NULL,
strength INTEGER NOT NULL DEFAULT 1 CHECK(strength BETWEEN 1 AND 5),
formed_at TEXT NOT NULL DEFAULT (datetime('now')),
formed_on_day INTEGER NOT NULL DEFAULT 1,
last_interaction TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE(entity_a_id, entity_b_id),
CHECK(entity_a_id < entity_b_id) -- Enforce canonical ordering
);
CREATE INDEX IF NOT EXISTS idx_rel_a ON relationships(entity_a_id);
CREATE INDEX IF NOT EXISTS idx_rel_b ON relationships(entity_b_id);
-- Individual encounters between entity pairs
CREATE TABLE IF NOT EXISTS interactions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
entity_a_id TEXT NOT NULL REFERENCES entities(id),
entity_b_id TEXT NOT NULL REFERENCES entities(id),
location_id INTEGER NOT NULL REFERENCES locations(id),
interaction_type TEXT NOT NULL,
description TEXT NOT NULL,
notable_outcome TEXT,
book_of_ages_entry TEXT NOT NULL,
timestamp TEXT NOT NULL DEFAULT (datetime('now')),
world_day INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_int_timestamp ON interactions(timestamp);
CREATE INDEX IF NOT EXISTS idx_int_a ON interactions(entity_a_id);
CREATE INDEX IF NOT EXISTS idx_int_b ON interactions(entity_b_id);
CREATE INDEX IF NOT EXISTS idx_int_day ON interactions(world_day);
-- Autonomous world events
CREATE TABLE IF NOT EXISTS world_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
event_type TEXT NOT NULL,
title TEXT NOT NULL,
description TEXT NOT NULL,
affected_locations TEXT NOT NULL, -- JSON array of location slugs
entity_effect TEXT NOT NULL,
book_of_ages_entry TEXT NOT NULL,
mystery_hook TEXT,
timestamp TEXT NOT NULL DEFAULT (datetime('now')),
world_day INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_events_day ON world_events(world_day);
-- Unified history log β every public-facing entry in the Book of Ages
CREATE TABLE IF NOT EXISTS book_of_ages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
world_day INTEGER NOT NULL,
entry_type TEXT NOT NULL CHECK(entry_type IN
('arrival','interaction','world_event','milestone','dream_fragment')),
title TEXT, -- Optional: for world events and milestones
content TEXT NOT NULL, -- The actual prose entry
entity_ids TEXT NOT NULL DEFAULT '[]', -- JSON array of involved entity IDs
location_id INTEGER REFERENCES locations(id),
timestamp TEXT NOT NULL DEFAULT (datetime('now')),
is_milestone INTEGER NOT NULL DEFAULT 0 -- 1 for significant entries
);
CREATE INDEX IF NOT EXISTS idx_boa_day ON book_of_ages(world_day);
CREATE INDEX IF NOT EXISTS idx_boa_type ON book_of_ages(entry_type);
-- Session tracking (rate limiting and attribution)
CREATE TABLE IF NOT EXISTS sessions (
session_id TEXT NOT NULL PRIMARY KEY,
last_creation TEXT, -- Timestamp of last entity creation
creation_count INTEGER NOT NULL DEFAULT 0,
first_seen TEXT NOT NULL DEFAULT (datetime('now')),
last_seen TEXT NOT NULL DEFAULT (datetime('now'))
);
```
---
## 11. Frontend & UX Specification
### The Three Core Views
**View 1: The Realm (default)**
The world map and live activity feed. This is what visitors see first.
**View 2: Book of Ages**
Full scrollable history. Every event since Day 1.
**View 3: All Entities**
Grid of entity cards, filterable by location, type, and status. Searchable.
---
### Layout Specification (View 1)
```
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β THE THOUSAND TOKEN REALM Day 7 Β· 23 entities Β· 41 eventsβ
β [THE REALM] [BOOK OF AGES] [ALL ENTITIES] β
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ€
β β TODAY IN THE REALM β
β WORLD MAP β βββββββββββββββββββββββββββββββββ β
β (SVG, 60% of width) β A meteor shower passes over the β
β β Clock Forest. Old songs fall with β
β 8 location nodes β the meteorites. β
β with glow effects β β
β β RECENT ARRIVALS β
β Click node β β βββββββββββββββββββββββββββββββββ β
β slide-in panel β β The Blind Cartographer β Library β
β shows entities there β β The Fog Merchant β Moon Market β
β β β A Debt of Thirteen Sighs β Sea β
β β β
ββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββ€
β SUMMON SOMETHING INTO THE REALM β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Describe what you are bringing into the world... β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β [Summon β] Hint: "A wizard" is forgotten. "A wizard who β
β collects the sound of doors closing" is remembered β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
---
### World Map Specification
The map is an SVG element rendered server-side by `ui/map.py` and updated every 30 seconds via Gradio's `every` parameter.
**SVG Dimensions:** `viewBox="0 0 800 600"`, responsive width.
**Location Node:**
- Circle with radius 28px
- Glow effect via SVG filter (color per location)
- Pulsing animation if that location has the active world event
- Entity count shown as text inside or below the circle
- Up to 5 small dots around the circle edge representing individual entities
- Click β JavaScript event β Gradio component updates with that location's entities
**Path Between Locations:**
- Irregular SVG paths (not straight lines)
- Subtle, low-opacity
- Slightly wavy, organic-feeling
**Background:**
- Deep dark gradient (top to bottom: near-black β slightly blue-dark)
- Very subtle constellation dots (white, 5% opacity circles scattered across SVG)
- The map feels like a night sky viewed from above
**Entity Dots on Map:**
- Small circles (radius 5px) clustered around their location node
- Colored by entity type: character (amber), creature (deep red), object (silver), place (green)
- On hover: tooltip with entity name
- Max 5 visible dots per location; if more, show `+N` text
---
### Entity Card Specification
```
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β [CHARACTER βΈ Clock Forest] [Day 7 Β· Active] β
β β
β The Joke Dragon β
β ββββββββββββββββββββββββββββββββββββββββββββββββββ β
β A bronze-scaled dragon who smells faintly of β
β punchlines. Their left eye is a comedian's β
β old monocle. They laugh at their own jokes β
β half a second too early, which ruins them. β
β β
β SEEKS β
β The world's objectively worst joke β
β β
β SECRETLY β
β Wants someone to laugh first, just once β
β β
β FEARS β
β A joke with no audience β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββ β
β "Hello. I know 43 jokes. Would you like β
β the worst one?" β
β ββββββββββββββββββββββββββββββββββββββββββββββββββ β
β WHAT THEY REMEMBER β
β Won the mayorship. Owes a favor to the Cartographer β
β who mapped their cave. Still seeking the perfect β
β punchline. The Crystal Tree is their only friend. β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββ β
β 3 relationships Β· 12 encounters Β· Created by visitorβ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
---
### Location Slide-In Panel Specification
When a user clicks a location node on the map, a panel slides in from the right (or appears below the map on mobile):
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β [β] The Clock Forest β
β Trees grow backwards. The oldest are smallest. β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β 7 entities currently here β
β β
β [The Joke Dragon] [The Silent Gear] [+5 more] β
β β
β RECENT EVENTS HERE β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β Day 7: A meteor shower passed over. β
β Day 5: The Silent Gear and the Joke Dragon met. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
---
### Visual Style Guide
**Color Palette (all CSS custom properties, dark-mode native):**
```css
:root {
--realm-bg-primary: #0a0a12; /* Near-black, blue-dark */
--realm-bg-secondary: #111120; /* Cards, panels */
--realm-bg-tertiary: #1a1a2e; /* Elevated elements */
--realm-text-primary: #e8e0d0; /* Warm off-white */
--realm-text-secondary: #a09880; /* Muted text */
--realm-text-tertiary: #605848; /* Very muted */
--realm-accent-gold: #c8a040; /* Primary accent, Book of Ages headers */
--realm-accent-violet: #8060b0; /* Secondary accent */
--realm-border: rgba(200, 160, 64, 0.15); /* Subtle gold border */
--realm-border-strong: rgba(200, 160, 64, 0.35);
/* Location glow colors */
--loc-library: #c8a040; /* Amber/gold */
--loc-sea: #7090b0; /* Silver/blue */
--loc-clockforest: #b06020; /* Copper/orange */
--loc-moonmarket: #7040a0; /* Violet/purple */
--loc-valley: #405040; /* Earth green */
--loc-crossroads: #c04020; /* Warm red */
--loc-mirrorbogs: #304840; /* Dark teal */
--loc-mountain: #606060; /* Stone grey */
}
```
**Typography:**
- **World title / Location names:** 'Cinzel' (Google Font) β serif, engraved feeling
- **Entity names:** 'Libre Baskerville' (Google Font) β readable serif
- **Book of Ages text:** 'EB Garamond' (Google Font) β old book feeling
- **UI / body text:** System UI stack β clean, readable
- **Greeting text:** Italic, slight golden tint
**Animations:**
- Entity appearing on map: `fade-in + scale(0.5 β 1)` over 600ms
- Active world event location: subtle `pulse-glow` keyframe animation
- New Book of Ages entry: `slide-up + fade-in` from below
- Loading state: slow rotating constellation pattern
- Location hover: `glow-intensify` on the SVG circle
**gr.Server Setup (for Off-Brand Award):**
```python
import gradio as gr
demo = gr.Blocks(
css=open("ui/styles.css").read(),
title="The Thousand Token Realm",
theme=gr.themes.Base(
primary_hue=gr.themes.colors.amber,
neutral_hue=gr.themes.colors.slate,
font=[gr.themes.GoogleFont("Libre Baskerville"), "Georgia", "serif"],
),
)
```
---
## 12. Hackathon Prize Strategy
### Track: Thousand Token Wood
**Why this wins the track:**
The premise fulfills all four judging criteria simultaneously:
- *Genuinely delightful (would you show a friend?):* A world that has been alive for 7 days when they open it β yes.
- *AI is load-bearing:* Remove the model and there is no world. There is a database with text.
- *Originality:* Persistent, multi-user, autonomous AI worlds at this aesthetic fidelity do not exist at this scale on this stack.
- *Polish of the Gradio app:* The mystical UI is the most distinctive possible contrast to default Gradio.
### Prize Target Matrix
| Prize | Eligibility | Notes | Confidence |
|-------|-------------|-------|-----------|
| Track 2 Main β 1st/2nd/3rd | Core track | The premise is designed for this track | High |
| Best Agent ($1,000) | Autonomous simulation = agentic system | Hourly Modal job doing reasoning + action | High |
| Off-Brand Award ($1,500) | Custom SVG map + mystical CSS via gr.Server | Most distinctive UI in the field | High |
| Best Demo ($1,000) | A world already alive for days = the demo | History visible, entities visible, events visible | High |
| Judges' Wildcard ($1,000) | Completely original category | Nothing else like it in the field | High |
| Community Choice ($2,000) | Collaborative by design | The community literally built the world | Medium |
| Modal Award | Using Modal for inference + scheduled jobs | Core to the architecture | Medium-High |
| OpenBMB Award | If using a MiniCPM or OpenBMB model | Swap Qwen for MiniCPM-3-4B to qualify | Medium |
### Badge Strategy
| Badge | Action Required | Effort | Recommendation |
|-------|----------------|--------|---------------|
| Off the Grid π | No cloud APIs | Conflicts with Modal | Skip β Modal is more important |
| Well-Tuned π― | Fine-tune model on HF, publish | Medium β Day 8 | YES β worth the effort |
| Off-Brand π¨ | Custom UI via gr.Server | Built-in to design | YES β earned by default |
| Llama Champion π¦ | Use llama.cpp runtime | Conflicts with Modal | Skip |
| Sharing is Caring π‘ | Share agent traces on Hub | 2 hours | YES β log entity generation traces |
| Field Notes π | Write HF blog post | 3 hours | YES β write it while building |
**Target: 4 badges** β Well-Tuned + Off-Brand + Sharing is Caring + Field Notes
**Note on the Off the Grid / Modal trade-off:**
Using Modal means losing Off the Grid. This is correct. The world only works for multiple concurrent users with fast inference. A slow local model on a free HF Space cannot serve 10 users simultaneously. Choose Modal + product quality over the badge.
---
## 13. 10-Day Build Plan
### MVP Definition (must exist by Day 8 to submit confidently)
- [x] Entity creation + AI generation working end-to-end
- [x] SQLite database with all schema tables
- [x] World persists across Space restarts (HF Dataset backup)
- [x] World map with all 8 locations showing entity counts
- [x] Entity profile visible on click
- [x] Book of Ages showing at least 3 days of history
- [x] At least 1 autonomous simulation tick has run
- [x] Pre-seeded world (interesting entities already present on Day 1)
- [x] Rate limiting for entity creation
- [x] Custom CSS (mystical theme applied)
### Nice-to-Have (add if time allows in Days 9β10)
- [ ] Relationship graph visualization
- [ ] Entity search and filter in All Entities view
- [ ] "What's happening right now" live pulse feed
- [ ] Mobile-responsive layout adjustments
- [ ] Location slide-in panel fully animated
- [ ] Dream fragment display (Valley special property)
---
### Day-by-Day Schedule
**Day 1 (June 5) β Foundation & Generation Quality**
- Set up HF Space (private for now)
- Set up Modal account; deploy basic Qwen 2.5 7B with the WorldOracle class
- Create all 5 prompt templates in `ai/prompts.py`
- Run 20+ test generations manually: *"A blind cartographer", "A fog that remembers voices", "A compass made of grief"*
- Iterate prompts until output quality is consistently strange and specific
- Goal: AI output is excellent before writing any frontend
**Day 2 β Database & Entity CRUD**
- Run complete schema SQL
- Seed all 8 locations with their full data (from Section 3)
- Write `world/entities.py` β create, read, update, list by location
- Write `world/book_of_ages.py` β create entry, read by day, read by entity
- Write `persistence/backup.py` β push/pull SQLite to HF Dataset
- Write `ai/generation.py` β call Modal, parse JSON, retry on failure, save to DB
- CLI test: `python test_entity.py "A weaver who collects echoes"` β see full profile saved
**Day 3 β Basic Gradio App**
- `app.py` with gr.Blocks
- Simple entity creation form with loading state
- Entity profile displayed as styled HTML (not raw JSON)
- Book of Ages displayed as styled Markdown
- Verify: type description β wait β see entity profile β see Book of Ages entry
- Keep everything working before adding map
**Day 4 β World Map**
- Build `ui/map.py` β SVG generator function
- Place all 8 location nodes with correct coordinates
- Show entity count on each node
- Connect with irregular paths
- Add location glow colors
- Integrate into Gradio with `gr.HTML(every=30)`
- Add location click β show entity list panel (start with simple Markdown list)
**Day 5 β Persistence & Stability**
- Test HF Dataset backup fully (write β restart Space β verify world still there)
- Test concurrent entity creation (2 users at once)
- WAL mode verified
- Rate limiting working
- Add pre-seeded starter entities to `seed_world.py` (create 10β15 interesting entities)
- Run `seed_world.py` β world now has history from Day 1
- Deploy to HF Space (still private) β verify it works live
**Day 6 β Interaction & Simulation Tick**
- Write `ai/interaction.py` with full interaction prompt
- Write `simulation/tick.py` β the complete 7-step tick from Section 6
- Write `simulation/modal_schedule.py` β Modal scheduled hourly job
- Run the tick 5 times manually β verify interactions appear in Book of Ages
- Write world event generation with full prompt
- Verify: after 5 ticks, the world has a real history with relationships forming
**Day 7 β Full Custom UI Polish**
- `ui/styles.css` β complete custom CSS with all CSS variables, animations, fonts
- `gr.Server` setup with custom theme
- Entity card HTML template (as specified in Section 11)
- Location slide-in panel
- World map node pulse animation for active events
- Entity arrival animation on map
- Make HF Space public
**Day 8 β Fine-Tuning (Well-Tuned Badge)**
- Collect 300β500 entity generation examples from all your testing (input β JSON output pairs)
- Add 200 synthetic examples generated via the base model
- Format as HF dataset
- Fine-tune Qwen 2.5 3B Instruct (smaller for faster training) using HF AutoTrain or Axolotl
- Compare: base model vs fine-tuned on 10 new descriptions
- If fine-tuned is better or equal: deploy to Modal, update `modal_client.py`
- Publish fine-tuned model to HF Hub with a good model card
**Day 9 β Testing + Sharing is Caring Badge**
- Full end-to-end test: 10 new entities, 3 manual ticks, verify history
- Generate and publish agent traces to HF dataset (every entity generation β log input/output/latency)
- Write blog post draft in `FIELD_NOTES.md` (publish to HF in Day 10)
- Set UptimeRobot to ping the HF Space URL every 25 minutes (keeps it awake)
- Fix all bugs found in testing
**Day 10 (June 14β15) β Demo + Submit**
- Set Modal `keep_warm=1` for demo period
- Run world for "7 simulated days" (7 manual ticks) so history is rich
- Record demo video (see Section 15)
- Publish `FIELD_NOTES.md` as HF blog post
- Write and post social media update
- Submit to hackathon with all required links
---
## 14. Budget: Modal & HF Credits
### Modal ($250 Credits)
**Usage breakdown:**
| Task | Duration | GPU Cost | Frequency | Total |
|------|----------|----------|-----------|-------|
| Entity generation | ~8 seconds/entity | ~$0.003 | ~500 over 10 days | ~$1.50 |
| Hourly simulation tick | ~90 seconds/tick | ~$0.027 | 240 ticks (10 days Γ 24) | ~$6.50 |
| Fine-tuning (if using Modal) | ~2 hours | ~$2.20/hr | Once | ~$4.40 |
| Development and testing | Variable | Variable | Throughout | ~$15.00 |
| Demo day (keep_warm=1, ~6hr) | 6 hrs continuous | ~$6.60/hr | Once | ~$40.00 |
| **Total estimated spend** | | | | **~$68** |
| **Remaining buffer** | | | | **~$182** |
**Key setting:** Keep `keep_warm=0` during development. Only set `keep_warm=1` for the final demo recording and during judging. Cold starts (~15-20 seconds) are acceptable during development but not during the demo.
### HF Credits ($20)
**Recommendation: Do not spend on inference.** Modal covers that far better.
**Best uses:**
1. GPU-tier HF Space if needed (prevents any compute limitations on the Space itself β $0.05/hr for a basic GPU Space if needed). Probably not necessary.
2. Keep as a buffer for unexpected needs.
**Free HF resources (no credits needed):**
- Private dataset repo for SQLite backup: Free
- Model hosting for your fine-tuned model: Free
- HF Space (CPU tier): Free
- HF AutoTrain for fine-tuning: Uses Compute Credits, partially covered by $20
### Keeping HF Space Alive
HF Spaces sleep after 48 hours of no traffic on free tier. Solution:
- Register a free account at UptimeRobot (https://uptimerobot.com)
- Set a monitor to ping your Space URL every 25 minutes
- This is free and keeps the Space awake indefinitely
---
## 15. Demo & Submission Strategy
### Pre-Demo Setup
Before recording, the world needs to already be alive. Run this sequence:
1. `python seed_world.py` β creates 12 starter entities across all locations
2. Run simulation tick 7 times (one per "day") β creates real history, relationships, events
3. Verify: Book of Ages has at least 20 entries across 7 days
4. Verify: at least 3 relationships have formed
5. Verify: at least 1 entity has reached a milestone (Mayor, ally, etc.)
6. Set Modal `keep_warm=1`
7. Test entity creation once more β timing should be fast
### Demo Script (90 seconds target)
**0:00 β 0:12** β Open the app. World map visible. Entity dots glowing.
*"This world has existed for 7 days. Other people have been building it."*
**0:12 β 0:28** β Open Book of Ages. Scroll slowly through 7 days of history.
*"Here's what happened. Nobody scripted any of this. The AI decided all of it."*
β Pause on one interesting event (The Dragon becoming Mayor is perfect)
**0:28 β 0:48** β Return to the Realm view. Type a new entity live:
*"A clockmaker who is afraid of her own clocks"*
Click Summon. Wait for generation (loading animation visible).
Profile appears. Entity appears on map. Arrival note visible in activity feed.
**0:48 β 1:05** β Click the entity's location on the map. Show the entities currently there.
Click the new entity's profile. Show full card: appearance, backstory, greeting, memory (empty, she just arrived).
**1:05 β 1:20** β Click another entity on the map (one of the pre-seeded ones with history).
Show their memory: "Has collected 43 jokes. Won the Mayorship. Owes the Cartographer a favor."
*"This one has been here for 7 days. It remembers specific things."*
**1:20 β 1:30** β Final frame: world map, all locations lit, entity dots visible.
*"The Thousand Token Realm. Running on a 7-billion-parameter model. Alive whether you're watching or not."*
### Social Post
```
I built a persistent fantasy world running on a 7B model.
Day 1: A Crystal Tree appeared.
Day 4: The Lantern Foxes settled by the river.
Day 7: The Joke Dragon became Mayor.
Day 10: Something large shifted in the Valley.
Nobody scripted any of it. The AI decided.
Come add something: [HF Space link]
Built for @GradioML Γ @HuggingFace hackathon.
#TTR #BuildInPublic #SmallModels #Gradio
```
### Submission Checklist
- [ ] HF Space is public and loading correctly
- [ ] Entity creation works without errors
- [ ] Book of Ages has 7+ days of history
- [ ] World map shows all 8 locations with entities
- [ ] Modal scheduled job is running (check logs)
- [ ] HF Dataset backup has at least 1 recent snapshot
- [ ] Fine-tuned model published to HF Hub (Well-Tuned badge)
- [ ] Agent traces published to HF dataset (Sharing is Caring badge)
- [ ] Field Notes blog post published on HF (Field Notes badge)
- [ ] Demo video recorded (90 seconds, screen recorded)
- [ ] Social post published and link saved
- [ ] Submission form completed with all links
---
## 16. Risk Register
| Risk | Probability | Impact | Mitigation |
|------|------------|--------|------------|
| AI output quality too inconsistent | Medium | High | Extensive prompt testing on Day 1 before any frontend work. Retry with lower temperature on failure. |
| HF Space sleeps β simulation stops | Medium | Medium | UptimeRobot ping every 25 minutes. Modal scheduled job runs independently of Space. |
| SQLite concurrent write conflict | Low | Medium | WAL mode enabled. All writes in transactions. Single-writer pattern in tick. |
| World state lost on Space restart | Medium | High | HF Dataset backup every 5 minutes. Tested explicitly on Day 5. |
| Entity generation too slow for UX | Low | Medium | Modal keep_warm=1 during demo. Animated loading state to manage expectation. |
| Inappropriate user input | Medium | Medium | Simple content filter before AI call. Budget one day for moderation edge cases. |
| Modal cold start during demo recording | Medium | Medium | keep_warm=1 on demo day. Test generation 3Γ before recording. |
| Fine-tuning doesn't improve quality | Low | Low | Fine-tuning is optional. The Well-Tuned badge is worth attempting but base model is sufficient to submit. |
| World becomes incoherent as it grows | Medium | Medium | Location system naturally scopes interactions. Memory compression keeps entity context bounded. |
| 10 days is not enough for full vision | Medium | High | MVP is defined clearly. Days 8β10 are polish, not core. If time runs short, cut nice-to-haves and protect the MVP. |
| Too many users overwhelming Modal during demo | Low | Low | Modal auto-scales. At $250 budget, this won't be a cost issue at hackathon traffic levels. |
---
*Specification version 1.0*
*World founding date: First successful deployment*
*The judges will open a world that is already alive.*
*That is the entire strategy.*
|