AI-powered 3D BIM scene control with natural language commands. Control your Cesium 3D scenes using simple, intuitive commands like "show all layers" or "fly to the building".
- π€ AI-Powered Control: Use natural language to control your 3D scene
- ποΈ Layer Management: Show/hide BIM layers with voice commands
- π· Camera Control: Fly to positions, zoom, rotate with AI assistance
- π― Scene Context: AI understands your scene and provides intelligent responses
- β‘ Real-time: Immediate feedback and execution
- π§ Developer Friendly: Simple hooks and TypeScript support
npm install geocopilot
import React, { useRef, useEffect } from 'react';
import * as Cesium from 'cesium';
import { useGeoCopilot, useSceneContext, useCameraControl } from 'GeoCopilot';
const MyApp = () => {
const viewerRef = useRef<Cesium.Viewer | null>(null);
const cesiumContainerRef = useRef<HTMLDivElement>(null);
const [input, setInput] = React.useState('');
const apiKey = process.env.REACT_APP_OPENAI_API_KEY || 'your-api-key-here';
// Initialize hooks
const { contextManager } = useSceneContext();
const { loading, error, lastResponse, run, initialize } = useGeoCopilot(contextManager,apiKey);
const cameraControl = useCameraControl();
// Initialize Cesium viewer
useEffect(() => {
if (cesiumContainerRef.current && !viewerRef.current) {
// Create viewer
viewerRef.current = new Cesium.Viewer(cesiumContainerRef.current, {
globe: false,
});
// Initialize GeoCopilot
initialize(viewerRef.current);
}
}, [initialize, cameraControl]);
const handleCommand = async () => {
if (!input.trim()) return;
await run(input);
setInput('');
};
return (
<div style={{ display: 'flex', height: '100vh' }}>
<div style={{ width: 300, padding: 16 }}>
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Try: 'show all layers'"
/>
<button onClick={handleCommand} disabled={loading}>
{loading ? 'AI thinking...' : 'Execute Command'}
</button>
{error && <div>β {error}</div>}
{lastResponse && <div>β
{lastResponse}</div>}
</div>
<div style={{ flex: 1 }}>
<div ref={cesiumContainerRef} style={{ width: '100%', height: '100%' }} />
</div>
</div>
);
};
Set your OpenAI API key:
# .env
REACT_APP_OPENAI_API_KEY=your_openai_api_key_here
// Register layers for AI control
layerControl.registerObject('building', tileset, {
name: 'Building',
type: 'BIM',
visible: true
});
// Or register multiple layers
const layers = [
{ id: 'architecture', name: 'Architecture', visible: true },
{ id: 'structural', name: 'Structural', visible: false },
{ id: 'electrical', name: 'Electrical', visible: true },
];
layers.forEach(layer => {
layerControl.registerObject(layer.id, null, {
name: layer.name,
type: 'BIM',
visible: layer.visible
});
});
"show all layers"
- Show all registered layers"hide all layers"
- Hide all registered layers"show building layer"
- Show specific layer"hide structural layer"
- Hide specific layer"only show architecture and electrical"
- Show only specified layers"set building opacity to 0.5"
- Set layer transparency
"fly to the building"
- Fly to a specific location"zoom in"
- Zoom closer to the scene"zoom out"
- Zoom away from the scene"rotate left 90 degrees"
- Rotate camera"switch to top view"
- Change camera angle"reset view"
- Return to initial position
"hide structural and electrical, then fly to the main entrance"
- Multiple actions"show only the building facade and zoom to 500 meters"
- Combined operations
Main hook for AI-powered scene control.
const { loading, error, lastResponse, run, clearHistory, initialize } = useGeoCopilot(contextManager);
Returns:
loading: boolean
- AI processing stateerror: string | null
- Error message if anylastResponse: string | null
- Last AI responserun(input: string): Promise<void>
- Execute AI commandclearHistory(): void
- Clear response historyinitialize(viewer: Cesium.Viewer): void
- Initialize with Cesium viewer
Control layer visibility and properties.
const { layers, loading, registerObject, setVisibility, showAll, hideAll } = useLayerControl();
Methods:
registerObject(id, cesiumObject, metadata)
- Register a layersetVisibility(layerId, visible)
- Show/hide layershowAll()
- Show all layershideAll()
- Hide all layersshowOnly(layerIds)
- Show only specified layers
Control camera position and orientation.
const { flyTo, setPosition, zoom, rotate, resetView } = useCameraControl();
Methods:
flyTo(options)
- Smoothly fly to positionsetPosition(options)
- Instantly set camera positionzoom(factor)
- Zoom in/outrotate(heading, pitch)
- Rotate cameraresetView()
- Reset to default view
Access scene context and AI understanding.
const { contextManager, context, getAIContext } = useSceneContext();
interface GeoCopilotState {
loading: boolean;
error: string | null;
lastResponse: string | null;
}
interface LayerInfo {
id: string;
name: string;
type: string;
visible: boolean;
[key: string]: unknown;
}
interface CameraInfo {
longitude: number;
latitude: number;
height: number;
heading: number;
pitch: number;
roll: number;
}
You can extend the AI capabilities by creating custom tools:
import { tool } from "@langchain/core/tools";
import { z } from "zod";
const createCustomTool = (myFunction) => {
return tool(
async ({ action, parameter }) => {
// Your custom logic here
return "Successfully executed custom action";
},
{
name: "customTool",
description: "Your custom tool description",
schema: z.object({
action: z.string(),
parameter: z.string().optional()
})
}
);
};
const { contextManager } = useSceneContext();
// Get current scene context
const context = contextManager.getContext();
// Get AI-optimized context
const aiContext = contextManager.getAIContext();
// Update scene description
contextManager.updateSceneDescription("A modern office building with 5 floors");
import React, { useRef, useEffect } from 'react';
import * as Cesium from 'cesium';
import { useGeoCopilot, useSceneContext, useLayerControl, useCameraControl } from 'GeoCopilot';
const CompleteExample = () => {
const viewerRef = useRef<Cesium.Viewer | null>(null);
const cesiumContainerRef = useRef<HTMLDivElement>(null);
const [input, setInput] = React.useState('');
const apiKey = process.env.REACT_APP_OPENAI_API_KEY || 'your-api-key-here';
const { contextManager } = useSceneContext();
const { loading, error, lastResponse, run, initialize, layerControl } = useGeoCopilot(contextManager,apiKey);
const cameraControl = useCameraControl();
useEffect(() => {
if (cesiumContainerRef.current && !viewerRef.current) {
viewerRef.current = new Cesium.Viewer(cesiumContainerRef.current, {
globe: false,
});
initialize(viewerRef.current);
// Add sample layers
const layers = [
{ id: 'architecture', name: 'Architecture', visible: true },
{ id: 'structural', name: 'Structural', visible: false },
{ id: 'electrical', name: 'Electrical', visible: true },
{ id: 'hvac', name: 'HVAC', visible: true },
];
layers.forEach(layer => {
layerControl.registerObject(layer.id, null, {
name: layer.name,
type: 'BIM',
visible: layer.visible
});
});
}
}, [initialize, cameraControl, layerControl]);
const handleCommand = async () => {
if (!input.trim()) return;
await run(input);
setInput('');
};
return (
<div style={{ display: 'flex', height: '100vh' }}>
<div style={{ width: 300, padding: 16, background: '#f8f9fa' }}>
<h3>π€ GeoCopilot</h3>
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Try: 'show all layers' or 'fly to building'"
style={{ width: '100%', height: 80, marginBottom: 8 }}
/>
<button
onClick={handleCommand}
disabled={loading}
style={{ width: '100%', padding: 8 }}
>
{loading ? 'π€ AI thinking...' : 'π Execute Command'}
</button>
{error && <div style={{ color: 'red' }}>β {error}</div>}
{lastResponse && <div style={{ color: 'green' }}>β
{lastResponse}</div>}
{/* Layer Controls */}
<div style={{ marginTop: 16 }}>
<h4>Manual Layer Control</h4>
{layerControl.layers.map(layer => (
<label key={layer.id} style={{ display: 'block', marginBottom: 4 }}>
<input
type="checkbox"
checked={layer.visible}
onChange={() => layerControl.setVisibility(layer.id, !layer.visible)}
/>
{layer.name}
</label>
))}
</div>
</div>
<div style={{ flex: 1 }}>
<div ref={cesiumContainerRef} style={{ width: '100%', height: '100%' }} />
</div>
</div>
);
};
- React 18+ or 19+
- Cesium 1.131.0+
- LangChain 0.3.29+
- OpenAI API key
MIT