# Studio UI Wiring Guide

**Complete mapping: Godot Editor Features → StudioBridge API → Studio Components**

## 🎯 Goal
Wire Studio UI (TypeScript/React) to have **100% feature parity** with Godot editor using the StudioBridge API.

---

## 📦 Part 1: What Godot Has (C++)

### Core Editor Panels
```
editor/
├── docks/
│   ├── scene_tree_dock.cpp      → Scene hierarchy
│   ├── inspector_dock.cpp       → Property editor
│   ├── filesystem_dock.cpp      → File browser
│   └── node_dock.cpp            → Node info
├── plugins/
│   ├── script_editor_plugin.cpp → Code editor
│   ├── canvas_item_editor_plugin.cpp → 2D viewport
│   └── node_3d_editor_plugin.cpp → 3D viewport
└── editor_node.cpp              → Main window/orchestration
```

---

## 🔌 Part 2: StudioBridge API (What We Already Built)

### ✅ Already Implemented (Basic CRUD)
```cpp
// Scene management
loadScene(path)        → Load .tscn file
saveScene(path)        → Save current scene
getSceneTree()         → Get full hierarchy

// Node operations
createNode(type, parent, name) → Add new node
deleteNode(path)       → Remove node
selectNode(path)       → Set active node

// Properties
setProperty(path, property, value) → Update node property
getProperty(path, property)        → Read property value

// Game control
runGame()              → Launch game instance
stopGame()             → Stop game
```

### ⏳ Need to Add (Advanced Features)

#### Scene Tree Operations
```cpp
// Add to studio_bridge.cpp:
Dictionary move_node(node_path, new_parent_path, position)
Dictionary duplicate_node(node_path)
Dictionary rename_node(node_path, new_name)
Dictionary reparent_node(node_path, new_parent_path)
Dictionary copy_node(node_path)  // to clipboard
Dictionary paste_node(parent_path)  // from clipboard
Dictionary get_node_groups(node_path)
Dictionary add_to_group(node_path, group_name)
```

#### Inspector/Properties
```cpp
Dictionary get_all_properties(node_path)  // Get full property list
Dictionary get_property_info(node_path, property)  // Type, hint, range
Dictionary reset_property(node_path, property)  // Reset to default
Array get_inspectable_nodes()  // Multi-select support
```

#### Resource/Asset Management
```cpp
Dictionary list_directory(path)  // File system browsing
Dictionary import_asset(path, type)
Dictionary create_resource(type, path)
Dictionary load_resource(path)
Array get_recent_files()
```

#### Script Editor
```cpp
Dictionary attach_script(node_path, script_path)
Dictionary detach_script(node_path)
String get_node_script(node_path)
Dictionary save_script(path, content)
Dictionary open_script(path)
```

#### 3D/2D Viewport
```cpp
Dictionary get_viewport_texture()  // Stream 3D view to Studio
Dictionary set_camera_position(x, y, z)
Dictionary set_camera_rotation(x, y, z)
Dictionary toggle_gizmos(enabled)
Dictionary set_grid_visible(visible)
```

---

## 🎨 Part 3: Studio UI Components (TypeScript/React)

### File Structure
```
studio/src/
├── engine/
│   ├── bridge.ts              ← API client (wraps fetch calls)
│   ├── types.ts               ← Node, Property, Scene types
│   └── hooks.ts               ← React hooks (useSceneTree, etc)
├── components/
│   ├── SceneTree/
│   │   ├── SceneTreePanel.tsx    ← Left sidebar hierarchy
│   │   ├── NodeItem.tsx          ← Tree node component
│   │   └── ContextMenu.tsx       ← Right-click menu
│   ├── Inspector/
│   │   ├── InspectorPanel.tsx    ← Right sidebar properties
│   │   ├── PropertyEditor.tsx    ← Individual property input
│   │   └── ResourcePicker.tsx    ← Resource selection
│   ├── Viewport/
│   │   ├── Viewport2D.tsx        ← 2D scene view
│   │   ├── Viewport3D.tsx        ← 3D scene view (WebGL/Three.js)
│   │   └── ViewportControls.tsx  ← Camera controls
│   ├── FileSystem/
│   │   ├── FileSystemPanel.tsx   ← Bottom file browser
│   │   └── AssetPreview.tsx      ← Preview images/models
│   ├── ScriptEditor/
│   │   ├── CodeEditor.tsx        ← Monaco editor wrapper
│   │   └── ScriptTabs.tsx        ← Open script tabs
│   └── Toolbar/
│       ├── MainToolbar.tsx       ← Top toolbar (Play, Stop, etc)
│       └── NodeToolbar.tsx       ← Node-specific tools
└── layouts/
    └── EditorLayout.tsx          ← Main layout orchestration
```

---

## 🔧 Implementation Roadmap

### Phase 1: Extend StudioBridge API (Engine Side)

**File:** `engine/modules/studio_bridge/studio_bridge.h`

