{capabilities.aleActiveRecently?'GAME SERVER LIVE':state?.settings.connector==='azerothcore'?'Native game bridge':'SIMULATION REALM'}{readOnly?'Visitor · Read only':'GM workspace'}
{page==='GM Console'?'THE WORLD IS YOUR SANDBOX':'AZEROTHAI CONTROL PLANE'}
{page==='Dashboard'?'Your realm, alive.':page}
{({'Dashboard':'The people, personalities, and stories that make your world.','World Monitor':'Watch Azeroth breathe: population, activity, systems, and the lives unfolding right now.','Realm Director':'Shape the adventure around you. Let your characters bring it to life.','World & Housing':'Homes, routines, simulation bands, and believable population flow.','Bots':'Give every character a purpose, then let their story unfold.','Bot Recipes':'Same model. Different personalities. A world of possibilities.','Memory & Bonds':'A shared history makes the next encounter matter.','Event Stream':'Follow the decisions and changes happening across your realm.','GM Console':'Pull up a chair. Put on the blue robe. Run your world.','Server & Models':'Connect the game engine and the minds behind your characters.'} as any)[page]}
{[[Users,'Active bots',state.bots.filter(b=>b.status==='online'&&(state.settings.connector==='simulation'||b.autonomy?.managed)).length,'Online in the simulation'],[BookOpen,'Bot recipes',state.recipes.length,'Distinct ways to experience the world'],[Brain,'Memories',state.bots.reduce((n,b)=>n+b.memories.length,0),'Stories carried into future decisions'],[Network,'Relationships',state.bots.reduce((n,b)=>n+b.relationships.length,0),'Directed bonds between characters']].map(([Icon,label,value,note]:any)=>
{label}
{value}
{label==='Active bots'&&state.settings.connector!=='simulation'?'Acknowledged by the game bridge':note}
{state.settings.provider==='deterministic'?'No model required. Try a decision from any online bot.':'Local model selected. Each decision includes identity and memories.'}
nav('Event Stream')}>View stream }>{}
Set the scene. Announce a gathering. Move a character to the next chapter of their story.
AzerothAI shapes identity and intent. The game server owns the rules of the world.
{if(!o)setBotId(null)}}>Bot profileIdentity, intent, and the story so far.{selected&&state&&}{if(!o)setConfirm(null)}}>{confirm?.title}{confirm?.description}Cancel{if(confirm)perform(confirm.action);setConfirm(null)}}>Confirm;
}
function CreateBot({state,act,busy,close}:any){const [name,setName]=useState(''),[role,setRole]=useState('Priest'),[race,setRace]=useState('Human'),[recipeId,setRecipeId]=useState(state.recipes[0].id),[goal,setGoal]=useState(`Support ${state.director.experience.toLowerCase()} in ${state.director.zone}`);return }
function RecipeEditor({recipe,act,busy,close}:any){const [r,setR]=useState(recipe??{name:'',description:'',tags:['Curious'],sociability:50,aggression:20,curiosity:70,economy:30,activities:['explore','quest']});const [tags,setTags]=useState(r.tags.join(', '));return }
function BotProfile({bot:b,state,act,busy,perform,confirm,readOnly=false,fixedRoster=false}:any){const [memory,setMemory]=useState(''),[importance,setImportance]=useState(7),[target,setTarget]=useState(state.bots.find((x:Bot)=>x.id!==b.id)?.id??''),[affinity,setAffinity]=useState(40),[note,setNote]=useState(''),[recipeId,setRecipeId]=useState(b.recipeId);const actions=fixedRoster?[]:b.status==='online'?['pause','despawn']:b.status==='paused'?['resume','despawn']:b.status==='offline'?['spawn','retire']:[];return <>
{b.name}
Level {b.level} {b.race} {b.role}
{b.status}
IdentityMemoryRelationships
Current goal
{b.goal}
{b.zone}
{b.personality.name} v{b.recipeVersion}
{b.personality.description}
{b.personality.tags.map((t:string)=>{t})}
Latest decision
{b.lastDecision?`${b.lastDecision.action}: ${b.lastDecision.reason}`:'No decisions yet. Run a decision while this bot is online.'}
No authoritative ALE world events have arrived yet. When the playable realm is online, login, combat, zone, quest, weather, and other server events will appear here.
>
}
function Director({state,act,busy}:any){const [d,setD]=useState(state.director);return
Characters, not background noise
A healer who remembers you. A trader with an agenda. A familiar rival on the road.
Direction, not a scripted outcome
Your brief goes into bot goals. Personality, memory, and available actions influence their next choice.
The game stays the game
The game connector translates intent. AzerothCore resolves movement, combat, loot, and progression.
Live Playerbots continue playing under AzerothCore even with no human online. AzerothAI periodically adds personality-, memory-, and goal-driven high-level intentions for authoritatively observed residents.
Latest 500 events · replay on reconnect}>kind==='all'||e.kind===kind)}/>>}
function Settings({state,act,busy,capabilities}:any){
const [s,setS]=useState(state.settings),[health,setHealth]=useState('');
const brains=s.brains;
const setBrains=(patch:any)=>setS({...s,brains:{...brains,...patch}});
return
setS({...s,connector})} items={[{value:'simulation',label:'Simulation · Ready to use'},{value:'azerothcore',label:'Live game server · Native bridge'}]}/>
Game bridge configured{capabilities.bridgeConfigured?'Yes':'Not yet'}
ALE control plane{capabilities.aleConfigured?'Configured':'Not yet'}
setS({...s,provider})} items={[{value:'deterministic',label:'Personality simulator · No model needed'},{value:'ollama',label:'Ollama · Local inference'},{value:'openai-compatible',label:'OpenAI-compatible endpoint'}]}/>
setBrains({enabled})}/>
setBrains({backgroundUseLLM})}/>
Local model endpoint configured{capabilities.llmConfigured?'Yes':'Not yet'}
Default: Qwen3.5 4B for residents and Zaku. Background residents stay on deterministic utility logic unless enabled here, saving CPU for foreground conversations and important decisions.
Movement → combat → inventory → world rules → authoritative events
}
function GM({state,act,busy,capabilities,setConfirm}:any){const [command,setCommand]=useState('.server info'),[live,setLive]=useState(false),[history,setHistory]=useState([]),[index,setIndex]=useState(-1);const gmEvents=state.events.filter((e:RealmEvent)=>e.kind==='gm'||e.kind==='error').slice(-30);const shortcuts=[['Server info','.server info'],['World announcement','.announce Travelers, gather at the gates of Stormwind!'],['Teleport character','.teleport name Yourname Stormwind'],['Character info','.pinfo Yourname'],['Message of the day','.server motd']];return
{live?'Commands will execute on your configured worldserver.':'Simulation mode. No connection to a real worldserver.'}
{gmEvents.length?gmEvents.map((e:RealmEvent)=>
{new Date(e.at).toLocaleTimeString()}
{e.message}
):
Type .server info to get started.
}
{shortcuts.map(([label,cmd])=>)}
Live commands use the configured game server and require confirmation. Supported commands are limited to this toolbox; bot models cannot issue them.
In-game commands such as .gm on, .gm visible off, and .summon need your logged-in GM character. This web console has no character position or selected target.
The first prototype provides remote announcements, named teleports, and server/player information. More GM powers can be added explicitly.