HBOx is a Unity project for generating and replaying AI-driven "Chats": short staged scenes with a cast, location, dialogue, sentiment, timing, and audio. The project started as polbots, but it now acts more like a shared runtime for multiple shows and worlds.
The current project is split into two main layers:
Assets/CoreShared engine code for chat generation, playback, actor control, UI, config loading, external integrations, replay loading, and prompt resolution.Assets/ScenesShow-specific scenes, actors, prefabs, audio, and scene adapters.
At a high level, the pipeline looks like this:
- A source provides an
Idea. Sources include replay folders, Reddit batches, HTTP endpoints, and scene-specific systems like thepolbotssoccer integration. ChatGeneratorturns the idea into aChat. It resolves prompt files fromVault, asks the LLM for topic/cast/location details, then runs attached generator components to fill in dialogue, reactions, voice lines, vibe, memories, and related metadata.ChatManagerqueues and plays the chat. It switches to the correct scene/context, loads staging information, spawns actors, runs intermission hooks, and activates eachChatNodein sequence.ActorControllerand scene components perform the scene. Shared actor subsystems handle animation, face/lips, camera look targets, voice playback, items, subtitles, and scene-specific behavior.
The original project, and still the heaviest scene-specific code layer.
Responsibilities:
- video-call presentation and per-actor cameras
- globe-mode staging and map-driven positioning
- country/flag-driven visuals
- soccer match integration that can emit live ideas back into the chat pipeline
Mostly a content/world pack on top of the shared core. It currently has very little custom C# and relies primarily on shared generation/playback behavior plus its own actors, prefabs, and assets.
Uses the shared core runtime with show-specific scene assets and actor data. No custom scene-side C# currently lives here.
Also uses the shared core runtime with its own cast, prefabs, and assets, with no current scene-side C# layer.
Assets/CoreRuntime systems shared across all shows.Assets/ScenesShow scenes and content.VaultPrompt, input, output, and other text assets used during generation.MemoryCapturesMemory-related data produced by the project.replays-*.txtLocal replay history trackers.reddit-*.txtLocal Reddit history trackers.
The project loads config.json from the executable root path through ConfigManager.
Each config entry must contain a Type field. Only the systems present in your scene/context need to be configured.
Example:
[
{
"Type": "openai",
"ApiUri": "https://api.openai.com",
"ApiKey": "YOUR_OPENAI_API_KEY",
"SlowModel": "gpt-4o",
"FastModel": "gpt-4o-mini",
"UseEmbeddings": false
},
{
"Type": "tts",
"GoogleApiKey": "YOUR_GOOGLE_TTS_KEY",
"OpenAiApiKey": "YOUR_OPENAI_TTS_KEY"
},
{
"Type": "discord",
"AvatarURL": "https://...",
"WebhookURLs": {
"#stream": "YOUR_STREAM_WEBHOOK_URL"
},
"EnableBot": true,
"BotToken": "YOUR_BOT_TOKEN",
"ApplicationId": "YOUR_APP_ID",
"SlashCommandGuildIds": ["YOUR_TEST_GUILD_ID"],
"EnableIdeaCommand": true,
"DefaultDailyIdeaLimit": 3,
"BoosterDailyIdeaLimit": 10,
"BoosterRoleIds": ["BOOSTER_ROLE_ID"]
},
{
"Type": "folder",
"ReplayDirectory": "polbots",
"ReplayRate": 80,
"ReplaysPerBatch": 20,
"MaxReplayAgeInMinutes": 1440
},
{
"Type": "reddit",
"SubReddits": {
"worldnews+anime_titties+todayilearned": "Default",
"AskHistorians+UnitedNations+geopolitics": "History",
"Africa+China+america+australia+europe": "Regional"
},
"MaxPostAgeInHours": 24,
"BatchSize": 20,
"BatchSizeLimit": 20,
"BatchIterations": 1,
"BatchPeriodOffset": "00:00",
"BatchPeriodInMinutes": 480,
"ActiveHoursStart": "00:00",
"ActiveHoursEnd": "23:59",
"MaxDepth": 3,
"TopRoots": 3,
"TopLevelLimit": 30,
"PerLevelChildLimit": 20,
"MaxDialogueLines": 16,
"MaxCharsPerLine": 280,
"Sort": "confidence"
},
{
"Type": "obs",
"VideosFolder": "C:/Videos/HBOx",
"OBSWebSocketURI": "ws://localhost:4455",
"IsStreaming": false,
"IsRecording": false,
"DoSplitRecording": true,
"OnlyNewEpisodes": true
},
{
"Type": "splash",
"Splashes": [
"Tonight on HBOx",
"Previously on nothing"
],
"TitleDuration": 5.0,
"SplashDuration": 2.0
}
]- Remove a config block entirely to disable that integration.
folderis the active replay loader type registered at runtime.reddit.SubRedditsis a dictionary, not a simple string array.- OpenAI text generation and OpenAI TTS are configured separately.
- Some integrations only matter in specific scenes, such as
soccerinpolbots.
soccer is scene-specific and currently powers three separate match-time layers in polbots:
Lines: live event narration text and residueInterruptSeeds: short pre-generated reaction seeds for injected micro-chats- announcer settings: optional TTS playback for narrated event lines
Example:
{
"Type": "soccer",
"MatchTimeLimit": 10,
"TimeBetweenGames": 0,
"MaxVolume": 1.0,
"EnableAnnouncer": true,
"AnnouncerVolume": 0.9,
"MaxAnnouncerQueue": 4,
"SkipAnnouncerDuringInterrupts": false,
"AnnouncerVoice": "alloy",
"ClearSceneOnGameEnd": true,
"RequireTextPatternMatch": false,
"GameOnStart": false,
"GameOnBatchEnd": false,
"GameOnMatchEnd": false,
"Lines": {
"FirstWhistleEvent": [
"The whistle blows.",
"And we're off.",
"Kickoff."
],
"FinalWhistleEvent": [
"# That's the final whistle! {1}",
"# Game over! {1}",
"# And that's full-time! {1}"
],
"RefereeShortWhistleEvent": [
"Quick whistle!",
"What's the call?",
"The ref steps in!"
],
"BallHitTheWoodWorkEvent": [
"SO CLOSE!",
"Denied by the post!",
"Off the bar!"
],
"PlayerSlideTackleEvent": [
"{0} lunges in!",
"{0} goes for the slide tackle!",
"{0} clatters into them!"
]
},
"InterruptSeeds": {
"Pregame": [
"Kickoff is approaching. Deliver a very short pregame beat about nerves, legitimacy, betting chatter, or alliance rivalry before play starts.",
"The match is about to begin. Deliver a very short pregame beat about diplomatic pageantry, procedural anxiety, or quiet panic before kickoff."
],
"GoalScoredEvent": [
"A goal has just been scored. React briefly and sharply without naming a specific score or minute.",
"A goal has changed the atmosphere instantly. Deliver a short reaction about humiliation, momentum, or political overreaction without citing exact numbers."
],
"RefereeShortWhistleEvent": [
"The referee has interrupted play. Deliver a brief reaction about procedure, officiating, corruption, or legitimacy.",
"A quick whistle just cut through the match. React briefly to the call, the process, or immediate suspicion of bias."
],
"KeeperSavesTheBallEvent": [
"A dramatic save just happened. React briefly without naming a specific score or minute.",
"The keeper just denied what looked inevitable. Deliver a short reaction about survival, theft, or divine intervention without exact numbers."
],
"BallHitTheWoodWorkEvent": [
"A near miss just rattled the stadium. React briefly without naming a specific score or minute.",
"The ball hit the woodwork and everything nearly changed. Deliver a short reaction about fate, robbery, or nerves without exact numbers."
],
"PlayerSlideTackleEvent": [
"A hard tackle just changed the emotional temperature of the match. Deliver a brief reaction.",
"A heavy slide tackle just landed. React briefly about aggression, legitimacy, revenge, or selective outrage."
]
}
}Notes:
Linesare short event phrases used for live narration, residue, and the optional announcer voice layer.InterruptSeedsare not dialogue output; they are brief generation seeds used to prebuild character reaction packets.- Keep
InterruptSeedsgeneric enough that pre-generated packets do not go stale immediately when the score changes. - Full-scene soccer framing now lives in Vault under
Vault/polbots/Prompts/Soccer Mode/Idea Seeds.
Generated chats are serialized to the user's Documents folder under a per-show directory:
Documents/<ShowName>/<chat-slug>.json
Those replay files can later be reloaded by the folder replay source and mixed back into the queue.
Prompt inputs and outputs are also written under Vault/<ShowName>/Inputs/... and Vault/<ShowName>/Outputs/... as generation runs.
ChatManagerContextdefines a show's cast, sentiments, spawn points, audio, config manager, and scene identity.- Scene-specific scripts should generally subscribe to core events instead of replacing the playback pipeline.
- If a show only needs different actors, prefabs, prompts, and locations, it can usually be built without adding new scene-side C#.
Older docs, file names, and comments may still refer to polbots. In the current project, that is just one show/context inside the larger HBOx runtime.