trenches / src /components /CommandMap.tsx
Codex
sync main snapshot for HF Space
1794757
import { useEffect, useId, useMemo, useRef, useState, type CSSProperties } from "react";
import mapboxgl, {
type GeoJSONSource,
type LngLatBoundsLike,
type MapboxGeoJSONFeature,
type MapMouseEvent,
} from "mapbox-gl";
import { CommandGlobe } from "./CommandGlobe";
import { getMapboxToken } from "../lib/env";
import type { MapSelection, ViewerMapEntity, ViewerMapFeature, ViewerMapLink, ViewerMapState } from "../lib/viewer-map";
type CommandMapProps = {
entities: ViewerMapEntity[];
features: ViewerMapFeature[];
links?: ViewerMapLink[];
selectedEntity: MapSelection;
onSelectEntity: (entityId: MapSelection) => void;
worldSummary: ViewerMapState["worldSummary"] & {
activeEventCount?: number;
lastUpdatedLabel?: string;
};
};
type GeoJsonFeatureProperties = {
id: string;
entityId: string;
entityLabel: string;
title: string;
subtitle: string;
category: string;
importance: string;
color: string;
accent: string;
selected: number;
dimmed: number;
interactive: number;
};
type GeoJsonFeatureCollection = GeoJSON.FeatureCollection<GeoJSON.Geometry, GeoJsonFeatureProperties>;
type MapFeatureMouseEvent = MapMouseEvent & { features?: MapboxGeoJSONFeature[] };
const DEFAULT_CENTER: [number, number] = [41.8, 27.8];
const DEFAULT_ZOOM = 2.35;
const FALLBACK_ENTITY: MapSelection = "all";
const MAP_STYLE = "mapbox://styles/mapbox/dark-v11";
const INTEL_HIDDEN_LAYERS = [
"road-label",
"settlement-label",
"settlement-subdivision-label",
"airport-label",
"poi-label",
"transit-label",
"natural-label",
];
const LAYER_LABELS: Record<string, string> = {
alliance_anchor: "Alliance Anchor",
chokepoint: "Chokepoint",
coalition_link: "Coalition Link",
front: "Front",
geospatial_anchor: "Geospatial Anchor",
infrastructure: "Infrastructure",
location: "Location",
strategic_site: "Strategic Site",
};
export function CommandMap({
entities,
features,
links = [],
selectedEntity,
onSelectEntity,
worldSummary,
}: CommandMapProps) {
const mapContainerRef = useRef<HTMLDivElement | null>(null);
const mapRef = useRef<mapboxgl.Map | null>(null);
const popupRef = useRef<mapboxgl.Popup | null>(null);
const [interactiveReady, setInteractiveReady] = useState(false);
const [mapError, setMapError] = useState<string | null>(null);
const mapId = useId().replace(/:/g, "");
const sourceId = `trenches-command-map-source-${mapId}`;
const token = getMapboxToken();
const hasToken = typeof token === "string" && token.trim().length > 0;
const entityLookup = useMemo(
() => new Map(entities.map((entity) => [entity.id, entity])),
[entities],
);
const geoJson = useMemo<GeoJsonFeatureCollection>(() => {
const pointFeatures: GeoJSON.Feature<GeoJSON.Point, GeoJsonFeatureProperties>[] = features.map((feature) => {
const entity = entityLookup.get(feature.entityId);
const isSelected = selectedEntity === FALLBACK_ENTITY || selectedEntity === feature.entityId;
return {
type: "Feature",
id: feature.id,
properties: {
id: feature.id,
entityId: feature.entityId,
entityLabel: feature.entityName,
title: feature.name,
subtitle: feature.description,
category: feature.layer,
importance: feature.layer === "chokepoint" ? "critical" : feature.layer === "front" ? "high" : "medium",
color: entity?.color ?? "#90d1ff",
accent: entity?.accent ?? "#dff3fb",
selected: isSelected ? 1 : 0,
dimmed: isSelected ? 0 : 1,
interactive: 1,
},
geometry: {
type: "Point",
coordinates: [feature.longitude, feature.latitude],
},
};
});
const linkFeatures: GeoJSON.Feature<GeoJSON.LineString, GeoJsonFeatureProperties>[] = links.map((link) => {
const entity = entityLookup.get(link.fromAgentId);
const isSelected =
selectedEntity === FALLBACK_ENTITY || selectedEntity === link.fromAgentId || selectedEntity === link.toAgentId;
const fromLabel = entityLookup.get(link.fromAgentId)?.displayName ?? link.fromAgentId;
const toLabel = entityLookup.get(link.toAgentId)?.displayName ?? link.toAgentId;
return {
type: "Feature",
id: link.id,
properties: {
id: link.id,
entityId: link.fromAgentId,
entityLabel: `${fromLabel}${toLabel}`,
title: "Coalition Link",
subtitle: `${fromLabel} coordinated with ${toLabel}.`,
category: "coalition_link",
importance: "medium",
color: entity?.color ?? "#90d1ff",
accent: entity?.accent ?? "#dff3fb",
selected: isSelected ? 1 : 0,
dimmed: isSelected ? 0 : 1,
interactive: 0,
},
geometry: {
type: "LineString",
coordinates: [link.from, link.to],
},
};
});
return {
type: "FeatureCollection",
features: [...linkFeatures, ...pointFeatures],
};
}, [entityLookup, features, links, selectedEntity]);
const focusFeatures = useMemo(() => {
if (selectedEntity === FALLBACK_ENTITY) {
return features;
}
return features.filter((feature) => feature.entityId === selectedEntity);
}, [features, selectedEntity]);
const focusLinks = useMemo(() => {
if (selectedEntity === FALLBACK_ENTITY) {
return links;
}
return links.filter((link) => link.fromAgentId === selectedEntity || link.toAgentId === selectedEntity);
}, [links, selectedEntity]);
const categorySummary = useMemo(() => {
const counts = new Map<string, number>();
for (const feature of focusFeatures) {
counts.set(feature.layer, (counts.get(feature.layer) ?? 0) + 1);
}
return [...counts.entries()]
.sort((left, right) => right[1] - left[1])
.slice(0, 5)
.map(([layer, count]) => ({
layer,
label: LAYER_LABELS[layer] ?? startCase(layer),
count,
}));
}, [focusFeatures]);
const selectedEntityMeta = useMemo(() => {
if (selectedEntity === FALLBACK_ENTITY) {
return {
label: "All Entities",
color: "linear-gradient(135deg, #87f8c1 0%, #6bb8ff 100%)",
headline: "Viewer-wide synthesis of every actor footprint, infrastructure chain, coalition line, and chokepoint.",
priorities: ["Cross-entity route awareness", "Coalition edges", "Escalation geography", "Foreign basing"],
featureCount: features.length,
foreignBaseCount: 0,
};
}
const entity =
selectedEntity === FALLBACK_ENTITY ? undefined : entityLookup.get(selectedEntity as ViewerMapEntity["id"]);
return {
label: entity?.displayName ?? selectedEntity,
color: entity?.color ?? "#90d1ff",
headline: entity?.headline ?? "Monitor the mapped footprint and strategic posture.",
priorities: entity?.priorities ?? [],
featureCount: entity?.featureCount ?? focusFeatures.length,
foreignBaseCount: entity?.foreignBaseCount ?? 0,
};
}, [entityLookup, features.length, focusFeatures.length, selectedEntity]);
useEffect(() => {
if (!hasToken || !mapContainerRef.current || mapRef.current) {
return;
}
setInteractiveReady(false);
setMapError(null);
mapboxgl.accessToken = token;
let map: mapboxgl.Map;
try {
map = new mapboxgl.Map({
container: mapContainerRef.current,
style: MAP_STYLE,
center: DEFAULT_CENTER,
zoom: DEFAULT_ZOOM,
attributionControl: false,
projection: "globe",
});
} catch (error) {
setMapError(error instanceof Error ? error.message : "Failed to initialize WebGL.");
return;
}
mapRef.current = map;
popupRef.current = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false,
offset: 18,
className: "command-map-popup",
});
map.addControl(new mapboxgl.NavigationControl({ visualizePitch: true }), "bottom-right");
map.on("style.load", () => {
applyIntelligenceTheme(map);
map.setFog({
color: "rgba(1, 5, 8, 0.96)",
"high-color": "rgba(9, 27, 39, 0.34)",
"space-color": "rgba(2, 5, 8, 1)",
"star-intensity": 0.08,
range: [-1, 2],
});
});
map.on("load", () => {
setInteractiveReady(true);
if (!map.getSource(sourceId)) {
map.addSource(sourceId, {
type: "geojson",
data: geoJson,
});
}
map.addLayer({
id: `${sourceId}-lines`,
type: "line",
source: sourceId,
filter: ["==", ["geometry-type"], "LineString"],
paint: {
"line-color": ["get", "color"],
"line-width": ["case", ["==", ["get", "selected"], 1], 3.2, 1.8],
"line-opacity": ["case", ["==", ["get", "selected"], 1], 0.9, 0.24],
"line-blur": ["case", ["==", ["get", "selected"], 1], 0.28, 0.85],
},
});
map.addLayer({
id: `${sourceId}-point-halo`,
type: "circle",
source: sourceId,
filter: ["==", ["geometry-type"], "Point"],
paint: {
"circle-radius": ["case", ["==", ["get", "selected"], 1], 15, 9],
"circle-color": ["get", "color"],
"circle-opacity": ["case", ["==", ["get", "selected"], 1], 0.2, 0.05],
"circle-blur": 0.58,
},
});
map.addLayer({
id: `${sourceId}-points`,
type: "circle",
source: sourceId,
filter: ["==", ["geometry-type"], "Point"],
paint: {
"circle-radius": [
"case",
["==", ["get", "importance"], "critical"],
6.8,
["==", ["get", "importance"], "high"],
5.9,
4.9,
],
"circle-color": ["get", "color"],
"circle-stroke-color": ["case", ["==", ["get", "selected"], 1], "#f8fdff", "rgba(255,255,255,0.42)"],
"circle-stroke-width": ["case", ["==", ["get", "selected"], 1], 1.45, 0.8],
"circle-opacity": ["case", ["==", ["get", "selected"], 1], 0.98, 0.34],
},
});
map.addLayer({
id: `${sourceId}-labels`,
type: "symbol",
source: sourceId,
filter: ["all", ["==", ["geometry-type"], "Point"], ["==", ["get", "selected"], 1]],
layout: {
"text-field": ["get", "title"],
"text-size": 11,
"text-offset": [0, 1.28],
"text-anchor": "top",
"text-font": ["DIN Pro Medium", "Arial Unicode MS Regular"],
},
paint: {
"text-color": "rgba(233, 244, 248, 0.92)",
"text-halo-color": "rgba(4, 10, 15, 0.95)",
"text-halo-width": 1.2,
"text-opacity": 0.9,
},
});
bindInteraction(map, popupRef.current, onSelectEntity);
fitMapToSelection(map, focusFeatures, focusLinks);
});
map.on("error", (event) => {
const nextError = event.error;
setMapError(nextError instanceof Error ? nextError.message : "Map rendering error.");
});
return () => {
popupRef.current?.remove();
popupRef.current = null;
setInteractiveReady(false);
setMapError(null);
map.remove();
mapRef.current = null;
};
}, [focusFeatures, focusLinks, geoJson, hasToken, onSelectEntity, sourceId, token]);
useEffect(() => {
const map = mapRef.current;
if (!map) {
return;
}
const source = map.getSource(sourceId) as GeoJSONSource | undefined;
if (source) {
source.setData(geoJson);
}
fitMapToSelection(map, focusFeatures, focusLinks);
}, [focusFeatures, focusLinks, geoJson, sourceId]);
return (
<section className="command-map">
<div className="command-map__header">
<div>
<p className="command-map__eyebrow">Viewer Layer</p>
<h2>World Intelligence Layer</h2>
<p className="command-map__lede">
This is a spectator command surface. Agents do not receive this spatial synthesis in their observation
payload.
</p>
</div>
<div className="command-map__metrics">
<MetricCard label="Turn" value={String(worldSummary.turn)} tone="neutral" />
<MetricCard label="Tension" value={worldSummary.tension.toFixed(1)} tone={scoreTone(worldSummary.tension)} />
<MetricCard
label="Market Stress"
value={worldSummary.marketStress.toFixed(1)}
tone={scoreTone(worldSummary.marketStress)}
/>
<MetricCard label="Oil" value={worldSummary.oilPressure.toFixed(1)} tone={scoreTone(worldSummary.oilPressure)} />
<MetricCard label="Live" value={worldSummary.liveMode ? "Armed" : "Static"} tone="neutral" />
<MetricCard label="Events" value={String(worldSummary.activeEventCount ?? 0)} tone="neutral" />
</div>
</div>
<div className="command-map__viewport">
<div className="command-map__surface">
{hasToken && !mapError ? (
<div ref={mapContainerRef} className="command-map__canvas" aria-label="Operational asset map" />
) : !hasToken ? (
<div className="command-map__fallback" role="status" aria-live="polite">
<div className="command-map__fallback-badge">Mapbox token missing</div>
<h3>Spatial viewer is ready, but the tile layer is offline.</h3>
<p>
Set <code>NEXT_PUBLIC_MAPBOX_TOKEN</code> to render the theater map. Entity footprints, coalition links, and
viewer controls remain available.
</p>
<div className="command-map__fallback-grid">
<div>
<span>Tracked footprints</span>
<strong>{features.length}</strong>
</div>
<div>
<span>Coalition links</span>
<strong>{links.length}</strong>
</div>
</div>
</div>
) : (
<CommandGlobe
entities={entities}
features={focusFeatures}
links={focusLinks}
selectedEntity={selectedEntity}
onSelectEntity={onSelectEntity}
/>
)}
{hasToken && mapError ? (
<div className="command-map__render-badge">WebGL unavailable, globe fallback active</div>
) : hasToken && !interactiveReady ? (
<div className="command-map__render-badge">Initializing interactive globe</div>
) : null}
<div className="command-map__overlay command-map__overlay--top">
<div className="command-map__viewer-chip">Operator intelligence wall</div>
{worldSummary.lastUpdatedLabel ? <span className="command-map__timestamp">{worldSummary.lastUpdatedLabel}</span> : null}
</div>
<div className="command-map__overlay command-map__overlay--bottom">
<div className="command-map__legend-line">
<span className="command-map__legend-title">Legend</span>
<span>Signals mark assets, fronts, chokepoints, and foreign basing. Lines trace active coalition edges.</span>
</div>
<div className="command-map__legend-swatches">
{entities.map((entity) => (
<button
key={entity.id}
type="button"
className={`command-map__swatch${selectedEntity === entity.id ? " is-active" : ""}`}
onClick={() => onSelectEntity(entity.id)}
style={cssVarStyle("--command-swatch", entity.color)}
>
<span className="command-map__swatch-color" />
<span>{entity.displayName}</span>
</button>
))}
</div>
</div>
</div>
<aside className="command-map__panel">
<div className="command-map__notice">
<span className="command-map__notice-label">Fog-of-war boundary</span>
<p>
The viewer sees the merged theater footprint. Models only receive text briefs, scoped source bundles, and
role-limited actions.
</p>
</div>
<div className="command-map__selector">
<label htmlFor={`${mapId}-entity-selector`}>Focus Entity</label>
<div className="command-map__selector-grid">
<button
type="button"
className={`command-map__entity-button${selectedEntity === FALLBACK_ENTITY ? " is-active" : ""}`}
onClick={() => onSelectEntity(FALLBACK_ENTITY)}
>
All Entities
</button>
{entities.map((entity) => (
<button
key={entity.id}
type="button"
className={`command-map__entity-button${selectedEntity === entity.id ? " is-active" : ""}`}
onClick={() => onSelectEntity(entity.id)}
style={cssVarStyle("--command-entity-color", entity.color)}
>
{entity.displayName}
</button>
))}
</div>
</div>
<div className="command-map__focus-card">
<div className="command-map__focus-bar" style={{ background: selectedEntityMeta.color }} />
<p className="command-map__focus-label">Active Focus</p>
<h3>{selectedEntityMeta.label}</h3>
<p>{selectedEntityMeta.headline}</p>
{selectedEntityMeta.priorities.length > 0 ? (
<ul className="command-map__priority-list">
{selectedEntityMeta.priorities.slice(0, 4).map((priority) => (
<li key={priority}>{priority}</li>
))}
</ul>
) : null}
<div className="command-map__focus-stats">
<div>
<span>Footprints</span>
<strong>{selectedEntityMeta.featureCount}</strong>
</div>
<div>
<span>Foreign Bases</span>
<strong>{selectedEntityMeta.foreignBaseCount}</strong>
</div>
</div>
</div>
<div className="command-map__category-stack">
<div className="command-map__section-head">
<h3>Top Layers</h3>
<span>{selectedEntity === FALLBACK_ENTITY ? "Entire theater" : "Focused entity"}</span>
</div>
{categorySummary.length > 0 ? (
categorySummary.map((item) => (
<div key={item.layer} className="command-map__category-row">
<span>{item.label}</span>
<strong>{item.count}</strong>
</div>
))
) : (
<p className="command-map__empty">No mapped footprints yet.</p>
)}
</div>
<div className="command-map__entity-list">
<div className="command-map__section-head">
<h3>Entities</h3>
<span>Mapped routing</span>
</div>
{entities.map((entity) => (
<button
key={entity.id}
type="button"
className={`command-map__entity-row${selectedEntity === entity.id ? " is-active" : ""}`}
onClick={() => onSelectEntity(entity.id)}
style={cssVarStyle("--command-entity-color", entity.color)}
>
<span className="command-map__entity-color" />
<span className="command-map__entity-copy">
<strong>{entity.displayName}</strong>
<small>{entity.headline}</small>
</span>
<span className="command-map__entity-count">{entity.featureCount}</span>
</button>
))}
</div>
</aside>
</div>
</section>
);
}
function MetricCard({
label,
value,
tone,
}: {
label: string;
value: string;
tone: "neutral" | "warn" | "hot";
}) {
return (
<div className={`command-map__metric command-map__metric--${tone}`}>
<span>{label}</span>
<strong>{value}</strong>
</div>
);
}
function scoreTone(value: number): "neutral" | "warn" | "hot" {
if (value >= 75) {
return "hot";
}
if (value >= 50) {
return "warn";
}
return "neutral";
}
function applyIntelligenceTheme(map: mapboxgl.Map) {
for (const layerId of INTEL_HIDDEN_LAYERS) {
if (map.getLayer(layerId)) {
map.setLayoutProperty(layerId, "visibility", "none");
}
}
const paintUpdates: Array<{
id: string;
prop: string;
value: string | number;
}> = [
{ id: "background", prop: "background-color", value: "#02070a" },
{ id: "land", prop: "fill-color", value: "#071117" },
{ id: "water", prop: "fill-color", value: "#040b10" },
{ id: "waterway", prop: "line-color", value: "#0d2732" },
{ id: "admin-0-boundary", prop: "line-color", value: "rgba(90, 150, 170, 0.18)" },
{ id: "admin-1-boundary", prop: "line-color", value: "rgba(90, 150, 170, 0.1)" },
{ id: "road-primary", prop: "line-color", value: "rgba(65, 96, 108, 0.16)" },
{ id: "road-secondary-tertiary", prop: "line-color", value: "rgba(55, 78, 88, 0.1)" },
{ id: "airport", prop: "circle-color", value: "rgba(120, 170, 188, 0.18)" },
{ id: "country-label", prop: "text-color", value: "rgba(174, 204, 214, 0.38)" },
{ id: "marine-label", prop: "text-color", value: "rgba(79, 121, 138, 0.32)" },
];
for (const update of paintUpdates) {
if (!map.getLayer(update.id)) {
continue;
}
try {
map.setPaintProperty(update.id, update.prop as never, update.value as never);
} catch {
continue;
}
}
}
function bindInteraction(
map: mapboxgl.Map,
popup: mapboxgl.Popup | null,
onSelectEntity: (entityId: MapSelection) => void,
) {
const interactiveLayers = map
.getStyle()
.layers?.filter((layer) => layer.id.endsWith("-points") || layer.id.endsWith("-lines"))
.map((layer) => layer.id);
if (!interactiveLayers || interactiveLayers.length === 0) {
return;
}
for (const layerId of interactiveLayers) {
map.on("mouseenter", layerId, () => {
map.getCanvas().style.cursor = "pointer";
});
map.on("mouseleave", layerId, () => {
map.getCanvas().style.cursor = "";
popup?.remove();
});
map.on("mousemove", layerId, (event) => {
renderPopup(map, popup, event);
});
map.on("click", layerId, (event) => {
const feature = event.features?.[0];
if (!feature || !feature.properties) {
return;
}
const properties = feature.properties as GeoJsonFeatureProperties;
if (properties.interactive === 1) {
onSelectEntity(properties.entityId as MapSelection);
}
});
}
}
function renderPopup(map: mapboxgl.Map, popup: mapboxgl.Popup | null, event: MapFeatureMouseEvent) {
if (!popup) {
return;
}
const feature = event.features?.[0];
if (!feature || !feature.properties) {
popup.remove();
return;
}
const properties = feature.properties as GeoJsonFeatureProperties;
popup
.setLngLat(resolvePopupCoordinates(feature.geometry))
.setHTML(buildPopupMarkup(properties))
.addTo(map);
}
function buildPopupMarkup(properties: GeoJsonFeatureProperties) {
return [
`<div class="command-map-popup__card">`,
`<span class="command-map-popup__category">${escapeHtml(LAYER_LABELS[properties.category] ?? startCase(properties.category))}</span>`,
`<strong>${escapeHtml(properties.title)}</strong>`,
`<p>${escapeHtml(properties.entityLabel)}</p>`,
properties.subtitle ? `<p class="command-map-popup__subtitle">${escapeHtml(properties.subtitle)}</p>` : "",
`</div>`,
].join("");
}
function resolvePopupCoordinates(geometry: GeoJSON.Geometry): [number, number] {
if (geometry.type === "Point") {
return geometry.coordinates as [number, number];
}
if (geometry.type === "LineString") {
return (geometry.coordinates[0] as [number, number]) ?? DEFAULT_CENTER;
}
return DEFAULT_CENTER;
}
function fitMapToSelection(map: mapboxgl.Map, features: ViewerMapFeature[], links: ViewerMapLink[]) {
const coordinates: Array<[number, number]> = [
...features.map((feature) => [feature.longitude, feature.latitude] as [number, number]),
...links.flatMap((link) => [link.from, link.to]),
];
if (coordinates.length === 0) {
map.easeTo({ center: DEFAULT_CENTER, zoom: DEFAULT_ZOOM, duration: 650 });
return;
}
if (coordinates.length === 1) {
map.easeTo({ center: coordinates[0], zoom: 4.2, duration: 650 });
return;
}
const bounds = new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]);
for (const coordinate of coordinates.slice(1)) {
bounds.extend(coordinate);
}
map.fitBounds(bounds as LngLatBoundsLike, {
padding: { top: 80, right: 420, bottom: 80, left: 80 },
duration: 850,
maxZoom: 5.3,
});
}
function startCase(value: string) {
return value
.replace(/[_-]+/g, " ")
.replace(/\s+/g, " ")
.trim()
.replace(/\b\w/g, (char) => char.toUpperCase());
}
function escapeHtml(value: string) {
return value
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll('"', "&quot;")
.replaceAll("'", "&#39;");
}
function cssVarStyle(name: string, value: string): CSSProperties {
return {
[name]: value,
} as CSSProperties;
}
export default CommandMap;