Add these method declarations:
```cpp
// Advanced node operations
Dictionary move_node(const Dictionary &p_params);
Dictionary duplicate_node(const Dictionary &p_params);
Dictionary rename_node(const Dictionary &p_params);

// Advanced properties
Dictionary get_all_properties(const Dictionary &p_params);
Dictionary get_property_info(const Dictionary &p_params);

// File system
Dictionary list_directory(const Dictionary &p_params);
Dictionary get_recent_files(const Dictionary &p_params);

// Scripts
Dictionary attach_script(const Dictionary &p_params);
Dictionary get_node_script(const Dictionary &p_params);

// Viewport streaming
Dictionary get_viewport_texture(const Dictionary &p_params);
Dictionary set_camera_transform(const Dictionary &p_params);
```

**File:** `engine/modules/studio_bridge/studio_bridge.cpp`

Implement these methods (similar to existing `_handle_create_node`, etc.)

---

### Phase 2: Build Studio Bridge Client (Studio Side)

**File:** `studio/src/engine/bridge.ts`

```typescript
export class EngineBridge {
  private baseUrl = 'http://localhost:6007';
  private ws: WebSocket | null = null;
  
  // Basic API calls
  async call(method: string, params: any = {}) {
    const response = await fetch(`${this.baseUrl}/rpc`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ method, params })
    });
    return response.json();
  }
  
  // Scene Tree
  async loadScene(path: string) {
    return this.call('loadScene', { path });
  }
  
  async getSceneTree() {
    return this.call('getSceneTree', {});
  }
  
  async createNode(type: string, parent: string, name: string) {
    return this.call('createNode', { type, parent, name });
  }
  
  async deleteNode(path: string) {
    return this.call('deleteNode', { path });
  }
  
  async moveNode(path: string, newParent: string, position: number) {
    return this.call('moveNode', { path, newParent, position });
  }
  
  async duplicateNode(path: string) {
    return this.call('duplicateNode', { path });
  }
  
  // Properties
  async getAllProperties(path: string) {
    return this.call('getAllProperties', { path });
  }
  
  async setProperty(path: string, property: string, value: any) {
    return this.call('setProperty', { path, property, value });
  }
  
  async getProperty(path: string, property: string) {
    return this.call('getProperty', { path, property });
  }
  
  // File System
  async listDirectory(path: string) {
    return this.call('listDirectory', { path });
  }
  
  // Scripts
  async attachScript(nodePath: string, scriptPath: string) {
    return this.call('attachScript', { nodePath, scriptPath });
  }
  
  // Game Control
  async runGame() {
    return this.call('runGame', {});
  }
  
  async stopGame() {
    return this.call('stopGame', {});
  }
  
  // WebSocket Events
  connectEvents(callbacks: {
    onSceneChanged?: () => void;
    onNodeSelected?: (node: any) => void;
    onPropertyChanged?: (path: string, property: string) => void;
    onConsoleOutput?: (message: string, type: string) => void;
  }) {
    this.ws = new WebSocket('ws://localhost:6007/events');
    
    this.ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
      
      if (data.event === 'scene_changed' && callbacks.onSceneChanged) {
        callbacks.onSceneChanged();
      } else if (data.event === 'node_selected' && callbacks.onNodeSelected) {
        callbacks.onNodeSelected(data.node);
      } else if (data.event === 'property_changed' && callbacks.onPropertyChanged) {
        callbacks.onPropertyChanged(data.path, data.property);
      } else if (data.event === 'console_output' && callbacks.onConsoleOutput) {
        callbacks.onConsoleOutput(data.message, data.type);
      }
    };
  }
}

// Singleton instance
export const bridge = new EngineBridge();
```

---

### Phase 3: Build React Components (Studio Side)

**File:** `studio/src/components/SceneTree/SceneTreePanel.tsx`

