import React, { useState, useCallback, useEffect } from 'react'
import mcpService from '../../services/mcpService'
import appLauncherService from '../../services/appLauncherService'
import MCPStatusBanner from '../../components/MCPStatusBanner'
// Unity3D integration data
const unityData = {
connected: true,
version: '2022.3.15f1',
project: {
name: 'RoboticsSimulation',
path: 'C:/UnityProjects/RoboticsSimulation',
scenes: 12,
assets: 456,
lastBuild: '2024-01-15T16:45:00Z'
},
activeScene: {
name: 'WarehouseScene',
objects: 234,
lights: 8,
cameras: 3,
physicsBodies: 45
},
buildSettings: {
platform: 'Windows',
target: 'x86_64',
compression: 'LZ4HC',
lastBuildTime: '45s',
buildSize: '1.2GB'
},
physics: {
gravity: -9.81,
fixedTimestep: 0.02,
maximumTimestep: 0.1,
solverIterations: 6,
solverVelocityIterations: 1
},
rendering: {
pipeline: 'URP',
quality: 'Ultra',
shadows: 'High',
antiAliasing: 'TAA',
resolution: '1920x1080'
},
roboticsIntegration: {
robotPrefabs: 8,
sensorComponents: 12,
controlScripts: 15,
physicsMaterials: 6
}
}
export default function Unity3DPage() {
console.log('Unity3D Integration loading...')
const [unity, setUnity] = useState(unityData)
const [selectedObject, setSelectedObject] = useState('')
const [consoleOutput, setConsoleOutput] = useState<string[]>([
'[Unity] Scene loaded successfully',
'[Unity] Robotics components initialized',
'[Unity] Physics simulation started'
])
const buildProject = useCallback(async () => {
console.log('Building Unity project...')
setConsoleOutput(prev => [...prev, '[Build] Starting build process...'])
if (mcpConnected) {
try {
// Call Unity3D MCP build tool
const result = await mcpService.unity3dCallTool('build_project', {
platform: unity.buildSettings.platform,
target: unity.buildSettings.target
})
if (result.success) {
setConsoleOutput(prev => [...prev, '[Build] Compilation successful'])
setConsoleOutput(prev => [...prev, `[Build] Build completed: ${result.data?.message || 'Success'}`])
setUnity(prev => ({
...prev,
buildSettings: {
...prev.buildSettings,
lastBuildTime: result.data?.buildTime || '45s'
}
}))
} else {
setConsoleOutput(prev => [...prev, `[Build] Error: ${result.error}`])
}
} catch (error) {
setConsoleOutput(prev => [...prev, `[Build] Error: ${error}`])
}
} else {
// Fallback simulation
setTimeout(() => {
setConsoleOutput(prev => [...prev, '[Build] Compilation successful'])
setTimeout(() => {
setConsoleOutput(prev => [...prev, '[Build] Build completed in 45s'])
setUnity(prev => ({
...prev,
buildSettings: {
...prev.buildSettings,
lastBuildTime: '45s'
}
}))
}, 2000)
}, 1000)
}
}, [mcpConnected, unity.buildSettings])
const playScene = useCallback(async () => {
console.log('Playing Unity scene...')
setConsoleOutput(prev => [...prev, '[Unity] Entering play mode'])
if (mcpConnected) {
try {
const result = await mcpService.unity3dCallTool('play_scene', {
scene_name: unity.activeScene.name
})
if (result.success) {
setConsoleOutput(prev => [...prev, '[Unity] Play mode activated'])
}
} catch (error) {
setConsoleOutput(prev => [...prev, `[Unity] Error: ${error}`])
}
}
}, [mcpConnected, unity.activeScene.name])
const stopScene = useCallback(() => {
console.log('Stopping Unity scene...')
setConsoleOutput(prev => [...prev, '[Unity] Exiting play mode'])
}, [])
const addRobotComponent = useCallback(async (type: string) => {
console.log(`Adding ${type} component...`)
setConsoleOutput(prev => [...prev, `[Unity] Adding ${type} component...`])
if (mcpConnected) {
try {
const result = await mcpService.unity3dCallTool('add_component', {
component_type: type,
scene_name: unity.activeScene.name
})
if (result.success) {
setConsoleOutput(prev => [...prev, `[Unity] Added ${type} component to scene`])
} else {
setConsoleOutput(prev => [...prev, `[Unity] Error adding component: ${result.error}`])
}
} catch (error) {
setConsoleOutput(prev => [...prev, `[Unity] Error: ${error}`])
}
} else {
setConsoleOutput(prev => [...prev, `[Unity] Added ${type} component to scene`])
}
}, [mcpConnected, unity.activeScene.name])
return (
<div style={{
minHeight: '100vh',
backgroundColor: '#0f172a',
color: '#f8fafc',
padding: '24px',
fontFamily: 'system-ui, -apple-system, sans-serif'
}}>
<div style={{ maxWidth: '1400px', margin: '0 auto' }}>
{/* Header */}
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: '32px',
padding: '24px',
backgroundColor: '#1e293b',
borderRadius: '16px',
border: '1px solid #334155'
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: '20px' }}>
<div style={{
width: '64px',
height: '64px',
backgroundColor: '#000000',
borderRadius: '16px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '32px'
}}>
๐ฎ
</div>
<div>
<h1 style={{
fontSize: '32px',
fontWeight: 'bold',
color: '#f8fafc',
marginBottom: '4px'
}}>Unity3D Integration</h1>
<p style={{ color: '#94a3b8' }}>Professional game engine integration for robotics simulation and visualization</p>
</div>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
<div style={{
padding: '8px 16px',
backgroundColor: mcpConnected ? '#10b981' : '#dc2626',
color: 'white',
borderRadius: '20px',
fontSize: '12px',
fontWeight: '500'
}}>
๐ {mcpConnected ? 'MCP Connected' : 'MCP Disconnected'}
</div>
{usingMockData && (
<div style={{
padding: '6px 12px',
backgroundColor: '#f59e0b',
color: 'white',
borderRadius: '12px',
fontSize: '11px',
fontWeight: '500'
}}>
โ ๏ธ MOCK DATA
</div>
)}
<div style={{
padding: '8px 16px',
backgroundColor: '#6b7280',
color: 'white',
borderRadius: '20px',
fontSize: '12px',
fontWeight: '500'
}}>
v{unity.version}
</div>
</div>
</div>
{/* Main Content */}
<div style={{
display: 'grid',
gridTemplateColumns: '1fr 350px',
gap: '24px'
}}>
{/* Left Panel - Scene Viewer & Controls */}
<div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>
{/* Scene Viewer */}
<div style={{
backgroundColor: '#1e293b',
borderRadius: '12px',
border: '1px solid #334155',
padding: '24px',
height: '500px'
}}>
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: '16px'
}}>
<h3 style={{ fontSize: '18px', fontWeight: '600', color: '#f8fafc' }}>
๐ฌ Scene Viewer - {unity.activeScene.name}
</h3>
<div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
{!appRunning ? (
<button
onClick={handleStartUnity}
style={{
padding: '8px 16px',
backgroundColor: '#10b981',
color: 'white',
border: 'none',
borderRadius: '6px',
fontSize: '12px',
fontWeight: '600',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
gap: '6px'
}}
>
โถ๏ธ Start Unity Editor
</button>
) : (
<button
onClick={handleStopUnity}
style={{
padding: '8px 16px',
backgroundColor: '#dc2626',
color: 'white',
border: 'none',
borderRadius: '6px',
fontSize: '12px',
fontWeight: '600',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
gap: '6px'
}}
>
โน๏ธ Stop Unity
</button>
)}
{appRunning && (
<>
<button
onClick={playScene}
style={{
padding: '6px 12px',
backgroundColor: '#10b981',
color: 'white',
border: 'none',
borderRadius: '4px',
fontSize: '11px',
cursor: 'pointer'
}}
>
โถ๏ธ Play
</button>
<button
onClick={stopScene}
style={{
padding: '6px 12px',
backgroundColor: '#f59e0b',
color: 'white',
border: 'none',
borderRadius: '4px',
fontSize: '11px',
cursor: 'pointer'
}}
>
โธ๏ธ Pause
</button>
<button
onClick={buildProject}
style={{
padding: '6px 12px',
backgroundColor: '#8b5cf6',
color: 'white',
border: 'none',
borderRadius: '4px',
fontSize: '11px',
cursor: 'pointer'
}}
>
๐จ Build
</button>
</>
)}
</div>
</div>
{/* Unity Scene Placeholder */}
<div style={{
height: '350px',
backgroundColor: '#0f172a',
borderRadius: '8px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
border: '2px dashed #475569'
}}>
<div style={{ textAlign: 'center', color: '#94a3b8' }}>
<div style={{ fontSize: '64px', marginBottom: '16px' }}>๐ฎ</div>
<div style={{ fontSize: '18px', fontWeight: '500', marginBottom: '8px' }}>
Unity3D Scene Active
</div>
<div style={{ fontSize: '14px' }}>
{unity.activeScene.objects} objects โข {unity.activeScene.physicsBodies} physics bodies โข {unity.activeScene.lights} lights
</div>
<div style={{ fontSize: '12px', marginTop: '8px', color: '#64748b' }}>
Pipeline: {unity.rendering.pipeline} โข Quality: {unity.rendering.quality}
</div>
</div>
</div>
</div>
{/* Object Hierarchy */}
<div style={{
backgroundColor: '#1e293b',
borderRadius: '12px',
border: '1px solid #334155',
padding: '24px'
}}>
<h3 style={{ fontSize: '18px', fontWeight: '600', color: '#f8fafc', marginBottom: '16px' }}>
๐ Object Hierarchy
</h3>
<div style={{ display: 'flex', flexDirection: 'column', gap: '4px', maxHeight: '200px', overflowY: 'auto' }}>
{[
{ name: 'Main Camera', type: 'Camera', children: 0 },
{ name: 'Directional Light', type: 'Light', children: 0 },
{ name: 'Robots', type: 'Folder', children: 3 },
{ name: ' โโโ Robot_01', type: 'GameObject', children: 2 },
{ name: ' โโโ Robot_02', type: 'GameObject', children: 2 },
{ name: ' โโโ Robot_03', type: 'GameObject', children: 2 },
{ name: 'Sensors', type: 'Folder', children: 4 },
{ name: 'Environment', type: 'Folder', children: 8 }
].map((obj, index) => (
<div
key={index}
onClick={() => setSelectedObject(obj.name)}
style={{
padding: '6px 12px',
backgroundColor: selectedObject === obj.name ? '#3b82f6' : 'transparent',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '12px',
color: '#f8fafc',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
}}
>
<span>{obj.name}</span>
<span style={{ color: '#94a3b8', fontSize: '10px' }}>{obj.type}</span>
</div>
))}
</div>
</div>
</div>
{/* Right Panel - Settings & Console */}
<div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>
{/* Launch Configuration */}
<div style={{
backgroundColor: '#1e293b',
borderRadius: '12px',
border: '1px solid #334155',
padding: '24px',
marginBottom: '24px'
}}>
<h3 style={{ fontSize: '18px', fontWeight: '600', color: '#f8fafc', marginBottom: '16px' }}>
๐ Launch Configuration
</h3>
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
<div>
<label style={{ display: 'block', fontSize: '12px', color: '#94a3b8', marginBottom: '4px' }}>
Project Path (optional)
</label>
<input
type="text"
value={projectPath}
onChange={(e) => setProjectPath(e.target.value)}
placeholder="C:/UnityProjects/MyProject"
style={{
width: '100%',
padding: '8px 12px',
backgroundColor: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#f8fafc',
fontSize: '12px'
}}
/>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }}>
<div>
<label style={{ display: 'block', fontSize: '12px', color: '#94a3b8', marginBottom: '4px' }}>
Desktop
</label>
<select
value={selectedDesktop}
onChange={(e) => setSelectedDesktop(parseInt(e.target.value))}
style={{
width: '100%',
padding: '8px 12px',
backgroundColor: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#f8fafc',
fontSize: '12px'
}}
>
{[1, 2, 3, 4].map(num => (
<option key={num} value={num}>Desktop {num}</option>
))}
</select>
</div>
<div>
<label style={{ display: 'block', fontSize: '12px', color: '#94a3b8', marginBottom: '4px' }}>
Monitor
</label>
<select
value={selectedMonitor}
onChange={(e) => setSelectedMonitor(parseInt(e.target.value))}
style={{
width: '100%',
padding: '8px 12px',
backgroundColor: '#0f172a',
border: '1px solid #334155',
borderRadius: '6px',
color: '#f8fafc',
fontSize: '12px'
}}
>
{[1, 2, 3, 4].map(num => (
<option key={num} value={num}>Monitor {num}</option>
))}
</select>
</div>
</div>
{appRunning && (
<div style={{
padding: '8px 12px',
backgroundColor: '#10b981',
borderRadius: '6px',
fontSize: '12px',
color: 'white',
textAlign: 'center'
}}>
โ
Unity Editor Running (Desktop {selectedDesktop}, Monitor {selectedMonitor})
</div>
)}
</div>
</div>
{/* Project Info */}
<div style={{
backgroundColor: '#1e293b',
borderRadius: '12px',
border: '1px solid #334155',
padding: '24px'
}}>
<h3 style={{ fontSize: '18px', fontWeight: '600', color: '#f8fafc', marginBottom: '16px' }}>
๐ Project Information
</h3>
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ color: '#94a3b8', fontSize: '12px' }}>Project</span>
<span style={{ color: '#f8fafc', fontSize: '12px' }}>{unity.project.name}</span>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ color: '#94a3b8', fontSize: '12px' }}>Scenes</span>
<span style={{ color: '#f8fafc', fontSize: '12px' }}>{unity.project.scenes}</span>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ color: '#94a3b8', fontSize: '12px' }}>Assets</span>
<span style={{ color: '#f8fafc', fontSize: '12px' }}>{unity.project.assets}</span>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ color: '#94a3b8', fontSize: '12px' }}>Platform</span>
<span style={{ color: '#f8fafc', fontSize: '12px' }}>{unity.buildSettings.platform}</span>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ color: '#94a3b8', fontSize: '12px' }}>Build Size</span>
<span style={{ color: '#f8fafc', fontSize: '12px' }}>{unity.buildSettings.buildSize}</span>
</div>
</div>
</div>
{/* Physics Settings */}
<div style={{
backgroundColor: '#1e293b',
borderRadius: '12px',
border: '1px solid #334155',
padding: '24px'
}}>
<h3 style={{ fontSize: '18px', fontWeight: '600', color: '#f8fafc', marginBottom: '16px' }}>
โ๏ธ Physics Settings
</h3>
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ color: '#94a3b8', fontSize: '12px' }}>Gravity</span>
<span style={{ color: '#f8fafc', fontSize: '12px' }}>{unity.physics.gravity} m/sยฒ</span>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ color: '#94a3b8', fontSize: '12px' }}>Fixed Timestep</span>
<span style={{ color: '#f8fafc', fontSize: '12px' }}>{unity.physics.fixedTimestep}s</span>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ color: '#94a3b8', fontSize: '12px' }}>Solver Iterations</span>
<span style={{ color: '#f8fafc', fontSize: '12px' }}>{unity.physics.solverIterations}</span>
</div>
</div>
</div>
{/* Robotics Components */}
<div style={{
backgroundColor: '#1e293b',
borderRadius: '12px',
border: '1px solid #334155',
padding: '24px'
}}>
<h3 style={{ fontSize: '18px', fontWeight: '600', color: '#f8fafc', marginBottom: '16px' }}>
๐ค Robotics Components
</h3>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px', marginBottom: '16px' }}>
<div style={{ textAlign: 'center' }}>
<div style={{ fontSize: '20px', fontWeight: 'bold', color: '#3b82f6' }}>
{unity.roboticsIntegration.robotPrefabs}
</div>
<div style={{ fontSize: '12px', color: '#94a3b8' }}>Robot Prefabs</div>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ fontSize: '20px', fontWeight: 'bold', color: '#10b981' }}>
{unity.roboticsIntegration.sensorComponents}
</div>
<div style={{ fontSize: '12px', color: '#94a3b8' }}>Sensors</div>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ fontSize: '20px', fontWeight: 'bold', color: '#f59e0b' }}>
{unity.roboticsIntegration.controlScripts}
</div>
<div style={{ fontSize: '12px', color: '#94a3b8' }}>Scripts</div>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ fontSize: '20px', fontWeight: 'bold', color: '#8b5cf6' }}>
{unity.roboticsIntegration.physicsMaterials}
</div>
<div style={{ fontSize: '12px', color: '#94a3b8' }}>Materials</div>
</div>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
<button
onClick={() => addRobotComponent('Robot Controller')}
style={{
padding: '8px 16px',
backgroundColor: '#3b82f6',
color: 'white',
border: 'none',
borderRadius: '4px',
fontSize: '12px',
cursor: 'pointer'
}}
>
โ Add Robot
</button>
<button
onClick={() => addRobotComponent('Sensor Array')}
style={{
padding: '8px 16px',
backgroundColor: '#10b981',
color: 'white',
border: 'none',
borderRadius: '4px',
fontSize: '12px',
cursor: 'pointer'
}}
>
๐ก Add Sensors
</button>
</div>
</div>
{/* Console Output */}
<div style={{
backgroundColor: '#1e293b',
borderRadius: '12px',
border: '1px solid #334155',
padding: '24px',
flex: 1
}}>
<h3 style={{ fontSize: '18px', fontWeight: '600', color: '#f8fafc', marginBottom: '16px' }}>
๐ Unity Console
</h3>
<div style={{
backgroundColor: '#0f172a',
borderRadius: '6px',
padding: '12px',
height: '200px',
overflowY: 'auto',
fontFamily: 'monospace',
fontSize: '11px'
}}>
{consoleOutput.slice(-10).map((line, index) => (
<div key={index} style={{
color: line.includes('[Build]') ? '#10b981' :
line.includes('[Unity]') ? '#3b82f6' :
line.includes('Error') ? '#dc2626' : '#94a3b8',
marginBottom: '2px'
}}>
{line}
</div>
))}
</div>
</div>
</div>
</div>
</div>
</div>
)
}