src/main.tsx
import {SettingsPage} from './Settings';
import React, {lazy,Suspense,useEffect,useMemo,useRef,useState} from "react";
import {LivePopulation} from './LivePopulation';
import {ItemSearchInput} from './blackrock/ItemSearchInput';
import type {CoordinationContext} from '../shared/coordination';
import type {CoordinationPlanSelection} from './coordination/CoordinationMapPanel';
import type {MissionResearchSelection} from '../shared/logistics';
const CoordinationMapPanel=lazy(()=>import('./coordination/CoordinationMapPanel').then(m=>({default:m.CoordinationMapPanel})));
import {MissionStatusBar} from './missions/MissionStatusBar';
import {useResearchLayers} from './useResearchLayers';
const SwarmWorkspace=lazy(()=>import('./swarms/SwarmWorkspace'));
const MissionWorkspace=lazy(()=>import('./missions/MissionWorkspace'));
import {AssistantPanel} from './assistant/AssistantPanel';
import {isResearchSection,initialSection,readLanding,sectionUrl,researchSection,type ResearchSection} from './blackrock/navigation';
import BlackrockWorkspace from './blackrock/LazyBlackrockWorkspace';
import type {Entity} from './blackrock/api';
import {readPaneFilters,type PaneFilter} from '../shared/pane-controls';
import { createRoot } from "react-dom/client";
import {
Search,
Map,
Globe,
Users,
Activity,
Database,
Terminal,
ChevronRight,
ChevronDown,
Crosshair,
Bookmark,
Layers,
Navigation,
MapPin,
X,
ArrowUpRight,
Download,
Radio,
Shield,
Sword,
Eye,
Code,
Clock,
Maximize2,
Minimize2,
Copy,
Check,
Plus,
Minus,
Box,
LockKeyhole,
SlidersHorizontal,
Target,
Sparkles,
} from "lucide-react";
import {CombatZoneBadge} from './CombatZoneBadge';
import {WorldToolbar} from "./WorldToolbar";
import { WorldViews } from "./WorldViews";
import {PinnedAtlas} from "./PinnedAtlas";
import { FollowMonitors } from "./FollowMonitors";
import { ViewerCommands, initialViewCamera, monitorHref, addFollowMonitor, type ViewCamera, type ViewCommand } from "../shared/viewer-session";
import { OperationsPanel, BotOperations, TeamFilter } from "./Operations";
import { bindingsForTeam, botKey } from "../shared/operations";
import { LocationShortcuts } from "./LocationShortcuts";
import { LOCATIONS } from "../shared/locations";
import { DeathRisk } from "./DeathRisk";
import { ItemSprite } from "./ItemSprite";
import {
Theme,
TextField,
TextArea,
Checkbox,
Badge,
Card,
Table,
SegmentedControlRadioGroup,
Tooltip,
Popover,
} from "@whop/react/components";
import { Button, FilterSelect } from "./ui";
import "@whop/react/styles.css";
import "./dither-theme.css";
import "./style.css";
import "./frosted.css";
import "./world.css";
import "./blackrock-shell.css";
import "./responsive-workspace.css";
import "./live-population.css";
const fmt = (v: any) => (v == null ? "—" : Number(v).toLocaleString());
const age = (t: any) =>
!t
? "unobserved"
: `${Math.max(0, Math.floor((Date.now() - t) / 1000))}s ago`;
const time = (t: number) =>
new Date(t).toLocaleTimeString([], { hour12: false });
const label = (v: string) => v.replaceAll("_", " ");
async function request(path: string, body?: any, method?: string) {
const r = await fetch(
path,
body !== undefined
? {
method: method ?? "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
}
: method
? { method }
: undefined,
);
const data = await r.json();
if (!r.ok) throw new Error(data.error ?? "Request failed");
return data;
}
function usePoll(path: string | null, ms = 1500) {
const [data, setData] = useState<any>(null);
const [error, setError] = useState("");
useEffect(() => {
setData(null);
setError("");
if (!path) return;
let stopped = false,
timer: ReturnType<typeof setTimeout>;
const abort = new AbortController();
async function poll() {
try {
const r = await fetch(path!, { signal: abort.signal });
const d = await r.json();
if (!r.ok) throw new Error(d.error || "Source unavailable");
if (!stopped) {
setData(d);
setError("");
}
} catch (e) {
if (!stopped)
setError(e instanceof Error ? e.message : "Connection lost");
}
if (!stopped) timer = setTimeout(poll, ms);
}
poll();
return () => {
stopped = true;
clearTimeout(timer);
abort.abort();
};
}, [path, ms]);
return { data, error };
}
function Empty({
title,
children,
}: {
title: string;
children?: React.ReactNode;
}) {
return (
<div className="empty">
<Target size={26} />
<h3>{title}</h3>
<p>{children}</p>
</div>
);
}
function Json({ data }: { data: any }) {
return <pre className="json">{JSON.stringify(data, null, 2)}</pre>;
}
const SIGNALS: Record<string, string> = {
an: "Animation [sequence, delay]",
sp: "Spot animation [ID, height, delay]",
fe: "Facing entity",
fs: "Facing fine coordinates",
hm: "Damage [amount, type]",
hp: "Reported HP [current, max]",
ch: "Public chat",
sy: "Overhead text",
m: "Step directions",
tp: "Movement discontinuity",
em: "Forced movement",
cc: "Chat colour / effect",
};
function EventRows({
events,
onEntity,
onFly,
compact = false,
}: {
events: any[];
onEntity: (name: string) => void;
onFly: (x: number, z: number) => void;
compact?: boolean;
}) {
return (
<div className={`event-list ${compact ? "compact" : ""}`}>
{events.length === 0 ? (
<Empty title="Listening for observations">
Events appear as the feed publishes them in the current observation
area.
</Empty>
) : (
events.map((e) => (
<div className={`event-row event-${e.kind}`} key={e.id}>
<time>{time(e.at)}</time>
<span className="event-kind">{label(e.kind)}</span>
<Button
className="entity-link"
onClick={() =>
e.entity && !e.entity.startsWith("npc:")
? onEntity(e.entity)
: e.payload.x && onFly(e.payload.x, e.payload.z)
}
>
{e.entity ?? "Console"}
</Button>
<span className="event-value" title={JSON.stringify(e.payload)}>
{e.kind === "equipment"
? e.payload.equipment?.map((i: any) => i.name).join(", ") ||
"No visible worn items"
: typeof e.payload.value === "string"
? e.payload.value
: e.payload.value !== undefined
? JSON.stringify(e.payload.value)
: (e.payload.note ??
e.payload.name ??
e.payload.kind ??
e.payload.meaning ??
`${e.payload.x ?? ""} ${e.payload.z ?? ""}`)}
</span>
{!compact && e.payload.x !== undefined && (
<Button
className="icon"
aria-label={`Fly to event ${e.id}`}
onClick={() => onFly(e.payload.x, e.payload.z)}
>
<Navigation size={13} />
</Button>
)}
</div>
))
)}
</div>
);
}
function Inspector({
selection,
state,
onClose,
onFollow,
onWatch,
onFly,
onResearch,
gearRequest,
}: {
selection: any;
state: any;
onClose: () => void;
onFollow: (n: string) => void;
onWatch: (n: string, note?: string) => void;
onFly: (x: number, z: number) => void;
onResearch: (entity: Entity) => void;
gearRequest:number;
}) {
const [tab, setTab] = useState("overview");
const [note, setNote] = useState("");
const [noteStatus, setNoteStatus] = useState("");
const name = selection?.kind === "player" ? selection.name : null;
const { data: dossier, error } = usePoll(
name ? "/api/dossier?name=" + encodeURIComponent(name) : null,
);
const { data: profile, error: profileError } = usePoll(
name && tab === "skills"
? "/api/public-profile?name=" + encodeURIComponent(name)
: null,
120000,
);
const npc =
selection?.kind === "npc"
? state?.npcs.find((n: any) => n.id === selection.id)
: null;
const { data: npcDef } = usePoll(
npc?.type !== undefined ? `/api/catalog?kind=npcs&q=${npc.type}` : null,
600000,
);
useEffect(() => {
setTab("overview");
setNote(
state?.watches.find((w: any) => w.name === name?.toLowerCase())?.note ??
"",
);
}, [name, selection?.kind, selection?.id]);
useEffect(()=>{if(gearRequest)setTab("gear");},[gearRequest]);
const current = dossier?.current;
const past = dossier?.record;
const watched = state?.watches.some(
(w: any) => w.name === name?.toLowerCase(),
);
const stale = state?.stale || dossier?.feedStale;
const gear = !stale ? current?.appearance?.equipment : null;
const p = selection?.kind === "npc" ? npc : current;
const signals = p?.signals ?? {};
const sourceName =
selection?.kind === "catalog"
? selection.item.name
: selection?.kind === "npc"
? (npc?.name ?? `NPC #${selection.id}`)
: (current?.name ?? past?.display_name ?? name);
return (
<aside
className={`inspector ${selection ? "open" : ""}`}
aria-label="Entity inspector"
>
<div className="panel-heading">
<span>ENTITY DOSSIER</span>
<Button className="icon" aria-label="Close inspector" onClick={onClose}>
<X size={15} />
</Button>
</div>
{!selection ? (
<Empty title="Select an entity">
Inspect a player, NPC, item definition, or an observed event. Agents
can use the same dossier through the local API.
</Empty>
) : (
<>
<div className="identity">
<div className="identity-icon">
{selection.kind === "player" ? (
<Users size={22} />
) : selection.kind === "npc" ? (
<Target size={22} />
) : (
<Box size={22} />
)}
</div>
<div>
<span className="eyebrow">
{selection.kind === "catalog"
? "CACHE DEFINITION"
: selection.kind === "npc"
? "OBSERVED NPC"
: "PLAYER"}
</span>
<h2>{sourceName}</h2>{selection.kind==='player' && <Badge size="1" color={current?.allegiance==='friendly'?'green':current?.allegiance==='enemy'?'red':'gray'}>{current?.allegiance==='friendly'?'Friendly':current?.allegiance==='enemy'?'Enemy candidate':'Allegiance unknown'}</Badge>}
<p>
{p ? (
<>
Level{" "}
{p.combatLevel ??
npcDef?.results.find((r: any) => r.id === npc?.type)
?.combatLevel ??
"—"}{" "}
<b>·</b> {p.x}, {p.z} <b>·</b> floor {p.plane}
</>
) : selection.kind === "catalog" ? (
`ID ${selection.item.id} · revision 289`
) : (
"Not in current roster"
)}
</p>
</div>
</div>
{name&&<div className="gear-coverage-note"><strong>{stale?'Detailed feed is stale':current?.appearance?.transmog!=null?'Transformed appearance · equipment unavailable':current?.appearance?(current.appearance.equipment.length?`${current.appearance.equipment.length} equipped slots observed`:'Appearance received · no equipped items reported'):dossier?.feedStale?'Detailed feed is stale':current?.inArea?'In detail area · waiting for appearance':'Position only · outside the live detail area'}</strong><p>Use Inspect gear on a pane to focus the shared detail area. Intelligence alone does not expand coverage.</p></div>}
{name && (
<div className="entity-actions">
<Button onClick={()=>onResearch({kind:"player",key:name,name})}><Activity size={14}/> Research holdings</Button>
<Button
className="primary"
onClick={() => onFollow(name)}
disabled={!current}
>
<Crosshair size={14} /> Follow
</Button>
<a className="button monitor-tab-link" href={monitorHref(name)} target="_blank" rel="noopener noreferrer">Monitor in new tab <ArrowUpRight size={13}/></a>
<Button
className={watched ? "watched" : ""}
onClick={() => onWatch(name, note)}
>
<Bookmark size={14} fill={watched ? "currentColor" : "none"} />
{watched ? "Watching" : "Watch"}
</Button>
</div>
)}
{selection.kind === "player" && (
<SegmentedControlRadioGroup.Root className="detail-tabs dossier-segments" aria-label="Dossier view" value={tab} onValueChange={setTab}>
{["overview", "gear", "skills", "history", "raw"].map((t) => (
<SegmentedControlRadioGroup.Item key={t} value={t}>
{t === "skills" ? "Public data" : label(t)}
</SegmentedControlRadioGroup.Item>
))}
</SegmentedControlRadioGroup.Root>
)}
<div className="inspector-content">
{error && <p className="error">{error}</p>}
{selection.kind === "catalog" ? (
<>
{selection.item.assetKind==='items'&&<div className="item-hero"><ItemSprite id={selection.item.id} name={selection.item.name} size={72}/></div>}
<p className="description">
{selection.item.description ||
"No examine description in this definition."}
</p>
<div className="facts">
<span>Base value</span>
<strong>
{selection.item.baseValue !== undefined
? `${fmt(selection.item.baseValue)} gp`
: "—"}
</strong>
<span>Stackable</span>
<strong>
{selection.item.stackable === undefined
? "—"
: selection.item.stackable
? "Yes"
: "No"}
</strong>
<span>Members</span>
<strong>
{selection.item.members === undefined
? "—"
: selection.item.members
? "Yes"
: "No"}
</strong>
<span>Combat level</span>
<strong>{selection.item.combatLevel ?? "—"}</strong>
</div>
<p className="note">
Definition data. Base value is not a market price or potential
drop value.
</p>
<h4>Available actions</h4>
<div className="chips">
{selection.item.actions?.map((a: any) => (
<span key={a.slot}>{a.name}</span>
))}
</div>
<Json data={selection.item} />
</>
) : selection.kind === "npc" ? (
<>
<Badge size="1" variant="soft" className="badge">
{npc ? "IN OBSERVATION AREA" : "NO LONGER OBSERVED"}
</Badge>
{npc && (
<Button className="wide" onClick={() => onFly(npc.x, npc.z)}>
<Navigation size={14} /> Fly to NPC
</Button>
)}
<p>
{
npcDef?.results.find((r: any) => r.id === npc?.type)
?.description
}
</p>
<h4>Definition & signals</h4>
<Json
data={{
definition: npcDef?.results.find(
(r: any) => r.id === npc?.type,
),
observed: npc,
}}
/>
</>
) : (
<>
{tab === "overview" && (
<>
<BotOperations context={dossier?.operations}/>
<div className="facts">
<span>Roster</span>
<strong
className={
current && !dossier?.rosterStale ? "mint" : "muted"
}
>
{current
? dossier?.rosterStale
? "Last known"
: "Online"
: "Not observed"}
</strong>
<span>Detailed appearance</span>
<strong>
{gear
? "Observed"
: stale
? "Stale"
: "Outside coverage / pending"}
</strong>
<span>Worn items</span>
<strong>{gear?.length ?? "Unknown"}</strong>
<span>Reported HP</span>
<strong>
{!stale && current?.health
? `${current.health[0]} / ${current.health[1]}`
: "Unknown"}
</strong>
<span>First recorded here</span>
<strong>
{past
? new Date(past.first_seen).toLocaleDateString()
: "—"}
</strong>
<span>Last roster observation</span>
<strong>{age(past?.last_seen)}</strong>
</div>
<h4>
Visible equipment <span>{gear?.length ?? "Unknown"}</span>
</h4>
{gear?.length ? (
gear.slice(0, 4).map((g: any) => (
<div className="mini-item" key={g.slot}>
<ItemSprite id={g.id} name={g.name}/>
<div>
{g.name}
<small>
{g.slot} · #{g.id}
</small>
</div>
</div>
))
) : (
<p className="note">
{gear ? "Current appearance reports no equipped items." : "No current equipment observation. Unknown does not mean empty."}
</p>
)}
<div className="boundary">
<LockKeyhole size={15} />
<div>
<strong>Carried inventory · unavailable</strong>
<p>
The public feed does not send it. Public bank previews
are in Public data.
</p>
</div>
</div>
<h4>
Nearby players <span>within 32 tiles</span>
</h4>
<div className="nearby-list">
{dossier?.relations?.nearby?.slice(0, 6).map((p: any) => (
<Button key={p.id} onClick={() => onFollow(p.name)}>
<Users size={12} />
<span>{p.name}</span>
<small>{p.distance} tiles</small>
</Button>
))}
</div>
<h4>Watch note</h4>
<TextArea
size="2"
variant="surface"
aria-label="Watch note"
value={note}
onChange={(e) => setNote(e.target.value)}
placeholder="What should an agent watch for?"
maxLength={1000}
/>
<Button
className="wide"
onClick={async () => {
try {
await request("/api/watches", { name, note });
setNoteStatus("Note saved");
} catch (e) {
setNoteStatus(String(e));
}
}}
>
<Bookmark size={13} /> Save note & watch
</Button>
{noteStatus && (
<p className="note" role="status">
{noteStatus}
</p>
)}
<h4>Recent signals</h4>
<div className="signal-facts">
{Object.entries(signals).length ? (
Object.entries(signals).map(([key, v]: any) => (
<div key={key}>
<span>{SIGNALS[key] ?? key}</span>
<strong>
{typeof v.value === "string"
? v.value
: JSON.stringify(v.value)}
</strong>
<small>{age(v.observedAt)}</small>
</div>
))
) : (
<p className="note">No detailed signals yet.</p>
)}
</div>
</>
)}
{tab === "gear" && (
<>
<p className="source-line">
{gear
? `Appearance observed ${age(current.appearanceAt)}`
: "No fresh appearance observation"}
</p>
<DeathRisk key={name} risk={stale?null:dossier?.deathRisk}/>
<details open className="equipment-slots"><summary>All equipment slots</summary>
{[
"Head",
"Cape",
"Neck",
"Weapon",
"Body",
"Shield",
"Legs",
"Hands",
"Feet",
].map((slot) => {
const i = gear?.find((g: any) => g.slot === slot);
return (
<div className="gear-row" key={slot}>
<ItemSprite id={i?.id} name={i?.name} size={36}/>
<span>{slot}</span>
<strong>
{i?.name ?? (gear ? "No visible item" : "Unknown")}
<small>{i ? `#${i.id}` : ""}</small>
</strong>
</div>
);
})}
</details>
<p className="note">
Rings and ammunition are not encoded in appearance. Worn
items do not establish death loot.
</p>
{past?.gear && (
<details>
<summary>
Last recorded equipment · {age(past.gear_at)}
</summary>
<Json data={past.gear} />
<p className="note">
Historical observation; may no longer be worn.
</p>
</details>
)}
</>
)}
{tab === "skills" && (
<>
{profileError && <p className="error">{profileError}</p>}
{!profile && !profileError && (
<p className="note">Loading public hiscores…</p>
)}
{profile && (
<>
<p className="source-line">
PUBLIC SNAPSHOTS · fetched {age(profile.fetchedAt)}
</p>
<p className="note">
Publication time is unknown. These are not live
inventory or bank contents.
</p>
<h4>Skill profile</h4>
<Table.Table className="skills">
<Table.Header>
<Table.Row>
<Table.ColumnHeaderCell>
Skill
</Table.ColumnHeaderCell>
<Table.ColumnHeaderCell>
Level
</Table.ColumnHeaderCell>
<Table.ColumnHeaderCell>
Rank
</Table.ColumnHeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{profile.skills?.rows.map((r: any) => (
<Table.Row key={r.skill}>
<Table.Cell title={r.time}>
{r.skill}
</Table.Cell>
<Table.Cell>{fmt(r.level)}</Table.Cell>
<Table.Cell>{fmt(r.rank)}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Table>
{["outfit", "bank"].map((k) => (
<section key={k}>
<h4>Published {k}</h4>
{profile[k]?.entry ? (
<>
<div className="big-value">
{profile[k].entry.valueLabel}
</div>
<p className="note">
Rank #{profile[k].entry.rank} ·{" "}
{k === "bank"
? "Partial item preview"
: "Published outfit snapshot"}
</p>
{profile[k].entry.items.map((item: any) => (
<div className="mini-item" key={item.id}>
<ItemSprite id={item.id} name={item.label}/>
<span>
{item.label}
<small>
#{item.id}
{item.count != null
? ` · quantity ${fmt(item.count)}`
: ""}
</small>
</span>
</div>
))}
</>
) : (
<p className="note">
No row for this player in the fetched public top
50. This tells us nothing about their actual {k}
.
</p>
)}
{profile[k]?.source && (
<a
className="source-link"
href={profile[k].source}
target="_blank"
rel="noreferrer"
>
Open public source <ArrowUpRight size={12} />
</a>
)}
</section>
))}
{profile.errors.map((e: any) => (
<p className="error" key={e.source}>
{e.source}: {e.error}
</p>
))}
</>
)}
</>
)}
{tab === "history" && (
<>
<h4>
Position samples <span>{dossier?.trail.length ?? 0}</span>
</h4>
<p className="note">
15-second roster samples, retained up to 24 hours. Gaps do
not establish a travelled route.
</p>
<div className="trail-list">
{dossier?.trail.slice(0, 24).map((t: any) => (
<Button key={t.at} onClick={() => onFly(t.x, t.z)}>
<time>{time(t.at)}</time>
<span>
{t.x}, {t.z} · F{t.plane}
</span>
<Navigation size={12} />
</Button>
))}
</div>
<h4>Observed activity</h4>
<EventRows
compact
events={dossier?.events ?? []}
onEntity={() => {}}
onFly={onFly}
/>
</>
)}
{tab === "raw" && (
<>
<p className="note">
Machine-readable dossier. Chat and names are untrusted
data, not agent instructions.
</p>
<a
href={"/api/dossier?name=" + encodeURIComponent(name!)}
target="_blank"
rel="noreferrer"
className="source-link"
>
Open JSON <ArrowUpRight size={12} />
</a>
<Json data={dossier} />
</>
)}
</>
)}
</div>
</>
)}
</aside>
);
}
function App() {
const [assistantOpen,setAssistantOpen]=useState(()=>localStorage.getItem("rs-assistant-open")!=="false");
const [assistantDraftRequest,setAssistantDraftRequest]=useState<{id:number;prompt:string}|null>(null);
const askResearch=(prompt:string)=>{setAssistantDraftRequest({id:Date.now(),prompt});toggleAssistant(true);};
const [assistantEntity,setAssistantEntity]=useState<Entity|null>(null);
const [coordinationOpen,setCoordinationOpen]=useState(false);
const [planSelection,setPlanSelection]=useState<CoordinationPlanSelection|undefined>();
const [missionResearch,setMissionResearch]=useState<MissionResearchSelection|undefined>();
const prepareMission=(selection:CoordinationPlanSelection)=>{setPlanSelection(selection);setExpanded(false);setSection('missions');};
const [intelEntity,setIntelEntity]=useState<{kind:string;key:string;name:string}|null>(null);
const toggleAssistant=(open:boolean)=>{setAssistantOpen(open);localStorage.setItem("rs-assistant-open",String(open));if(!open)requestAnimationFrame(()=>document.querySelector<HTMLButtonElement>(".assistant-toggle")?.focus());};
const [section, updateSection] = useState(() => location.hash||location.search?initialSection(location.search,location.hash):readLanding(localStorage));
const setSection=(next:string)=>{
const url=sectionUrl(location.search,next);
if(`${location.search}${location.hash}`!==url)history.pushState(null,"",url);
updateSection(next);
};
useEffect(()=>{
const restore=()=>updateSection(initialSection(location.search,location.hash));
window.addEventListener('popstate',restore);
window.addEventListener('hashchange',restore);
return()=>{window.removeEventListener('popstate',restore);window.removeEventListener('hashchange',restore);};
},[]);
const economy = isResearchSection(section);
const intelligenceWorkspace = section === 'swarms' || section === 'missions' || section === 'settings';
const [swarmVisited,setSwarmVisited]=useState(section==='swarms');
useEffect(()=>{if(section==='swarms')setSwarmVisited(true);},[section]);
const [missionVisited,setMissionVisited]=useState(section==='missions');
const [returnToMission,setReturnToMission]=useState(false);
useEffect(()=>{if(section==='missions')setMissionVisited(true);},[section]);
const [researchVisited, setResearchVisited] = useState(economy);
useEffect(() => { if (economy) setResearchVisited(true); }, [economy]);
const [researchNavigationId,setResearchNavigationId]=useState(0);
const navigateResearch=(next:ResearchSection)=>{setSection(next);setResearchNavigationId(v=>v+1);};
const lastEconomy = useRef<string>(readLanding(localStorage)), lastWorld = useRef("map");
const [researchContext,setResearchContext]=useState("Economic intelligence");
const [swarmRequest,setSwarmRequest]=useState<{id:string;requestId:number}|null>(null);
const [researchRequest,setResearchRequest]=useState<{entity:Entity;id:number}|null>(null);
useEffect(()=>{if(economy)lastEconomy.current=section;else if(section!=='settings')lastWorld.current=section;},[section,economy]);
const switchMode=(mode:string)=>setSection(mode==="blackrock"?lastEconomy.current:lastWorld.current);
const openResearch=(entity:Entity)=>{setResearchRequest({entity,id:Date.now()});setSection("market");};
const { data: state, error: stateError } = usePoll(economy ? null : "/api/state", 1000);
const researchSource = useResearchLayers(state, !!stateError || economy);
const { data: feed } = usePoll(economy ? null : "/api/events?limit=80", 2000);
const { data: tactical, error: tacticalError } = usePoll(economy ? null : "/api/tactical", 3000);
const { data: polledOperations, error: operationsError } = usePoll("/api/operations", 30000);
const [refreshedOperations, setRefreshedOperations] = useState<any>(null);
const operations = refreshedOperations ?? polledOperations;
useEffect(() => { setRefreshedOperations(null); }, [polledOperations]);
const [selectedTeam, setSelectedTeam] = useState("all");
const teamNames = useMemo(() => selectedTeam === "all" ? undefined : operations ? bindingsForTeam(operations, selectedTeam).map(b => b.name) : [], [selectedTeam, operations]);
const teamNameKeys = useMemo(() => teamNames ? new Set(teamNames.map(botKey)) : null, [teamNames]);
async function refreshOperations() {
const response = await request("/api/operations/refresh", {});
setRefreshedOperations(response);
}
const [list, setList] = useState("players"),
[query, setQuery] = useState(""),
[minimum, setMinimum] = useState(0),
[selection, setSelection] = useState<any>(null),
[error, setError] = useState(""),
[expanded, setExpanded] = useState(true);
const [showLayers, setShowLayers] = useState(false);
const [layers, setLayers] = useState<Record<string, boolean>>({
showPlayers: true,
showNpcs: true,
showPlayerNames: true,
showNpcNames: false,
showChat: true,
showCombat: true,
});
const [atlasOpen, setAtlasOpen] = useState(false);
const [rosterOpen, setRosterOpen] = useState(()=>!window.matchMedia('(max-width:1100px)').matches);
useEffect(()=>{const query=window.matchMedia('(max-width:1100px)');const shrink=()=>{if(query.matches)setRosterOpen(false);};query.addEventListener('change',shrink);return()=>query.removeEventListener('change',shrink);},[]);
const [onlyMyBots, setOnlyMyBots] = useState(() => {
try { return (sessionStorage.getItem("rs-watch:only-my-bots") ?? (new URLSearchParams(location.search).has("follow") ? "false" : localStorage.getItem("rs-watch:only-my-bots"))) === "true"; } catch { return false; }
});
useEffect(() => {
try { sessionStorage.setItem("rs-watch:only-my-bots", String(onlyMyBots)); } catch {}
}, [onlyMyBots]);
const [x, setX] = useState("3061"),
[z, setZ] = useState("3877"),
[height, setHeight] = useState("70"),
[eventKind, setEventKind] = useState("all"),
[eventQuery, setEventQuery] = useState(""),
[onlyWatched, setOnlyWatched] = useState(false),
[catalogKind, setCatalogKind] = useState("items"),
[catalogQuery, setCatalogQuery] = useState(""),
[limit, setLimit] = useState(100),
[waypointLabel, setWaypointLabel] = useState(""),
[viewerReady, setViewerReady] = useState(false),
[copied, setCopied] = useState(false),
[catalogOffset, setCatalogOffset] = useState(0);
const iframe = useRef<HTMLIFrameElement>(null);
const acked = useRef("");
const [tabCommands] = useState(() => new ViewerCommands());
const [viewCommand, setViewCommand] = useState<ViewCommand | null>(null);
const commandFrame = useRef<HTMLIFrameElement | null>(null);
const [tabCamera, setTabCamera] = useState<ViewCamera>(() => {
let saved: string | null = null;
try { saved = sessionStorage.getItem("rs-watch:tab-camera"); } catch {}
return initialViewCamera(location.search, saved);
});
const {data:coordinationData,error:coordinationError}=usePoll(section==='missions'||section==='map'&&coordinationOpen?'/api/coordination/context':null,2000);
const mapContext:CoordinationContext|undefined=coordinationData?{...coordinationData,...(coordinationError?{sourceState:'unavailable' as const,protectionReady:false}:{}),point:Number.isInteger(tabCamera.combatPlane)&&[0,1,2,3].includes(tabCamera.combatPlane!)?{worldId:'main',x:Math.round(tabCamera.x),z:Math.round(tabCamera.z),level:tabCamera.combatPlane as 0|1|2|3}:undefined}:undefined;
const tabCameraRef = useRef(tabCamera); tabCameraRef.current = tabCamera;
const primaryFrame=useRef<HTMLIFrameElement|null>(null);
const [primaryFollow,setPrimaryFollow]=useState(tabCamera.follow);
const [activeMonitor,setActiveMonitor]=useState<string|null>(null);
const activeMonitorRef=useRef(activeMonitor);activeMonitorRef.current=activeMonitor;
const [gearRequest,setGearRequest]=useState(0);
const [paneFilters,setPaneFilters]=useState<Record<string,PaneFilter>>(()=>{try{return readPaneFilters(sessionStorage.getItem('rs-watch:pane-filters'));}catch{return {};}});
useEffect(()=>{try{sessionStorage.setItem('rs-watch:pane-filters',JSON.stringify(paneFilters));}catch{}},[paneFilters]);
const changePaneFilter=(key:string,value:PaneFilter)=>setPaneFilters(old=>({...old,[key]:value}));
// Defaults from explicit hotspot jumps are separate from the user's overrides.
const [hotspotFilters,setHotspotFilters]=useState<Record<string,PaneFilter>>(()=>{try{return readPaneFilters(sessionStorage.getItem('rs-watch:hotspot-filters'));}catch{return {};}});
useEffect(()=>{try{sessionStorage.setItem('rs-watch:hotspot-filters',JSON.stringify(hotspotFilters));}catch{}},[hotspotFilters]);
const effectivePaneFilters=useMemo(()=>({...hotspotFilters,...paneFilters}),[hotspotFilters,paneFilters]);
const activePaneFilterKey=()=>activeMonitorRef.current?'monitor:'+activeMonitorRef.current:iframe.current?.dataset.paneFilterKey??'primary:0';
const inspectPane=(name:string)=>{setSelection({kind:'player',name});setExpanded(false);setGearRequest(v=>v+1);};
const [followMonitors,setFollowMonitors] = useState<string[]>(()=>{
try { const names=JSON.parse(sessionStorage.getItem('rs-watch:follow-monitors')||'[]');return Array.isArray(names)?names.reduce((all:string[],name:unknown)=>typeof name==='string'?addFollowMonitor(all,name,tabCamera.follow):all,[]):[]; } catch {return [];}
});
useEffect(()=>{try{sessionStorage.setItem('rs-watch:follow-monitors',JSON.stringify(followMonitors));}catch{}},[followMonitors]);
function addMonitor(name:string) { setFollowMonitors(names=>addFollowMonitor(names,name,tabCameraRef.current.follow)); }
const [agentControl, setAgentControl] = useState(false);
const agentControlRef = useRef(false); agentControlRef.current = agentControl;
const observedFollow = useRef<string | null>(null);
const [viewerSrc, setViewerSrc] = useState<string | null>(null);
const [dualWorld, setDualWorld] = useState(false);
const [paneVersion, setPaneVersion] = useState(0);
const allegiance = useMemo(() => state?.friendlies ? {names:state.friendlies.names,ready:state.friendlies.ready,onlyFriendlies:onlyMyBots,visibleNames:teamNames} : null, [state?.friendlies?.refreshedAt,onlyMyBots,teamNames]);
const { data: filteredFeed } = usePoll(
section === "signals"
? "/api/events?limit=100" +
(eventKind !== "all"
? "&kind=" + encodeURIComponent(eventKind)
: "") +
(onlyWatched ? "&watched=true" : "")
: null,
2000,
);
const { data: catalog } = usePoll(
section === "catalog"
? `/api/catalog?kind=${catalogKind}&q=${encodeURIComponent(catalogQuery)}&offset=${catalogOffset}`
: null,
600000,
);
const { data: caps } = usePoll(
section === "agent" ? "/api/capabilities" : null,
600000,
);
const { data: board, error: boardError } = usePoll(
section === "wealth"
? `/api/leaderboard?kind=${catalogKind === "npcs" ? "outfit" : "bank"}`
: null,
300000,
);
const run = async (path: string, body?: any, method?: string) => {
try {
const result = await request(path, body, method);
setError("");
return result;
} catch (e) {
setError(e instanceof Error ? e.message : "Request failed");
return null;
}
};
async function command(c: any) {
try {
const result = tabCommands.queue(c);
if(c.kind==='goto'||c.kind==='follow') {
const key=activePaneFilterKey();
setHotspotFilters(old=>{const next={...old};delete next[key];return next;});
}
commandFrame.current = iframe.current;
setViewCommand(result);
setError("");
return result;
} catch (e) {
setError(e instanceof Error ? e.message : "Invalid camera command");
return null;
}
}
async function fly(cx: number, cz: number, h = 70, plane = 0, hotspotFilter?:'all'|'friendly') {
const key=activePaneFilterKey();
setX(String(Math.round(cx)));
setZ(String(Math.round(cz)));
setSection("map");
const result=await command({ kind: "goto", x: cx, z: cz, height: h, plane });
if(result&&hotspotFilter)setHotspotFilters(old=>({...old,[key]:hotspotFilter}));
}
async function selectPlayer(name: string) {
if(window.matchMedia('(max-width:1100px)').matches)setRosterOpen(false);
setSelection({ kind: "player", name });
const current = tabCommands.current?.status === 'pending' && tabCommands.current.kind === 'follow' ? tabCommands.current.name : tabCameraRef.current.follow;
if (current && botKey(current)!==botKey(name)) {
setFollowMonitors(names=>addFollowMonitor(names,name,current));
return;
}
await command({ kind: "follow", name });
}
async function watch(name: string, note = "") {
const existing = state?.watches.some(
(w: any) => w.name === name.toLowerCase(),
);
await run(
existing
? "/api/watches?name=" + encodeURIComponent(name)
: "/api/watches",
existing ? undefined : { name, note },
existing ? "DELETE" : undefined,
);
}
useEffect(() => {
if (viewerSrc || !state) return;
const c = tabCameraRef.current;
const params = new URLSearchParams({
cx: String(c.x),
cy: String(c.height),
cz: String(c.z),
p: String(c.pitch),
y: String(c.yaw),
plane: String(c.plane??0),
v: "1",
native: "1",
multifollow: "1",
live: `ws://${location.host}/viewer-feed`,
});
if (c.follow) params.set("follow", c.follow);
setViewerSrc("/viewer/?" + params.toString());
setX(String(Math.round(c.x)));
setZ(String(Math.round(c.z)));
setHeight(String(Math.round(c.height)));
}, [state, viewerSrc]);
useEffect(() => {
function handler(e: MessageEvent) {
if (e.origin !== location.origin) return;
// A pending command stays tied to the pane selected when it was queued.
if (e.data?.type === "rs-watch-ack" && e.source === commandFrame.current?.contentWindow) {
const result = tabCommands.ack(e.data.id, e.data.status, e.data.error);
if (result) {
setViewCommand(result);
if (result.status === "failed") setError(result.error || "Viewer command failed");
return;
}
if (String(e.data.id).startsWith("view-")) return;
}
if (e.source !== iframe.current?.contentWindow) return;
if (e.data?.type === "rs-watch-follow-request" && typeof e.data.name === 'string') {
setSelection({kind:'player',name:e.data.name});
setFollowMonitors(names=>addFollowMonitor(names,e.data.name,tabCameraRef.current.follow));
return;
}
if(e.data?.type === "rs-watch-native-state") setAtlasOpen(e.data.worldMapOpen===true);
if (e.data?.type === "rs-watch-camera") {
const camera = e.data.camera;
if (!camera || ![camera.x,camera.z,camera.height,camera.pitch,camera.yaw].every(Number.isFinite)) return;
const local = {...camera, at:Date.now()};
setTabCamera(local);
tabCameraRef.current = local;
if(activeMonitorRef.current===null)try { sessionStorage.setItem("rs-watch:tab-camera", JSON.stringify(local)); } catch {}
setViewerReady(true);
// Shared agent telemetry is published only by an explicitly opted-in tab.
if (agentControlRef.current) run("/api/viewer-state", local);
if (camera.follow !== observedFollow.current) {
observedFollow.current = camera.follow;
if (camera.follow) setSelection({ kind: "player", name: camera.follow });
}
}
if (e.data?.type === "rs-watch-ack" && agentControlRef.current) {
acked.current = e.data.id;
run("/api/command-ack", e.data);
}
}
window.addEventListener("message", handler);
return () => window.removeEventListener("message", handler);
}, []);
useEffect(() => {
if (!viewerReady) return;
iframe.current?.contentWindow?.postMessage(
{type: 'rs-watch-native-ui', action: 'chrome', open: expanded},
location.origin,
);
}, [expanded, viewerReady, paneVersion]);
useEffect(() => {
if (!viewCommand || viewCommand.status !== "pending") return;
const target = commandFrame.current ?? iframe.current;
if (target && !target.isConnected) {
const result = tabCommands.ack(viewCommand.id, "failed", "The selected view was closed");
if (result) setViewCommand(result);
return;
}
if (!commandFrame.current && target) commandFrame.current = target;
const result = tabCommands.deliver(viewerReady ? target?.contentWindow ?? null : null, location.origin);
if (result && result !== viewCommand) setViewCommand(result);
}, [viewCommand, viewerReady, paneVersion, state?.serverTime]);
useEffect(() => {
document.title = `${economy ? researchSection(section as ResearchSection).label : section === "settings" ? "Settings" : section === "swarms" ? "Swarm intelligence" : section === "missions" ? "Command workspace" : tabCamera.follow || "World"} · ${economy ? "RS-BLACKROCK" : "RS-PALANTIR"}`;
const icon=document.querySelector<HTMLLinkElement>('link[rel="icon"]');if(icon)icon.href=economy?"/brand/rs-blackrock.png":"/brand/rs-palantir.png";
}, [tabCamera.follow, section, economy]);
useEffect(() => {
const c = state?.command;
if (
agentControl && c?.status === "pending" &&
c.id !== acked.current &&
Date.now() - c.at < 30000 &&
viewerReady
) {
iframe.current?.contentWindow?.postMessage(
{ type: "rs-watch-command", command: c },
location.origin,
);
}
}, [
state?.command?.id,
state?.command?.status,
agentControl,
viewerReady,
state?.serverTime,
paneVersion,
]);
useEffect(() => {
if (localStorage.getItem("rs-watch:migrated-v2")) return;
try {
const names = JSON.parse(
localStorage.getItem("rs-watch:watchlist") || "[]",
);
if (Array.isArray(names))
Promise.all(
names
.filter((n) => typeof n === "string")
.slice(0, 100)
.map((name) => request("/api/watches", { name, note: "" })),
)
.then(() => localStorage.setItem("rs-watch:migrated-v2", "true"))
.catch(() => {});
} catch {}
}, []);
useEffect(() => {
const c = state?.command;
if (agentControl && c?.kind === "layers" && c.status === "applied")
setLayers((prev) => ({
...prev,
...Object.fromEntries(
Object.keys(prev)
.filter((k) => typeof c[k] === "boolean")
.map((k) => [k, c[k]]),
),
}));
}, [state?.command?.id, state?.command?.status, agentControl]);
useEffect(() => {
setLimit(100);
}, [query, list, minimum, onlyMyBots, selectedTeam]);
const roster = useMemo(() => {
let rows = list === "npcs" ? (state?.npcs ?? []) : (state?.players ?? []);
const q = query.toLowerCase();
return rows
.filter(
(p: any) =>
p.name.toLowerCase().includes(q) &&
(list === "npcs" || !onlyMyBots || p.allegiance === "friendly") &&
(list === "npcs" || !teamNameKeys || teamNameKeys.has(botKey(p.name))) &&
(list !== "watch" ||
state.watches.some((w: any) => w.name === p.name.toLowerCase())) &&
(p.combatLevel ?? 126) >= minimum,
)
.sort((a: any, b: any) =>
a.name.localeCompare(b.name, undefined, { numeric: true }),
);
}, [state?.players, state?.npcs, state?.watches, list, query, minimum, onlyMyBots, teamNameKeys]);
const events = (filteredFeed?.events ?? []).filter(
(e: any) =>
(eventKind === "all" || e.kind === eventKind) &&
(!onlyWatched || state?.watches.some((w: any) => w.name === e.entity)) &&
JSON.stringify(e).toLowerCase().includes(eventQuery.toLowerCase()),
);
const stale = !state || state.stale || !!stateError;
const nativeViewerParams = new URLSearchParams(viewerSrc?.split('?')[1] ?? '');
if (tabCamera) {
const c = tabCamera;
for (const [key, value] of Object.entries({cx:c.x, cy:c.height, cz:c.z, p:c.pitch, y:c.yaw, plane:c.plane??0})) nativeViewerParams.set(key, String(value));
if (c.follow) nativeViewerParams.set('follow', c.follow);
else nativeViewerParams.delete('follow');
}
const nativeViewerHref = '/viewer/?' + nativeViewerParams.toString();
const presets = state?.waypoints ?? [];
return (
<div className={`app ${section==='settings'?'settings-mode':''} ${economy?'economy-mode':''} ${intelligenceWorkspace?'intelligence-mode':''} ${section==='map'?'world-mode':''} ${followMonitors.length||dualWorld?'split-world':''} ${section==='operations'?'operations-mode':''} ${atlasOpen?'atlas-open':''} ${selection?'has-selection':''} ${rosterOpen?'':'roster-hidden'} ${expanded ? "expanded" : ""}`}>
<div className="research-mode-dock" role="navigation" aria-label="Switch research mode">
<div className="research-dock-controls"><SegmentedControlRadioGroup.Root className="research-mode-toggle" aria-label="Application mode" value={economy?"blackrock":"palantir"} onValueChange={switchMode}>
<SegmentedControlRadioGroup.Item value="palantir"><img src="/brand/rs-palantir.png" alt=""/><span>RS-PALANTIR<small>World & players</small></span></SegmentedControlRadioGroup.Item>
<SegmentedControlRadioGroup.Item value="blackrock"><img src="/brand/rs-blackrock.png" alt=""/><span>RS-BLACKROCK<small>Economic intelligence</small></span></SegmentedControlRadioGroup.Item>
</SegmentedControlRadioGroup.Root>
{!economy&§ion==='map'&&expanded&&<div className="intel-quick-nav" role="navigation" aria-label="Palantir workspaces">{[{key:'map',name:'World',icon:Globe},{key:'swarms',name:'Swarms',icon:Users},{key:'missions',name:'Command',icon:Target}].map(({key,name,icon:Icon})=><Button key={key} size="1" variant={section===key?'soft':'ghost'} aria-current={section===key?'page':undefined} onClick={()=>{setExpanded(false);setSection(key);}}><Icon size={14}/><span>{name}</span></Button>)}</div>}
<Button aria-current={section==='settings'?'page':undefined} onClick={()=>{setExpanded(false);setSection('settings');}}>Settings</Button>
<Button className="assistant-toggle" variant={assistantOpen?"soft":"surface"} color="blue" aria-label="Toggle research assistant" aria-expanded={assistantOpen} onClick={()=>toggleAssistant(!assistantOpen)}><Sparkles size={16}/><span>Assistant</span></Button>
</div><LivePopulation world={state} worldError={!!stateError} poll={economy}/><div className="research-dock-context"><div className="research-resume"><span>{economy?"WORLD CONTEXT":"RESEARCH CONTEXT"}</span><Button variant="ghost" color="gray" onClick={()=>switchMode(economy?"palantir":"blackrock")}><ArrowUpRight size={14}/>{economy?(selection?.name??tabCamera.follow??"Return to world"):`Back to ${researchContext}`}</Button></div>
{!economy&&selection?.kind==='player'&&<Button className="research-player-link" onClick={()=>openResearch({kind:'player',key:selection.name,name:selection.name})}><Activity size={14}/>Research {selection.name}</Button>}</div>
</div>
<header>
<a className="brand" href={economy?"#economy":"#world"} aria-label={economy?"RS-BLACKROCK market home":"RS-PALANTIR world home"} onClick={e=>{e.preventDefault();economy?navigateResearch("economy"):setSection("map")}}>
<span className={`mode-emblem ${economy?"mode-emblem-blackrock":"mode-emblem-palantir"}`}><img src={economy?"/brand/rs-blackrock.png":"/brand/rs-palantir.png"} alt=""/></span>
<span>{economy?"RS-BLACKROCK":"RS-PALANTIR"}<small>{economy?"ECONOMIC INTELLIGENCE":"WORLD INTELLIGENCE"}</small></span>
</a>
<nav aria-label="Main navigation">
{(economy ? [
{ key: "watchlists", name: "Watchlists", icon: Bookmark },
{ key: "market", name: "Exchange", icon: Search },
{ key: "economy", name: "Economy", icon: Activity },
{ key: "fleet", name: "Fleet", icon: Users },
] : [
{ key: "map", name: "World", icon: Globe },
{ key: "swarms", name: "Swarms", icon: Users },
{ key: "missions", name: "Command", icon: Target },
]).map(({ key, name, icon: Icon }) => (
<Button
key={key}
aria-label={name}
aria-current={section === key ? "page" : undefined}
className={section === key ? "active" : ""}
onClick={() => isResearchSection(key)?navigateResearch(key):setSection(key)}
>
<Icon size={15} />
<span>{name}</span>
{key === "signals" && <i className="nav-dot" />}
</Button>
))}
<select className="br-more-nav" aria-label="More sections" value={["operations","swarms","missions","signals","wealth","catalog","agent"].includes(section)?section:""} onChange={e=>{if(e.target.value)setSection(e.target.value)}}>
<option value="" disabled>More</option><option value="operations">Operations</option><option value="swarms">Swarms</option><option value="missions">Command workspace</option><option value="signals">Signals</option><option value="wealth">Wealth</option><option value="catalog">Catalog</option><option value="agent">Agent API</option>
</select>
</nav>
<div className="header-right">
<span className="read-only">
<Eye size={13} /> OBSERVER
</span>
{!economy && <Badge
size="1"
color={stale ? "amber" : "green"}
variant="soft"
className={`status ${stale ? "bad" : ""}`}
>
<i />
{stale
? state?.status === "live"
? "SYNCING"
: "RECONNECTING"
: "LIVE"}
</Badge>}
</div>
</header>
<MissionStatusBar onNavigate={()=>setSection("missions")}/>
<div className="research-body"><div className="research-content">
<div className="blackrock-host" hidden={!economy}>{returnToMission&&<Button onClick={()=>setSection('missions')}>Return to mission & supplies</Button>}{(economy || researchVisited) && <BlackrockWorkspace onOpenSwarm={id=>{setSwarmRequest({id,requestId:Date.now()});setExpanded(false);setSection("swarms");}} onAsk={askResearch} navigationId={researchNavigationId} onNavigate={navigateResearch} active={economy} researchRequest={researchRequest} onContext={setResearchContext} onEntityContext={setAssistantEntity} section={(economy?section:lastEconomy.current) as ResearchSection} onOpenWorld={(name?:string)=>{setSection("map");if(name){setExpanded(false);void selectPlayer(name);}}} />}</div>
<div className="world-host" hidden={economy}>
<div className="metrics" aria-label="World statistics">
{[
{
icon: Users,
value: state?.onlineCount,
label: "Online players",
note: "Global roster",
},
{
icon: Target,
value: state?.npcCount,
label: "World NPCs",
note: "Across the world",
},
{
icon: Eye,
value: state?.npcs.length,
label: "In observation area",
note: "Detailed live coverage",
},
{
icon: Activity,
value: state?.intel.events,
label: "Recorded events",
note: "Your local history",
},
{
icon: Database,
value: state?.intel.entities,
label: "Entity dossiers",
note: "Searchable intelligence",
},
].map(({ icon: Icon, value, label: caption, note }) => (
<Card key={caption} className="metric-card" size="1">
<div className="metric-caption">
<Icon size={14} />
{caption}
</div>
<div className="metric-value">
{fmt(value)}
<span>{note}</span>
</div>
</Card>
))}
</div>
{(stateError || error) && (
<div className="error-banner" role="alert">
{stateError ? "Local API disconnected. Retrying…" : error}
<Button
className="icon"
onClick={() => setError("")}
aria-label="Dismiss error"
>
<X size={14} />
</Button>
</div>
)}
<main>
<aside className="roster">
<div className="panel-heading">
<span>WORLD ENTITIES</span><Button size="1" variant="ghost" aria-label="Close player roster" onClick={()=>setRosterOpen(false)}><X size={14}/></Button>
<span className="tag">
{state?.rosterStale ? "LAST KNOWN" : "LIVE ROSTER"}
</span>
</div>
<div className="roster-tabs">
{["players", "npcs", "watch", "places"].map((t) => (
<Button
key={t}
aria-pressed={list === t}
className={list === t ? "active" : ""}
onClick={() => setList(t)}
>
{t === "watch" ? <Bookmark size={13} /> : null}
{t === "npcs" ? "NPCs" : label(t)}
{t === "watch" && <small>{state?.watches.length ?? 0}</small>}
</Button>
))}
</div>
{list === "places" ? (
<div className="places">
<h4>Jump to region</h4>
{LOCATIONS.map((p) => (
<Button key={p.label} onClick={() => fly(p.x, p.z, p.height, p.plane??0)}>
<MapPin size={14} />
<span>
{p.label}
<small>
{p.x}, {p.z}
</small>
</span>
<ChevronRight size={14} />
</Button>
))}
<h4>
Saved waypoints <span>{presets.length}</span>
</h4>
{presets.map((p: any) => (
<Button key={p.id} onClick={() => fly(p.x, p.z, p.height, p.plane??0)}>
<Bookmark size={14} />
<span>
{p.label}
<small>
{p.x}, {p.z}
</small>
</span>
</Button>
))}
<label className="field">
Waypoint name
<TextField.Input
size="2"
variant="surface"
value={waypointLabel}
onChange={(e) => setWaypointLabel(e.target.value)}
placeholder="North gate observation"
/>
</label>
<Button
className="wide"
disabled={
!waypointLabel.trim() || !tabCamera.at || Date.now()-tabCamera.at>5000
}
onClick={async () => {
const c = tabCamera;
const r = await run("/api/waypoints", {
label: waypointLabel,
x: c.x,
z: c.z,
height: c.height,
});
if (r) setWaypointLabel("");
}}
>
<Plus size={14} /> Save camera location
</Button>
</div>
) : (
<>
<label className="search">
<Search size={15} />
<TextField.Input
size="2"
variant="surface"
aria-label="Search entities"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder={
list === "npcs" ? "Search nearby NPCs…" : "Find a player…"
}
/>
{query && (
<Button
className="icon"
aria-label="Clear search"
onClick={() => setQuery("")}
>
<X size={13} />
</Button>
)}
</label>
{list !== "npcs" && <div className="ops-roster-filter"><TeamFilter data={operations} value={selectedTeam} onChange={setSelectedTeam}/></div>}
<div className="filter-line">
<span>{roster.length} results</span>
{list !== "npcs" && (
<label>
Combat ≥{" "}
<FilterSelect
label="Minimum combat level"
value={String(minimum)}
onValueChange={(v) => setMinimum(Number(v))}
options={[0, 50, 80, 100, 120].map((n) => ({
value: String(n),
label: n ? String(n) : "Any",
}))}
/>
</label>
)}
</div>
<div className="list-head">
<span>ENTITY</span>
<span>LVL</span>
<span>LOCATION</span>
</div>
<div className="entity-list">
{roster.slice(0, limit).map((p: any) => (
<Button
className={`entity-row allegiance-${list==='npcs'?'npc':(p.allegiance??'unknown')} ${(selection?.kind === "player" && selection.name.toLowerCase() === p.name.toLowerCase()) || (selection?.kind === "npc" && selection.id === p.id && list === "npcs") ? "selected" : ""}`}
key={p.id}
aria-label={`Inspect ${p.name}${list === "npcs" ? ` NPC ${p.id}` : ""}`}
onClick={() =>
list === "npcs"
? (setSelection({ kind: "npc", id: p.id }),
fly(p.x, p.z))
: selectPlayer(p.name)
}
>
<span className="entity-name" title={list==='npcs'?'NPC':p.allegiance==='friendly'?'Friendly · project roster':p.allegiance==='enemy'?'Enemy candidate · not on friendly roster':'Allegiance unknown'}>
<i
className={
p.observed || list === "npcs" ? "observed" : ""
}
/>
{p.name}
{state?.watches.some(
(w: any) => w.name === p.name.toLowerCase(),
) && <Bookmark size={10} />}
</span>
<span>{p.combatLevel ?? "—"}</span>
<span>
{p.x}, {p.z}
</span>
</Button>
))}
{roster.length > limit && (
<Button
className="wide"
onClick={() => setLimit((v) => v + 100)}
>
Load 100 more <ChevronDown size={13} />
</Button>
)}
{!roster.length && (
<Empty
title={
list === "watch"
? "No watched players online"
: "No matching entities"
}
>
{list === "npcs"
? "NPC details cover the camera observation area."
: onlyMyBots ? "No known friendly identities match. Turn off Friendlies only to see everyone." : "Try another name or combat filter."}
</Empty>
)}
{list === "watch" &&
state?.watches
.filter((w: any) => !onlyMyBots || state?.friendlies?.names.some((name: string) => name.trim().toLowerCase().replace(/[_ -]/g, "") === w.name.trim().toLowerCase().replace(/[_ -]/g, "")))
.filter(
(w: any) =>
!state.players.some(
(p: any) => p.name.toLowerCase() === w.name,
),
)
.map((w: any) => (
<Button
className="offline-row"
key={w.name}
onClick={() =>
setSelection({ kind: "player", name: w.name })
}
>
<Bookmark size={12} />
{w.name}
<small>Offline / not in roster</small>
</Button>
))}
</div>
<div className="roster-bottom">
<i className="tiny-dot" />{" "}
{list === "npcs" ? "Area observations" : "Global roster"}{" "}
<span>{age(state?.lastRosterAt)}</span>
</div>
</>
)}
</aside>
<section className="workspace">
<div className="workspace-heading">
<div>
<div className="breadcrumb">
RS SDK <ChevronRight size={12} />{" "}
{section === "map" ? "Live operations" : label(section)}
</div>
<h1>
{section === "map"
? "Live world"
: section === "swarms"
? "Swarm intelligence"
: section === "missions"
? "Command workspace"
: section === "operations"
? "Fleet operations"
: section === "signals"
? "Signal stream"
: section === "wealth"
? "Published wealth"
: section === "catalog"
? "World catalog"
: "Agent control surface"}
</h1>
</div>
<div className="workspace-actions">
{section === "map" && (
<>
<Tooltip content="Show known project friendlies only; hide other players in this view">
<Button className={onlyMyBots ? "active" : ""} aria-pressed={onlyMyBots} onClick={() => setOnlyMyBots(v => !v)}><Shield size={14}/> Friendlies only</Button>
</Tooltip>
<Button className={`dual-3d-toggle ${dualWorld?'active':''}`} aria-pressed={dualWorld} onClick={()=>setDualWorld(v=>!v)}><Layers size={14}/>{dualWorld?'Single 3D':'Dual 3D'}</Button>
<Button aria-label="Toggle entity roster" aria-pressed={rosterOpen} onClick={()=>setRosterOpen(v=>!v)}><Users size={14}/> Players</Button>
<Button disabled={!viewerReady} onClick={()=>iframe.current?.contentWindow?.postMessage({type:'rs-watch-native-ui',action:'worldmap',open:true},location.origin)}><Map size={14}/> World map</Button>
<a className="button monitor-tab-link" href={monitorHref(selection?.kind === 'player' ? selection.name : tabCamera.follow)} target="_blank" rel="noopener noreferrer" title="Open an independent monitor tab for this player. Detailed NPC and equipment coverage is still shared.">New monitor tab <ArrowUpRight size={13}/></a>
<a className="button native-viewer-link" href={nativeViewerHref} target="_blank" rel="noreferrer" title="Open Max's native viewer with its own controls">Native viewer <ArrowUpRight size={13}/></a>
<Button
className="explore-button"
aria-label={expanded ? "Return to console" : "Open Max’s native world"}
onClick={() => setExpanded(!expanded)}
>
{expanded ? (
<Minimize2 size={15} />
) : (
<Maximize2 size={15} />
)}
{expanded ? "Intelligence" : "Native world"}
</Button>
</>
)}
<a
className="icon bordered"
href="/api/export"
download="rs-palantir-export.json"
aria-label="Export observations"
>
<Download size={15} />
</a>
</div>
</div>
<div className={`map-stage ${section !== "map" ? "hidden" : ""}`}>
<div className="viewer-frame">
{expanded && <div className="allegiance-legend"><span>● Friendly</span>{!onlyMyBots && <span>● Enemy candidate</span>}{!state?.friendlies?.ready&&<small>Roster unavailable</small>}</div>}
{section === "map" && (
<WorldToolbar>
<span className="dock-brand"><span className="mode-emblem mode-emblem-palantir"><img src="/brand/rs-palantir.png" alt=""/></span><span>RS-PALANTIR<small>WORLD INTELLIGENCE</small></span></span><Button onClick={()=>switchMode("blackrock")}><Activity size={14}/>Resume research</Button>
<Tooltip content="Open player dossiers, gear, signals and agent tools">
<Button className="primary" onClick={() => setExpanded(!expanded)}><Database size={14}/>{expanded?"Intelligence":"Map only"}</Button>
</Tooltip>
{!expanded&&<Button aria-pressed={rosterOpen} onClick={()=>setRosterOpen(!rosterOpen)}><Users size={14}/>Players</Button>}
<Tooltip content="Focus the world · WASD to move · hold Shift for 10× speed">
<Button disabled={!viewerReady} onClick={() => iframe.current?.contentWindow?.postMessage({type:'rs-watch-native-ui',action:'focus'},location.origin)}><Navigation size={14}/> Fly <kbd className="flight-key">Shift ×10</kbd></Button>
</Tooltip>
<Tooltip content="Show known project friendlies only; hide other players in this view">
<Button className={onlyMyBots ? "active" : ""} aria-pressed={onlyMyBots} onClick={() => setOnlyMyBots(v => !v)}><Shield size={14}/> Friendlies only</Button>
</Tooltip>
<a className="button monitor-tab-link" href={monitorHref(selection?.kind === 'player' ? selection.name : tabCamera.follow)} target="_blank" rel="noopener noreferrer" title="Open an independent monitor tab for this player. Detailed NPC and equipment coverage is still shared.">New monitor tab <ArrowUpRight size={13}/></a>
<div className="ops-dock-team"><TeamFilter data={operations} value={selectedTeam} onChange={setSelectedTeam}/></div>
<Button onClick={() => {setExpanded(false);setSection("operations");}}><Users size={14}/> Readiness {tactical?.available && !tacticalError && tactical.nearby.length > 0 ? `· ${tactical.nearby.length} nearby` : ""}</Button>
<Button className={`dual-3d-toggle ${dualWorld?'active':''}`} aria-pressed={dualWorld} onClick={()=>setDualWorld(v=>!v)}><Layers size={14}/>{dualWorld?'Single 3D':'Dual 3D'}</Button>
<LocationShortcuts fly={fly} ready={viewerReady} waypoints={presets} onSelect={p=>void fly(p.x,p.z,p.height,p.plane??0,LOCATIONS.find(place=>place.id===p.id)?.defaultPlayerFilter)}/>
<Tooltip content="Open the native terrain atlas">
<Button disabled={!viewerReady} onClick={() => iframe.current?.contentWindow?.postMessage({type:'rs-watch-native-ui',action:'worldmap',open:true},location.origin)}><Map size={14}/> World map</Button>
</Tooltip>
<Button aria-expanded={coordinationOpen} onClick={()=>setCoordinationOpen(v=>!v)}><Target size={14}/>Squad planner</Button>
<Button aria-expanded={showLayers} onClick={()=>setShowLayers(!showLayers)}><Layers size={14}/>Layers</Button>
<Popover.Root><Popover.Trigger><Button><Navigation size={14}/>Coordinates</Button></Popover.Trigger><Popover.Content size="2" aria-label="Fly to coordinates"> <div className="world-coordinate-menu">
<div className="coordinate-fields">
<Navigation size={14} />
<label>
X{" "}
<TextField.Input
size="2"
variant="surface"
aria-label="Camera X"
value={x}
onChange={(e) => setX(e.target.value)}
/>
</label>
<label>
Z{" "}
<TextField.Input
size="2"
variant="surface"
aria-label="Camera Z"
value={z}
onChange={(e) => setZ(e.target.value)}
/>
</label>
<label>
ALT{" "}
<TextField.Input
size="2"
variant="surface"
aria-label="Camera height"
value={height}
onChange={(e) => setHeight(e.target.value)}
/>
</label>
<Button
onClick={() => fly(Number(x), Number(z), Number(height))}
>
Fly to <ChevronRight size={13} />
</Button>
</div>
<span className="camera-readout">
{tabCamera.at && Date.now()-tabCamera.at<=5000
? `${tabCamera.x.toFixed(1)}, ${tabCamera.z.toFixed(1)} · ${tabCamera.follow ? `following ${tabCamera.follow}` : "free camera"}`
: "Awaiting camera"}
</span>
</div>
</Popover.Content></Popover.Root>
<CombatZoneBadge camera={tabCamera}/><Badge variant="soft" color={stale?'amber':'green'} size="1" className="explore-status"><span className="feed-status-dot"/>{stale ? "Feed stale" : "Live world"}</Badge>
</WorldToolbar>
)}
{viewerSrc && (
<FollowMonitors atlas={<PinnedAtlas researchSource={researchSource} players={state?.players??[]} friendlyNames={allegiance?.names??[]} ready={allegiance?.ready??false} stale={!state||state.rosterStale||!!stateError} onSelect={addMonitor}/>} onChangePrimary={name=>{if(!primaryFrame.current)return;iframe.current=primaryFrame.current;setActiveMonitor(null);void command({kind:"follow",name});}} players={(state?.players??[]).map((p:{name:string})=>p.name)} onChangeNames={setFollowMonitors} names={followMonitors} base={viewerSrc} primary={primaryFollow} allegiance={allegiance} onAdd={addMonitor} onAddMany={incoming=>setFollowMonitors(old=>incoming.reduce((all,name)=>addFollowMonitor(all,name,primaryFollow),old))} activeMonitor={activeMonitor} filters={effectivePaneFilters} onFilter={changePaneFilter} onInspect={inspectPane} onActivate={(name,frame)=>{iframe.current=frame;setActiveMonitor(name?botKey(name):null);setViewerReady(false);setPaneVersion(v=>v+1);}} onClose={name=>{setFollowMonitors(names=>names.filter(n=>botKey(n)!==botKey(name)));if(activeMonitor===botKey(name))setActiveMonitor(null);}}>
<WorldViews primaryFrame={primaryFrame} src={viewerSrc} dual={dualWorld} atlasOpen={atlasOpen} nativeUi={expanded} activeFrame={iframe} allegiance={allegiance} onActivate={()=>{setActiveMonitor(null);setViewerReady(false);setPaneVersion(v=>v+1);}} enabled={activeMonitor===null} showControls={true} filters={effectivePaneFilters} onFilter={changePaneFilter} onInspect={inspectPane} onPrimaryFollow={setPrimaryFollow}/>
</FollowMonitors>
)}
<div className="map-topbar">
<span className="scene-tag">
<i className="tiny-dot" />
{!viewerReady ? "VIEWER CONNECTING" : stale ? "RS WORLD · FEED STALE" : "RS WORLD · LIVE"}
</span>
<Button
className={showLayers ? "active" : ""}
onClick={() => setShowLayers(!showLayers)}
>
<Layers size={14} /> Layers
</Button>
</div>
{showLayers && (
<div className="layers-panel">
<h4>Scene layers</h4>
<Button color="amber" variant="soft" disabled={!viewerReady} aria-pressed={!!tabCamera.multiCombatVisible} onClick={()=>iframe.current?.contentWindow?.postMessage({type:'rs-watch-multi-combat',enabled:!tabCamera.multiCombatVisible},location.origin)}>{tabCamera.multiCombatVisible?'Hide':'Show'} multi-combat zones</Button>
<small>Amber areas · local game-source boundaries, live revision unverified.</small>
{Object.entries(layers).map(([key, value]) => (
<label key={key}>
<Checkbox
size="2"
aria-label={key
.replace("show", "")
.replace(/([a-z])([A-Z])/g, "$1 $2")}
checked={value}
onCheckedChange={(checked) => {
const next = { ...layers, [key]: checked === true };
setLayers(next);
command({ kind: "layers", ...next });
}}
/>
{key
.replace("show", "")
.replace(/([a-z])([A-Z])/g, "$1 $2")}
</label>
))}
</div>
)}
<div className="camera-hint">
<span>
<kbd>W A S D</kbd> fly <kbd>E / C</kbd> elevation
</span>
<span>Drag to look · right-drag to pan · scroll to zoom</span>
</div>
</div>
{section==='map'&&coordinationOpen&&<div className="world-coordination-drawer"><Button size="1" variant="ghost" onClick={()=>setCoordinationOpen(false)}>Close squad planner</Button>{mapContext?<Suspense fallback={<p role="status">Loading squad planner…</p>}><CoordinationMapPanel context={mapContext} onPlan={prepareMission} onTrackPlayer={name=>void selectPlayer(name)} selectedPlayerKey={selection?.name?.toLowerCase().replace(/\s+/g,'_')}/></Suspense>:<p role="status">{coordinationError?'Coordination source unavailable':'Loading current observations…'}</p>}</div>}
<div className="live-strip">
<div className="strip-title">
<Activity size={13} /> OBSERVATIONS{" "}
<Button onClick={() => setSection("signals")}>
View all <ArrowUpRight size={12} />
</Button>
</div>
<EventRows
events={(feed?.events ?? [])
.filter(
(e: any) =>
!["animation", "spot_animation"].includes(e.kind),
)
.slice(0, 4)}
onEntity={selectPlayer}
onFly={fly}
compact
/>
</div>
</div>
{(section === "swarms"||swarmVisited) && <div className="intelligence-route" hidden={section!=="swarms"}><Suspense fallback={<p role="status">Loading swarm intelligence…</p>}><SwarmWorkspace groupRequest={swarmRequest} active={section==='swarms'} onPrepareMission={value=>{setMissionResearch(value);setExpanded(false);setSection('missions');}} onContext={setIntelEntity} onAsk={askResearch} onInspectPlayer={name=>{setSection("map");setSelection({kind:"player",name});setExpanded(false);}} onShowPlayer={name=>{setSection("map");setExpanded(false);void selectPlayer(name);}}/></Suspense></div>}
{(section === "missions"||missionVisited) && <div className="intelligence-route" hidden={section!=="missions"}>{missionResearch?.source==='swarm'&&<Button onClick={()=>setSection('swarms')}>Back to swarm research</Button>}<Suspense fallback={<p role="status">Loading command workspace…</p>}><MissionWorkspace active={section==='missions'} mapContext={mapContext} initialSelection={planSelection} researchSelection={missionResearch} onOpenWorld={(point,name)=>{setSection('map');if(name)void selectPlayer(name);else if(point)void fly(point.x,point.z,70);}} onTrackPlayer={name=>{setSection('map');void selectPlayer(name);}} onOpenItem={(id,name,view)=>{setReturnToMission(true);openResearch({kind:'item',key:String(id),itemId:id,name,view});}} onContext={id=>setIntelEntity({kind:"mission",key:id,name:"Mission preview"})}/></Suspense></div>}
{section === "settings" && <SettingsPage onNavigate={setSection} onOpenAssistant={()=>toggleAssistant(true)}/>}
{section === "operations" && <OperationsPanel tactical={tactical} tacticalError={tacticalError} data={operations} error={operationsError} players={state?.players ?? []} rosterStale={!state || state.rosterStale || !!stateError} onRefresh={refreshOperations} onInspect={name => {setExpanded(false);setSection("map");setSelection({kind:"player",name});if(state?.players.some((p:any)=>botKey(p.name)===botKey(name)))void selectPlayer(name);}}/>}
{section === "signals" && (
<div className="data-surface">
<div className="surface-toolbar">
<label className="search">
<Search size={14} />
<TextField.Input
size="2"
variant="surface"
aria-label="Search signals"
value={eventQuery}
onChange={(e) => setEventQuery(e.target.value)}
placeholder="Entity, message, item…"
/>
</label>
<FilterSelect
label="Signal type"
value={eventKind}
onValueChange={setEventKind}
options={[
"all",
"chat",
"hitsplat",
"equipment",
"animation",
"teleport",
"roster_join",
"roster_leave",
].map((v) => ({ value: v, label: label(v) }))}
/>
<label className="toggle">
<Checkbox
size="2"
checked={onlyWatched}
onCheckedChange={(checked) =>
setOnlyWatched(checked === true)
}
/>{" "}
Watched only
</label>
</div>
<div className="source-notice">
<Radio size={13} /> {feed?.coverage} · Latest 100 matching
events shown.
</div>
<EventRows events={events} onEntity={selectPlayer} onFly={fly} />
</div>
)}
{section === "wealth" && (
<div className="data-surface">
<div className="surface-toolbar">
<div className="segmented">
<Button
className={catalogKind !== "npcs" ? "active" : ""}
onClick={() => setCatalogKind("items")}
>
Bank leaderboard
</Button>
<Button
className={catalogKind === "npcs" ? "active" : ""}
onClick={() => setCatalogKind("npcs")}
>
Outfit leaderboard
</Button>
</div>
<a
className="source-link"
href={board?.source}
target="_blank"
rel="noreferrer"
>
Public source <ArrowUpRight size={12} />
</a>
</div>
<div className="source-notice">
Published top 50 · partial item previews · fetched{" "}
{age(board?.fetchedAt)} · publication time unknown
</div>
{boardError && <p className="error">{boardError}</p>}
<div className="table-scroll">
<Table.Table className="data-table">
<Table.Header>
<Table.Row>
<Table.ColumnHeaderCell>RANK</Table.ColumnHeaderCell>
<Table.ColumnHeaderCell>PLAYER</Table.ColumnHeaderCell>
<Table.ColumnHeaderCell>
PUBLISHED VALUE
</Table.ColumnHeaderCell>
<Table.ColumnHeaderCell>
VISIBLE PREVIEW
</Table.ColumnHeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{board?.rows.map((r: any) => (
<Table.Row
key={r.name}
onClick={() =>
setSelection({ kind: "player", name: r.name })
}
>
<Table.Cell>#{r.rank}</Table.Cell>
<Table.Cell>
<Button className="entity-link">{r.name}</Button>
</Table.Cell>
<Table.Cell className="gold">{r.valueLabel}</Table.Cell>
<Table.Cell>
{r.items.length?<div className="wealth-items">{r.items.map((i:any)=><span key={i.id} title={`${i.label}${i.count!=null?` · ${fmt(i.count)}`:''}`}><ItemSprite id={i.id} name={i.label}/>{i.count!=null&&<small>{fmt(i.count)}</small>}</span>)}</div>:"No preview published"}
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Table>
</div>
</div>
)}
{section === "catalog" && (
<div className="data-surface">
<div className="surface-toolbar">
<div className="segmented">
<Button
className={catalogKind === "items" ? "active" : ""}
onClick={() => {
setCatalogKind("items");
setCatalogOffset(0);
}}
>
Items
</Button>
<Button
className={catalogKind === "npcs" ? "active" : ""}
onClick={() => {
setCatalogKind("npcs");
setCatalogOffset(0);
}}
>
NPCs
</Button>
</div>
<label className="search">
<Search size={14} />
{catalogKind==='items'?<ItemSearchInput label="Search catalog" value={catalogQuery} onChange={value=>{setCatalogQuery(value);setCatalogOffset(0)}} onPick={item=>{setCatalogQuery(String(item.id));setCatalogOffset(0)}}/>:<TextField.Input
size="2"
variant="surface"
aria-label="Search catalog"
value={catalogQuery}
onChange={(e) => {
setCatalogQuery(e.target.value);
setCatalogOffset(0);
}}
placeholder="Name or definition ID…"
/>}
</label>
</div>
<div className="source-notice">
{fmt(catalog?.total)} matching definitions · revision 289 ·
definition data does not establish possession
</div>
<div className="table-scroll">
<Table.Table className="data-table">
<Table.Header>
<Table.Row>
<Table.ColumnHeaderCell>ID</Table.ColumnHeaderCell>
<Table.ColumnHeaderCell>NAME</Table.ColumnHeaderCell>
<Table.ColumnHeaderCell>
{catalogKind === "items" ? "BASE VALUE" : "COMBAT"}
</Table.ColumnHeaderCell>
<Table.ColumnHeaderCell>EXAMINE</Table.ColumnHeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{catalog?.results.map((r: any) => (
<Table.Row
key={r.id}
onClick={() =>
setSelection({ kind: "catalog", item: {...r,assetKind:catalogKind} })
}
>
<Table.Cell>{r.id}</Table.Cell>
<Table.Cell>
<div className="catalog-item">{catalogKind==='items'&&<ItemSprite id={r.id} name={r.name}/>}<Button className="entity-link">{r.name}</Button></div>
</Table.Cell>
<Table.Cell>
{catalogKind === "items"
? `${fmt(r.baseValue)} gp`
: (r.combatLevel ?? "—")}
</Table.Cell>
<Table.Cell>{r.description || "—"}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Table>
</div>
</div>
)}
{section === "catalog" && (
<div className="pagination">
<Button
disabled={!catalogOffset}
onClick={() => setCatalogOffset((v) => Math.max(0, v - 80))}
>
Previous
</Button>
<span>
{catalogOffset + 1}–
{Math.min(catalogOffset + 80, catalog?.total ?? 0)} /{" "}
{fmt(catalog?.total)}
</span>
<Button
disabled={catalogOffset + 80 >= (catalog?.total ?? 0)}
onClick={() => setCatalogOffset((v) => v + 80)}
>
Next
</Button>
</div>
)}
{section === "agent" && (
<div className="agent-surface">
<div className="agent-intro">
<Terminal size={24} />
<h2>One interface for agents and you.</h2>
<p>
Discover, inspect, watch, navigate. Every result carries its
source and time. Camera commands have an acknowledgement; a
queued command is not proof of execution.
</p>
<div>
<a
className="button primary"
href="/api/openapi.json"
target="_blank"
rel="noreferrer"
>
OpenAPI schema <ArrowUpRight size={14} />
</a>
<a
className="button"
href="/agent-guide"
target="_blank"
rel="noreferrer"
>
Agent guide <ArrowUpRight size={14} />
</a>
</div>
</div>
<h4>MCP · local stdio server</h4>
<div className="codebar">
<code>
bun run world:intel:mcp
</code>
<Button
className="icon"
aria-label="Copy MCP command"
onClick={async () => {
await navigator.clipboard.writeText(
"bun run world:intel:mcp",
);
setCopied(true);
}}
>
{copied ? <Check size={14} /> : <Copy size={14} />}
</Button>
</div>
<h4>rs-sdk · shared live intelligence</h4>
<div className="codebar"><code>bun run world:intel -- intel --observer AuraMaxxer --radius 32</code></div>
<p className="note">Existing project MCP: world_intel / world_friendlies. HTTP: /api/intel. Native scripts: sdk/world-intel.ts. Fresh player snapshots are global; detailed NPC coverage is shared and bounded.</p>
<p className="note">Friendly registry: {state?.friendlies?.ready ? `${fmt(state.friendlies.names.length)} known identities` : "Unavailable — allegiance unknown"}. Green = project friendly; red = enemy candidate, not proven hostile.</p>
<a href="/api/friendlies" target="_blank" rel="noreferrer" className="button">View friendly registry <ArrowUpRight size={14}/></a>
<h4>Agent camera control · this tab</h4>
<Button aria-pressed={agentControl} className={agentControl ? 'active' : ''} onClick={()=>setAgentControl(v=>!v)}>{agentControl ? 'Agent control enabled' : 'Enable agent control in this tab'}</Button>
<p className="note">Follow, Fly, filters and camera saves stay in their own browser tab. Enable shared API/MCP camera commands in just the tab you want agents to steer. Each tab has its own camera; detailed NPC, equipment and skull observations still share one feed area.</p>
<h4>This tab’s latest camera command</h4>
<div className="command-state"><Badge size="1" variant="soft" className="badge">{viewCommand?.status ?? 'NO COMMAND'}</Badge><span>{viewCommand?.kind} {viewCommand?.name ?? ''}</span></div>
<h4>Latest shared agent camera command</h4>
<div className="command-state">
<Badge size="1" variant="soft" className="badge">
{state?.command?.status ?? "NO COMMAND"}
</Badge>
<span>
{state?.command?.kind} {state?.command?.name ?? ""}
</span>
<code>{state?.command?.id?.slice(0, 8)}</code>
</div>
<Json
data={
state?.command ?? {
hint: "Use POST /api/commands or the MCP fly_to / follow_player tools",
}
}
/>
<h4>Available sources</h4>
{caps?.sources.map((s: any) => (
<Card className="source-card" key={s.id}>
<strong>
{s.id}
<span>{s.type}</span>
</strong>
<p>{s.coverage}</p>
<div className="chips">
{s.fields.map((f: string) => (
<span key={f}>{f}</span>
))}
</div>
<small>{s.freshness}</small>
</Card>
))}
<h4>Explicit unknowns</h4>
{caps?.unavailable.map((u: any) => (
<div className="unknown" key={u.field}>
<LockKeyhole size={14} />
<div>
<strong>{label(u.field)}</strong>
<p>{u.reason}</p>
</div>
</div>
))}
</div>
)}
</section>
<Inspector
selection={selection}
state={state}
onClose={() => setSelection(null)}
onFollow={selectPlayer}
onResearch={openResearch}
gearRequest={gearRequest}
onWatch={watch}
onFly={fly}
/>
</main>
<footer>
<span>
<i className={`tiny-dot ${stale ? "gray" : ""}`} /> WORLD FEED{" "}
<b>·</b> tick {fmt(state?.tick)} <b>·</b> {age(state?.lastTickAt)}
</span>
<span className="footer-middle">
Local history · {fmt(state?.intel.trailSamples)} position samples{" "}
<b>·</b> one shared observation area
</span>
<span>
<Code size={12} /> API READY <b>·</b> {state?.viewerClients ?? 0}{" "}
viewer(s)
</span>
</footer>
</div>
</div><AssistantPanel draftRequest={assistantDraftRequest} open={assistantOpen} onClose={()=>toggleAssistant(false)} context={{mode:economy?'blackrock':'palantir',section,label:economy?researchContext:section==='swarms'?'Swarm intelligence':section==='missions'?'Command workspace':selection?.name??'World overview',entity:economy?assistantEntity:section==='swarms'?(intelEntity?.kind==='swarm'?intelEntity:null):section==='missions'?(intelEntity?.kind==='mission'?intelEntity:null):selection?.kind==='player'?{kind:'player',key:selection.name,name:selection.name}:null}}/></div>
</div>
);
}
createRoot(document.getElementById("root")!).render(
<Theme
appearance="dark"
accentColor="blue"
grayColor="slate"
className="rs-theme"
>
<App />
</Theme>,
);