```tsx
import { useState, useEffect } from 'react';
import { bridge } from '@/engine/bridge';

interface Node {
  name: string;
  type: string;
  path: string;
  children: Node[];
}

export function SceneTreePanel() {
  const [tree, setTree] = useState<Node | null>(null);
  const [selectedPath, setSelectedPath] = useState<string>('');
  
  useEffect(() => {
    // Load initial scene tree
    loadTree();
    
    // Listen for changes
    bridge.connectEvents({
      onSceneChanged: loadTree,
      onNodeSelected: (node) => setSelectedPath(node.path)
    });
  }, []);
  
  async function loadTree() {
    const result = await bridge.getSceneTree();
    if (result.success) {
      setTree(result.result);
    }
  }
  
  async function handleCreateNode(type: string, parentPath: string) {
    await bridge.createNode(type, parentPath, `New${type}`);
    loadTree();
  }
  
  async function handleDeleteNode(path: string) {
    await bridge.deleteNode(path);
    loadTree();
  }
  
  async function handleSelectNode(path: string) {
    await bridge.call('selectNode', { path });
    setSelectedPath(path);
  }
  
  return (
    <div className="scene-tree-panel">
      <div className="toolbar">
        <button onClick={() => handleCreateNode('Node2D', selectedPath)}>
          + Add Node
        </button>
        <button onClick={() => handleDeleteNode(selectedPath)}>
          Delete
        </button>
      </div>
      
      {tree && (
        <NodeTree 
          node={tree} 
          selectedPath={selectedPath}
          onSelect={handleSelectNode}
        />
      )}
    </div>
  );
}

function NodeTree({ node, selectedPath, onSelect }: {
  node: Node;
  selectedPath: string;
  onSelect: (path: string) => void;
}) {
  const [expanded, setExpanded] = useState(true);
  
  return (
    <div className="node-item">
      <div 
        className={`node-header ${node.path === selectedPath ? 'selected' : ''}`}
        onClick={() => onSelect(node.path)}
      >
        <span onClick={() => setExpanded(!expanded)}>
          {node.children.length > 0 ? (expanded ? '▼' : '▶') : '  '}
        </span>
        <span className="node-icon">{getIconForType(node.type)}</span>
        <span className="node-name">{node.name}</span>
        <span className="node-type">{node.type}</span>
      </div>
      
      {expanded && node.children.length > 0 && (
        <div className="node-children">
          {node.children.map((child) => (
            <NodeTree 
              key={child.path}
              node={child}
              selectedPath={selectedPath}
              onSelect={onSelect}
            />
          ))}
        </div>
      )}
    </div>
  );
}

function getIconForType(type: string): string {
  // Return icon based on node type
  const icons: Record<string, string> = {
    'Node2D': '🎯',
    'Sprite2D': '🖼️',
    'Camera2D': '📷',
    'CharacterBody2D': '🏃',
    'Node3D': '📦',
    'MeshInstance3D': '🎲',
    // ... add more
  };
  return icons[type] || '⚫';
}
```

---

**File:** `studio/src/components/Inspector/InspectorPanel.tsx`

```tsx
import { useState, useEffect } from 'react';
import { bridge } from '@/engine/bridge';

export function InspectorPanel({ selectedNodePath }: { selectedNodePath: string }) {
  const [properties, setProperties] = useState<any[]>([]);
  
  useEffect(() => {
    if (selectedNodePath) {
      loadProperties();
    }
  }, [selectedNodePath]);
  
  async function loadProperties() {
    const result = await bridge.getAllProperties(selectedNodePath);
    if (result.success) {
      setProperties(result.result);
    }
  }
  
  async function handlePropertyChange(property: string, value: any) {
    await bridge.setProperty(selectedNodePath, property, value);
  }
  
  if (!selectedNodePath) {
    return <div className="inspector-empty">No node selected</div>;
  }
  
  return (
    <div className="inspector-panel">
      <h3>Inspector</h3>
      <div className="property-list">
        {properties.map((prop) => (
          <PropertyEditor
            key={prop.name}
            property={prop}
            onChange={(value) => handlePropertyChange(prop.name, value)}
          />
        ))}
      </div>
    </div>
  );
}

function PropertyEditor({ property, onChange }: any) {
  // Render different input types based on property type
  if (property.type === 'Vector2') {
    return (
      <div className="property-vector2">
        <label>{property.name}</label>
        <input 
          type="number" 
          value={property.value.x}
          onChange={(e) => onChange({ ...property.value, x: +e.target.value })}
        />
        <input 
          type="number" 
          value={property.value.y}
          onChange={(e) => onChange({ ...property.value, y: +e.target.value })}
        />
      </div>
    );
  }
  
  if (property.type === 'bool') {
    return (
      <div className="property-bool">
        <label>{property.name}</label>
        <input 
          type="checkbox"
          checked={property.value}
          onChange={(e) => onChange(e.target.checked)}
        />
      </div>
    );
  }
  
  // Default: text input
  return (
    <div className="property-default">
      <label>{property.name}</label>
      <input 
        type="text"
        value={property.value}
        onChange={(e) => onChange(e.target.value)}
      />
    </div>
  );
}
```

---

## 📊 Feature Checklist

### ✅ Core (Already Built via StudioBridge)
- [x] Load/save scenes
- [x] Create/delete nodes
- [x] Get/set properties
- [x] Scene tree hierarchy

### ⏳ Advanced (Need to Add)
- [ ] Move/reparent nodes
- [ ] Duplicate nodes
- [ ] Copy/paste nodes
- [ ] Undo/redo system
- [ ] Multi-node selection
- [ ] Node groups
- [ ] Script attachment
- [ ] Resource management
- [ ] Asset import
- [ ] 2D/3D viewport rendering
- [ ] Camera controls
- [ ] Gizmos (transform handles)
- [ ] Debugger integration
- [ ] Profiler data
- [ ] Remote scene tree (running game)

---

## 🚀 Next Steps

1. **Extend StudioBridge API** - Add 20+ new RPC methods for advanced features
2. **Implement HTTP Server** - Make the bridge actually accept network requests
3. **Build React Components** - Create SceneTree, Inspector, Viewport panels
4. **Add WebSocket Events** - Real-time updates Engine → Studio
5. **Integrate Monaco Editor** - For script editing
6. **Viewport Streaming** - Show 3D scene in Studio UI

**Estimated Time:** 4-6 weeks for full feature parity

Want me to start implementing the extended API methods?
