1255 lines
41 KiB
Python
1255 lines
41 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
Nexus Architect Tool Module
|
||
|
|
|
||
|
|
This module provides autonomous 3D world generation capabilities for the Three.js Nexus.
|
||
|
|
It enables Timmy to design and build rooms, portals, lighting, and architectural features
|
||
|
|
through LLM-generated Three.js code that is validated for safety before execution.
|
||
|
|
|
||
|
|
Available tools:
|
||
|
|
- nexus_design_room: Design a new room with specified theme, dimensions, and features
|
||
|
|
- nexus_create_portal: Create portals connecting rooms with visual effects
|
||
|
|
- nexus_add_lighting: Add lighting systems (ambient, point, directional, spot)
|
||
|
|
- nexus_add_architecture: Add architectural elements (walls, floors, ceilings, decor)
|
||
|
|
- nexus_validate_scene: Validate and lint generated Three.js code
|
||
|
|
- nexus_export_scene: Export the current scene to JSON or JS format
|
||
|
|
|
||
|
|
Features:
|
||
|
|
- LLM-powered Three.js code generation with structured prompts
|
||
|
|
- Code safety validation (syntax check, sandboxing, dangerous API detection)
|
||
|
|
- Scene graph management and serialization
|
||
|
|
- Portal network management for room connectivity
|
||
|
|
- Lighting system design with energy/consistency checks
|
||
|
|
- Architecture component library integration
|
||
|
|
|
||
|
|
Usage:
|
||
|
|
from nexus_architect import nexus_design_room, nexus_validate_scene
|
||
|
|
|
||
|
|
# Design a meditation chamber
|
||
|
|
result = await nexus_design_room(
|
||
|
|
name="Zen Garden",
|
||
|
|
theme="meditation",
|
||
|
|
dimensions={"width": 20, "height": 10, "depth": 20},
|
||
|
|
features=["water_feature", "floating_lanterns", "bamboo_grove"]
|
||
|
|
)
|
||
|
|
|
||
|
|
# Validate the generated code
|
||
|
|
validation = await nexus_validate_scene(generated_code)
|
||
|
|
"""
|
||
|
|
|
||
|
|
import json
|
||
|
|
import logging
|
||
|
|
import re
|
||
|
|
import ast
|
||
|
|
from typing import Dict, Any, List, Optional, Union, Tuple
|
||
|
|
from dataclasses import dataclass, field
|
||
|
|
from enum import Enum
|
||
|
|
|
||
|
|
logger = logging.getLogger(__name__)
|
||
|
|
|
||
|
|
|
||
|
|
# =============================================================================
|
||
|
|
# Configuration & Constants
|
||
|
|
# =============================================================================
|
||
|
|
|
||
|
|
class RoomTheme(Enum):
|
||
|
|
"""Predefined room themes with associated assets and lighting profiles."""
|
||
|
|
MEDITATION = "meditation"
|
||
|
|
TECH_LAB = "tech_lab"
|
||
|
|
NATURE = "nature"
|
||
|
|
CRYSTAL_CAVE = "crystal_cave"
|
||
|
|
LIBRARY = "library"
|
||
|
|
VOID = "void"
|
||
|
|
CUSTOM = "custom"
|
||
|
|
|
||
|
|
|
||
|
|
class LightType(Enum):
|
||
|
|
"""Supported Three.js light types."""
|
||
|
|
AMBIENT = "ambient"
|
||
|
|
DIRECTIONAL = "directional"
|
||
|
|
POINT = "point"
|
||
|
|
SPOT = "spot"
|
||
|
|
HEMISPHERE = "hemisphere"
|
||
|
|
RECT_AREA = "rect_area"
|
||
|
|
|
||
|
|
|
||
|
|
class PortalStyle(Enum):
|
||
|
|
"""Visual styles for portal connections."""
|
||
|
|
CIRCULAR = "circular"
|
||
|
|
RECTANGULAR = "rectangular"
|
||
|
|
STARGATE = "stargate"
|
||
|
|
DISSOLVE = "dissolve"
|
||
|
|
GLITCH = "glitch"
|
||
|
|
|
||
|
|
|
||
|
|
# Safety configuration - banned APIs and patterns
|
||
|
|
BANNED_JS_PATTERNS = [
|
||
|
|
r"eval\s*\(",
|
||
|
|
r"Function\s*\(",
|
||
|
|
r"setTimeout\s*\(\s*['\"]",
|
||
|
|
r"setInterval\s*\(\s*['\"]",
|
||
|
|
r"document\.write",
|
||
|
|
r"window\.location",
|
||
|
|
r"window\.open",
|
||
|
|
r"XMLHttpRequest",
|
||
|
|
r"fetch\s*\(", # Network requests
|
||
|
|
r"WebSocket",
|
||
|
|
r"localStorage",
|
||
|
|
r"sessionStorage",
|
||
|
|
r"indexedDB",
|
||
|
|
r"navigator",
|
||
|
|
r"document\.cookie",
|
||
|
|
r"import\s*\(", # Dynamic imports
|
||
|
|
r"require\s*\(", # Node-style requires
|
||
|
|
]
|
||
|
|
|
||
|
|
ALLOWED_THREE_APIS = {
|
||
|
|
"THREE.Scene",
|
||
|
|
"THREE.PerspectiveCamera",
|
||
|
|
"THREE.WebGLRenderer",
|
||
|
|
"THREE.BoxGeometry",
|
||
|
|
"THREE.SphereGeometry",
|
||
|
|
"THREE.PlaneGeometry",
|
||
|
|
"THREE.CylinderGeometry",
|
||
|
|
"THREE.ConeGeometry",
|
||
|
|
"THREE.TorusGeometry",
|
||
|
|
"THREE.CircleGeometry",
|
||
|
|
"THREE.RingGeometry",
|
||
|
|
"THREE.Mesh",
|
||
|
|
"THREE.MeshBasicMaterial",
|
||
|
|
"THREE.MeshStandardMaterial",
|
||
|
|
"THREE.MeshPhongMaterial",
|
||
|
|
"THREE.MeshLambertMaterial",
|
||
|
|
"THREE.MeshPhysicalMaterial",
|
||
|
|
"THREE.Texture",
|
||
|
|
"THREE.TextureLoader",
|
||
|
|
"THREE.Color",
|
||
|
|
"THREE.Vector3",
|
||
|
|
"THREE.Euler",
|
||
|
|
"THREE.Quaternion",
|
||
|
|
"THREE.Matrix4",
|
||
|
|
"THREE.Group",
|
||
|
|
"THREE.Object3D",
|
||
|
|
"THREE.AmbientLight",
|
||
|
|
"THREE.DirectionalLight",
|
||
|
|
"THREE.PointLight",
|
||
|
|
"THREE.SpotLight",
|
||
|
|
"THREE.HemisphereLight",
|
||
|
|
"THREE.Fog",
|
||
|
|
"THREE.FogExp2",
|
||
|
|
"THREE.Raycaster",
|
||
|
|
"THREE.Clock",
|
||
|
|
"THREE.AnimationMixer",
|
||
|
|
"THREE.AnimationClip",
|
||
|
|
"THREE.AnimationAction",
|
||
|
|
"THREE.BufferGeometry",
|
||
|
|
"THREE.BufferAttribute",
|
||
|
|
"THREE.Float32BufferAttribute",
|
||
|
|
"THREE.Points",
|
||
|
|
"THREE.PointsMaterial",
|
||
|
|
"THREE.Sprite",
|
||
|
|
"THREE.SpriteMaterial",
|
||
|
|
"THREE.CanvasTexture",
|
||
|
|
"THREE.OrthographicCamera",
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
# =============================================================================
|
||
|
|
# Data Models
|
||
|
|
# =============================================================================
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class RoomConfig:
|
||
|
|
"""Configuration for a Nexus room."""
|
||
|
|
name: str
|
||
|
|
theme: RoomTheme
|
||
|
|
dimensions: Dict[str, float] = field(default_factory=lambda: {"width": 10, "height": 5, "depth": 10})
|
||
|
|
features: List[str] = field(default_factory=list)
|
||
|
|
lighting_profile: str = "default"
|
||
|
|
ambient_audio: Optional[str] = None
|
||
|
|
skybox: Optional[str] = None
|
||
|
|
fog_enabled: bool = False
|
||
|
|
fog_color: str = "#000000"
|
||
|
|
fog_density: float = 0.02
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class PortalConfig:
|
||
|
|
"""Configuration for a Nexus portal."""
|
||
|
|
name: str
|
||
|
|
source_room: str
|
||
|
|
target_room: str
|
||
|
|
position: Dict[str, float] = field(default_factory=lambda: {"x": 0, "y": 0, "z": 0})
|
||
|
|
rotation: Dict[str, float] = field(default_factory=lambda: {"x": 0, "y": 0, "z": 0})
|
||
|
|
scale: Dict[str, float] = field(default_factory=lambda: {"x": 1, "y": 1, "z": 1})
|
||
|
|
style: PortalStyle = PortalStyle.CIRCULAR
|
||
|
|
color: str = "#00ffff"
|
||
|
|
particle_effect: Optional[str] = None
|
||
|
|
sound_effect: Optional[str] = None
|
||
|
|
one_way: bool = False
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class LightConfig:
|
||
|
|
"""Configuration for a Nexus lighting element."""
|
||
|
|
name: str
|
||
|
|
type: LightType
|
||
|
|
position: Dict[str, float] = field(default_factory=lambda: {"x": 0, "y": 5, "z": 0})
|
||
|
|
color: str = "#ffffff"
|
||
|
|
intensity: float = 1.0
|
||
|
|
distance: Optional[float] = None
|
||
|
|
decay: Optional[float] = None
|
||
|
|
angle: Optional[float] = None # For spot lights
|
||
|
|
penumbra: Optional[float] = None # For spot lights
|
||
|
|
cast_shadow: bool = True
|
||
|
|
target: Optional[Dict[str, float]] = None
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class ArchitectureConfig:
|
||
|
|
"""Configuration for architectural elements."""
|
||
|
|
name: str
|
||
|
|
element_type: str # wall, floor, ceiling, pillar, arch, etc.
|
||
|
|
geometry: str = "box"
|
||
|
|
dimensions: Dict[str, float] = field(default_factory=lambda: {"width": 1, "height": 1, "depth": 1})
|
||
|
|
position: Dict[str, float] = field(default_factory=lambda: {"x": 0, "y": 0, "z": 0})
|
||
|
|
rotation: Dict[str, float] = field(default_factory=lambda: {"x": 0, "y": 0, "z": 0})
|
||
|
|
material: str = "standard"
|
||
|
|
color: str = "#888888"
|
||
|
|
texture: Optional[str] = None
|
||
|
|
roughness: float = 0.5
|
||
|
|
metalness: float = 0.0
|
||
|
|
emissive: Optional[str] = None
|
||
|
|
emissive_intensity: float = 0.0
|
||
|
|
transparent: bool = False
|
||
|
|
opacity: float = 1.0
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class SceneGraph:
|
||
|
|
"""Represents the complete Nexus scene graph."""
|
||
|
|
version: str = "1.0.0"
|
||
|
|
rooms: Dict[str, RoomConfig] = field(default_factory=dict)
|
||
|
|
portals: Dict[str, PortalConfig] = field(default_factory=dict)
|
||
|
|
lights: Dict[str, LightConfig] = field(default_factory=dict)
|
||
|
|
architecture: Dict[str, ArchitectureConfig] = field(default_factory=dict)
|
||
|
|
global_settings: Dict[str, Any] = field(default_factory=dict)
|
||
|
|
|
||
|
|
def to_dict(self) -> Dict[str, Any]:
|
||
|
|
"""Serialize scene graph to dictionary."""
|
||
|
|
return {
|
||
|
|
"version": self.version,
|
||
|
|
"rooms": {k: self._room_to_dict(v) for k, v in self.rooms.items()},
|
||
|
|
"portals": {k: self._portal_to_dict(v) for k, v in self.portals.items()},
|
||
|
|
"lights": {k: self._light_to_dict(v) for k, v in self.lights.items()},
|
||
|
|
"architecture": {k: self._arch_to_dict(v) for k, v in self.architecture.items()},
|
||
|
|
"global_settings": self.global_settings,
|
||
|
|
}
|
||
|
|
|
||
|
|
@staticmethod
|
||
|
|
def _room_to_dict(room: RoomConfig) -> Dict[str, Any]:
|
||
|
|
return {
|
||
|
|
"name": room.name,
|
||
|
|
"theme": room.theme.value,
|
||
|
|
"dimensions": room.dimensions,
|
||
|
|
"features": room.features,
|
||
|
|
"lighting_profile": room.lighting_profile,
|
||
|
|
"ambient_audio": room.ambient_audio,
|
||
|
|
"skybox": room.skybox,
|
||
|
|
"fog_enabled": room.fog_enabled,
|
||
|
|
"fog_color": room.fog_color,
|
||
|
|
"fog_density": room.fog_density,
|
||
|
|
}
|
||
|
|
|
||
|
|
@staticmethod
|
||
|
|
def _portal_to_dict(portal: PortalConfig) -> Dict[str, Any]:
|
||
|
|
return {
|
||
|
|
"name": portal.name,
|
||
|
|
"source_room": portal.source_room,
|
||
|
|
"target_room": portal.target_room,
|
||
|
|
"position": portal.position,
|
||
|
|
"rotation": portal.rotation,
|
||
|
|
"scale": portal.scale,
|
||
|
|
"style": portal.style.value,
|
||
|
|
"color": portal.color,
|
||
|
|
"particle_effect": portal.particle_effect,
|
||
|
|
"sound_effect": portal.sound_effect,
|
||
|
|
"one_way": portal.one_way,
|
||
|
|
}
|
||
|
|
|
||
|
|
@staticmethod
|
||
|
|
def _light_to_dict(light: LightConfig) -> Dict[str, Any]:
|
||
|
|
return {
|
||
|
|
"name": light.name,
|
||
|
|
"type": light.type.value,
|
||
|
|
"position": light.position,
|
||
|
|
"color": light.color,
|
||
|
|
"intensity": light.intensity,
|
||
|
|
"distance": light.distance,
|
||
|
|
"decay": light.decay,
|
||
|
|
"angle": light.angle,
|
||
|
|
"penumbra": light.penumbra,
|
||
|
|
"cast_shadow": light.cast_shadow,
|
||
|
|
"target": light.target,
|
||
|
|
}
|
||
|
|
|
||
|
|
@staticmethod
|
||
|
|
def _arch_to_dict(arch: ArchitectureConfig) -> Dict[str, Any]:
|
||
|
|
return {
|
||
|
|
"name": arch.name,
|
||
|
|
"element_type": arch.element_type,
|
||
|
|
"geometry": arch.geometry,
|
||
|
|
"dimensions": arch.dimensions,
|
||
|
|
"position": arch.position,
|
||
|
|
"rotation": arch.rotation,
|
||
|
|
"material": arch.material,
|
||
|
|
"color": arch.color,
|
||
|
|
"texture": arch.texture,
|
||
|
|
"roughness": arch.roughness,
|
||
|
|
"metalness": arch.metalness,
|
||
|
|
"emissive": arch.emissive,
|
||
|
|
"emissive_intensity": arch.emissive_intensity,
|
||
|
|
"transparent": arch.transparent,
|
||
|
|
"opacity": arch.opacity,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
# =============================================================================
|
||
|
|
# Validation & Safety
|
||
|
|
# =============================================================================
|
||
|
|
|
||
|
|
class CodeValidationResult:
|
||
|
|
"""Result of code validation."""
|
||
|
|
def __init__(self, is_valid: bool, errors: List[str] = None, warnings: List[str] = None):
|
||
|
|
self.is_valid = is_valid
|
||
|
|
self.errors = errors or []
|
||
|
|
self.warnings = warnings or []
|
||
|
|
|
||
|
|
def to_dict(self) -> Dict[str, Any]:
|
||
|
|
return {
|
||
|
|
"is_valid": self.is_valid,
|
||
|
|
"errors": self.errors,
|
||
|
|
"warnings": self.warnings,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def validate_three_js_code(code: str, strict_mode: bool = False) -> CodeValidationResult:
|
||
|
|
"""
|
||
|
|
Validate generated Three.js code for syntax and safety.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
code: The JavaScript/Three.js code to validate
|
||
|
|
strict_mode: If True, additional restrictions apply
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
CodeValidationResult with validation status and any issues
|
||
|
|
"""
|
||
|
|
errors = []
|
||
|
|
warnings = []
|
||
|
|
|
||
|
|
# Check for banned patterns
|
||
|
|
for pattern in BANNED_JS_PATTERNS:
|
||
|
|
if re.search(pattern, code, re.IGNORECASE):
|
||
|
|
errors.append(f"Security violation: Banned pattern detected: {pattern}")
|
||
|
|
|
||
|
|
# Basic syntax validation (check for balanced braces)
|
||
|
|
open_braces = code.count("{")
|
||
|
|
close_braces = code.count("}")
|
||
|
|
if open_braces != close_braces:
|
||
|
|
errors.append(f"Syntax error: Mismatched braces ({open_braces} open, {close_braces} close)")
|
||
|
|
|
||
|
|
open_parens = code.count("(")
|
||
|
|
close_parens = code.count(")")
|
||
|
|
if open_parens != close_parens:
|
||
|
|
errors.append(f"Syntax error: Mismatched parentheses ({open_parens} open, {close_parens} close)")
|
||
|
|
|
||
|
|
# Check for potentially dangerous Three.js operations
|
||
|
|
if "new Function" in code:
|
||
|
|
errors.append("Security violation: Dynamic function creation is not allowed")
|
||
|
|
|
||
|
|
if "constructor" in code and "prototype" in code:
|
||
|
|
warnings.append("Potential prototype manipulation detected")
|
||
|
|
|
||
|
|
# Check for required Three.js patterns (if strict)
|
||
|
|
if strict_mode:
|
||
|
|
if "THREE." not in code:
|
||
|
|
warnings.append("No THREE namespace usage detected")
|
||
|
|
|
||
|
|
# Check for scene creation
|
||
|
|
if "new THREE.Scene()" not in code:
|
||
|
|
warnings.append("Scene object not explicitly created")
|
||
|
|
|
||
|
|
# Validate import statements if present
|
||
|
|
import_pattern = r'import\s+.*?\s+from\s+[\'"]([^\'"]+)[\'"]'
|
||
|
|
imports = re.findall(import_pattern, code)
|
||
|
|
for imp in imports:
|
||
|
|
if not imp.endswith('.js') and not imp.startswith('three'):
|
||
|
|
warnings.append(f"Non-standard import: {imp}")
|
||
|
|
|
||
|
|
is_valid = len(errors) == 0
|
||
|
|
return CodeValidationResult(is_valid, errors, warnings)
|
||
|
|
|
||
|
|
|
||
|
|
def sanitize_three_js_code(code: str) -> str:
|
||
|
|
"""
|
||
|
|
Sanitize Three.js code by removing potentially dangerous elements.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
code: The code to sanitize
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Sanitized code
|
||
|
|
"""
|
||
|
|
# Remove comments that might contain malicious code
|
||
|
|
code = re.sub(r'/\*.*?\*/', '', code, flags=re.DOTALL)
|
||
|
|
code = re.sub(r'//.*?$', '', code, flags=re.MULTILINE)
|
||
|
|
|
||
|
|
# Remove debugger statements
|
||
|
|
code = re.sub(r'\bdebugger\b;', '', code)
|
||
|
|
|
||
|
|
# Remove console methods (keep console.log for debugging but remove others)
|
||
|
|
code = re.sub(r'console\.(warn|error|info|debug|table|trace)\s*\([^)]*\);?', '', code)
|
||
|
|
|
||
|
|
return code.strip()
|
||
|
|
|
||
|
|
|
||
|
|
# =============================================================================
|
||
|
|
# LLM Prompt Generation
|
||
|
|
# =============================================================================
|
||
|
|
|
||
|
|
def generate_room_design_prompt(config: RoomConfig, mental_state: Optional[Dict] = None) -> str:
|
||
|
|
"""
|
||
|
|
Generate a structured prompt for the LLM to design a room.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
config: Room configuration
|
||
|
|
mental_state: Optional mental state/context for design decisions
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Formatted prompt string
|
||
|
|
"""
|
||
|
|
mental_context = ""
|
||
|
|
if mental_state:
|
||
|
|
mood = mental_state.get("mood", "neutral")
|
||
|
|
energy = mental_state.get("energy", 0.5)
|
||
|
|
focus = mental_state.get("focus", "general")
|
||
|
|
mental_context = f"""
|
||
|
|
Design Context:
|
||
|
|
- Current Mood: {mood}
|
||
|
|
- Energy Level: {energy:.1f}/1.0
|
||
|
|
- Focus Area: {focus}
|
||
|
|
"""
|
||
|
|
|
||
|
|
prompt = f"""You are an expert Three.js developer and 3D environment designer for the "Nexus" - a virtual metaverse space.
|
||
|
|
|
||
|
|
Design a room with the following specifications:
|
||
|
|
|
||
|
|
Room Name: {config.name}
|
||
|
|
Theme: {config.theme.value}
|
||
|
|
Dimensions: {config.dimensions['width']}w x {config.dimensions['height']}h x {config.dimensions['depth']}d
|
||
|
|
Features: {', '.join(config.features) if config.features else 'None specified'}
|
||
|
|
{mental_context}
|
||
|
|
|
||
|
|
Generate Three.js code that creates this room. Follow these guidelines:
|
||
|
|
|
||
|
|
1. STRUCTURE:
|
||
|
|
- Create a complete, self-contained function called `createRoom()`
|
||
|
|
- Return a THREE.Group containing all room elements
|
||
|
|
- Include proper disposal methods for memory management
|
||
|
|
|
||
|
|
2. GEOMETRY:
|
||
|
|
- Use appropriate geometries for the theme (BoxGeometry for walls, PlaneGeometry for floors, etc.)
|
||
|
|
- Optimize by reusing geometries where possible
|
||
|
|
- Keep polygon count reasonable (< 10,000 triangles per room)
|
||
|
|
|
||
|
|
3. MATERIALS:
|
||
|
|
- Use MeshStandardMaterial for PBR lighting
|
||
|
|
- Set appropriate roughness/metalness values
|
||
|
|
- Include emissive materials for glowing elements
|
||
|
|
|
||
|
|
4. LIGHTING:
|
||
|
|
- Include ambient light (0.3 intensity base)
|
||
|
|
- Add theme-appropriate accent lights
|
||
|
|
- Use shadows sparingly for performance
|
||
|
|
|
||
|
|
5. SAFETY:
|
||
|
|
- Only use allowed Three.js APIs
|
||
|
|
- No eval, Function, or dynamic code execution
|
||
|
|
- No network requests or external dependencies
|
||
|
|
|
||
|
|
Return ONLY the JavaScript code, wrapped in a markdown code block:
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// Your code here
|
||
|
|
```
|
||
|
|
"""
|
||
|
|
return prompt
|
||
|
|
|
||
|
|
|
||
|
|
def generate_portal_prompt(config: PortalConfig, source_room_config: Optional[RoomConfig] = None) -> str:
|
||
|
|
"""Generate a prompt for creating a portal."""
|
||
|
|
room_context = ""
|
||
|
|
if source_room_config:
|
||
|
|
room_context = f"""
|
||
|
|
Source Room Context:
|
||
|
|
- Name: {source_room_config.name}
|
||
|
|
- Theme: {source_room_config.theme.value}
|
||
|
|
- This portal should match the room's aesthetic
|
||
|
|
"""
|
||
|
|
|
||
|
|
prompt = f"""You are a Three.js developer creating a portal for the Nexus.
|
||
|
|
|
||
|
|
Portal Specifications:
|
||
|
|
- Name: {config.name}
|
||
|
|
- Connects: {config.source_room} -> {config.target_room}
|
||
|
|
- Position: ({config.position['x']}, {config.position['y']}, {config.position['z']})
|
||
|
|
- Style: {config.style.value}
|
||
|
|
- Color: {config.color}
|
||
|
|
{room_context}
|
||
|
|
|
||
|
|
Generate Three.js code that creates this portal. The portal should:
|
||
|
|
|
||
|
|
1. Have an animated visual effect (shader or texture-based)
|
||
|
|
2. Include a collider/trigger zone for teleportation
|
||
|
|
3. Emit appropriate particle effects
|
||
|
|
4. Match the specified style ({config.style.value})
|
||
|
|
5. Include a sound trigger point (audio implementation placeholder)
|
||
|
|
|
||
|
|
Return ONLY the JavaScript code in a markdown code block:
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
function createPortal() {{
|
||
|
|
// Your portal code here
|
||
|
|
return portalGroup;
|
||
|
|
}}
|
||
|
|
```
|
||
|
|
"""
|
||
|
|
return prompt
|
||
|
|
|
||
|
|
|
||
|
|
def generate_lighting_prompt(lights: List[LightConfig], room_name: str) -> str:
|
||
|
|
"""Generate a prompt for designing a lighting system."""
|
||
|
|
light_specs = "\n".join([
|
||
|
|
f"- {light.name}: {light.type.value} at ({light.position['x']}, {light.position['y']}, {light.position['z']})"
|
||
|
|
for light in lights
|
||
|
|
])
|
||
|
|
|
||
|
|
prompt = f"""You are a lighting designer for the Nexus 3D environment.
|
||
|
|
|
||
|
|
Design a lighting system for room: {room_name}
|
||
|
|
|
||
|
|
Light Specifications:
|
||
|
|
{light_specs}
|
||
|
|
|
||
|
|
Generate Three.js code that:
|
||
|
|
1. Creates all specified lights with correct types
|
||
|
|
2. Sets up shadow mapping if cast_shadow is true
|
||
|
|
3. Includes light helpers for debugging (commented out by default)
|
||
|
|
4. Implements a day/night cycle system (optional toggle)
|
||
|
|
5. Optimizes for performance (shadow map sizes reasonable)
|
||
|
|
|
||
|
|
Return ONLY the JavaScript code in a markdown code block:
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
function setupLighting() {{
|
||
|
|
const lights = {{}};
|
||
|
|
// Your lighting code here
|
||
|
|
return lights;
|
||
|
|
}}
|
||
|
|
```
|
||
|
|
"""
|
||
|
|
return prompt
|
||
|
|
|
||
|
|
|
||
|
|
# =============================================================================
|
||
|
|
# Core Tool Functions
|
||
|
|
# =============================================================================
|
||
|
|
|
||
|
|
class NexusArchitect:
|
||
|
|
"""Main class for Nexus architectural operations."""
|
||
|
|
|
||
|
|
def __init__(self):
|
||
|
|
self.scene_graph = SceneGraph()
|
||
|
|
self.generated_code_cache: Dict[str, str] = {}
|
||
|
|
|
||
|
|
def design_room(
|
||
|
|
self,
|
||
|
|
name: str,
|
||
|
|
theme: str,
|
||
|
|
dimensions: Optional[Dict[str, float]] = None,
|
||
|
|
features: Optional[List[str]] = None,
|
||
|
|
lighting_profile: str = "default",
|
||
|
|
mental_state: Optional[Dict] = None,
|
||
|
|
) -> Dict[str, Any]:
|
||
|
|
"""
|
||
|
|
Design a new room in the Nexus.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
name: Unique room name
|
||
|
|
theme: Room theme (meditation, tech_lab, nature, crystal_cave, library, void, custom)
|
||
|
|
dimensions: Room dimensions {width, height, depth}
|
||
|
|
features: List of feature names to include
|
||
|
|
lighting_profile: Lighting preset name
|
||
|
|
mental_state: Optional context for design decisions
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Dict with design result, generated prompt, and room configuration
|
||
|
|
"""
|
||
|
|
# Validate inputs
|
||
|
|
try:
|
||
|
|
theme_enum = RoomTheme(theme.lower())
|
||
|
|
except ValueError:
|
||
|
|
return {
|
||
|
|
"success": False,
|
||
|
|
"error": f"Invalid theme: {theme}. Valid themes: {[t.value for t in RoomTheme]}"
|
||
|
|
}
|
||
|
|
|
||
|
|
if name in self.scene_graph.rooms:
|
||
|
|
return {
|
||
|
|
"success": False,
|
||
|
|
"error": f"Room '{name}' already exists. Use update_room to modify."
|
||
|
|
}
|
||
|
|
|
||
|
|
# Create room configuration
|
||
|
|
room_config = RoomConfig(
|
||
|
|
name=name,
|
||
|
|
theme=theme_enum,
|
||
|
|
dimensions=dimensions or {"width": 10, "height": 5, "depth": 10},
|
||
|
|
features=features or [],
|
||
|
|
lighting_profile=lighting_profile,
|
||
|
|
)
|
||
|
|
|
||
|
|
# Generate LLM prompt
|
||
|
|
prompt = generate_room_design_prompt(room_config, mental_state)
|
||
|
|
|
||
|
|
# Store in scene graph
|
||
|
|
self.scene_graph.rooms[name] = room_config
|
||
|
|
|
||
|
|
return {
|
||
|
|
"success": True,
|
||
|
|
"room_name": name,
|
||
|
|
"theme": theme,
|
||
|
|
"prompt": prompt,
|
||
|
|
"config": self.scene_graph._room_to_dict(room_config),
|
||
|
|
"message": f"Room '{name}' designed successfully. Use the prompt with an LLM to generate Three.js code."
|
||
|
|
}
|
||
|
|
|
||
|
|
def create_portal(
|
||
|
|
self,
|
||
|
|
name: str,
|
||
|
|
source_room: str,
|
||
|
|
target_room: str,
|
||
|
|
position: Optional[Dict[str, float]] = None,
|
||
|
|
style: str = "circular",
|
||
|
|
color: str = "#00ffff",
|
||
|
|
) -> Dict[str, Any]:
|
||
|
|
"""
|
||
|
|
Create a portal connecting two rooms.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
name: Unique portal name
|
||
|
|
source_room: Source room identifier
|
||
|
|
target_room: Target room identifier
|
||
|
|
position: Portal position {x, y, z}
|
||
|
|
style: Portal visual style
|
||
|
|
color: Portal color (hex)
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Dict with portal creation result
|
||
|
|
"""
|
||
|
|
# Validate rooms exist
|
||
|
|
if source_room not in self.scene_graph.rooms:
|
||
|
|
return {"success": False, "error": f"Source room '{source_room}' does not exist"}
|
||
|
|
if target_room not in self.scene_graph.rooms:
|
||
|
|
return {"success": False, "error": f"Target room '{target_room}' does not exist"}
|
||
|
|
|
||
|
|
try:
|
||
|
|
style_enum = PortalStyle(style.lower())
|
||
|
|
except ValueError:
|
||
|
|
return {
|
||
|
|
"success": False,
|
||
|
|
"error": f"Invalid style: {style}. Valid styles: {[s.value for s in PortalStyle]}"
|
||
|
|
}
|
||
|
|
|
||
|
|
portal_config = PortalConfig(
|
||
|
|
name=name,
|
||
|
|
source_room=source_room,
|
||
|
|
target_room=target_room,
|
||
|
|
position=position or {"x": 0, "y": 0, "z": 0},
|
||
|
|
style=style_enum,
|
||
|
|
color=color,
|
||
|
|
)
|
||
|
|
|
||
|
|
self.scene_graph.portals[name] = portal_config
|
||
|
|
|
||
|
|
prompt = generate_portal_prompt(
|
||
|
|
portal_config,
|
||
|
|
self.scene_graph.rooms.get(source_room)
|
||
|
|
)
|
||
|
|
|
||
|
|
return {
|
||
|
|
"success": True,
|
||
|
|
"portal_name": name,
|
||
|
|
"source": source_room,
|
||
|
|
"target": target_room,
|
||
|
|
"prompt": prompt,
|
||
|
|
"config": self.scene_graph._portal_to_dict(portal_config),
|
||
|
|
}
|
||
|
|
|
||
|
|
def add_lighting(
|
||
|
|
self,
|
||
|
|
room_name: str,
|
||
|
|
lights: List[Dict[str, Any]],
|
||
|
|
) -> Dict[str, Any]:
|
||
|
|
"""
|
||
|
|
Add lighting to a room.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
room_name: Target room name
|
||
|
|
lights: List of light configurations
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Dict with lighting addition result
|
||
|
|
"""
|
||
|
|
if room_name not in self.scene_graph.rooms:
|
||
|
|
return {"success": False, "error": f"Room '{room_name}' does not exist"}
|
||
|
|
|
||
|
|
light_configs = []
|
||
|
|
for light_data in lights:
|
||
|
|
try:
|
||
|
|
light_type = LightType(light_data.get("type", "point").lower())
|
||
|
|
except ValueError:
|
||
|
|
return {
|
||
|
|
"success": False,
|
||
|
|
"error": f"Invalid light type: {light_data.get('type')}"
|
||
|
|
}
|
||
|
|
|
||
|
|
light_config = LightConfig(
|
||
|
|
name=light_data.get("name", f"light_{len(self.scene_graph.lights)}"),
|
||
|
|
type=light_type,
|
||
|
|
position=light_data.get("position", {"x": 0, "y": 5, "z": 0}),
|
||
|
|
color=light_data.get("color", "#ffffff"),
|
||
|
|
intensity=light_data.get("intensity", 1.0),
|
||
|
|
cast_shadow=light_data.get("cast_shadow", True),
|
||
|
|
)
|
||
|
|
light_configs.append(light_config)
|
||
|
|
self.scene_graph.lights[light_config.name] = light_config
|
||
|
|
|
||
|
|
prompt = generate_lighting_prompt(light_configs, room_name)
|
||
|
|
|
||
|
|
return {
|
||
|
|
"success": True,
|
||
|
|
"room": room_name,
|
||
|
|
"lights_added": len(light_configs),
|
||
|
|
"prompt": prompt,
|
||
|
|
"light_configs": [self.scene_graph._light_to_dict(l) for l in light_configs],
|
||
|
|
}
|
||
|
|
|
||
|
|
def validate_scene_code(self, code: str, strict_mode: bool = False) -> Dict[str, Any]:
|
||
|
|
"""
|
||
|
|
Validate generated Three.js code.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
code: JavaScript code to validate
|
||
|
|
strict_mode: Enable stricter validation
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Dict with validation results
|
||
|
|
"""
|
||
|
|
# Sanitize first
|
||
|
|
sanitized = sanitize_three_js_code(code)
|
||
|
|
|
||
|
|
# Validate
|
||
|
|
result = validate_three_js_code(sanitized, strict_mode)
|
||
|
|
|
||
|
|
# Extract code block if wrapped in markdown
|
||
|
|
code_block_pattern = r'```(?:javascript|js)?\s*\n(.*?)\n```'
|
||
|
|
match = re.search(code_block_pattern, sanitized, re.DOTALL)
|
||
|
|
if match:
|
||
|
|
extracted_code = match.group(1)
|
||
|
|
else:
|
||
|
|
extracted_code = sanitized
|
||
|
|
|
||
|
|
return {
|
||
|
|
"is_valid": result.is_valid,
|
||
|
|
"errors": result.errors,
|
||
|
|
"warnings": result.warnings,
|
||
|
|
"sanitized_code": sanitized,
|
||
|
|
"extracted_code": extracted_code,
|
||
|
|
"safety_score": max(0, 100 - len(result.errors) * 20 - len(result.warnings) * 5),
|
||
|
|
}
|
||
|
|
|
||
|
|
def export_scene(self, format: str = "json") -> Dict[str, Any]:
|
||
|
|
"""
|
||
|
|
Export the current scene configuration.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
format: Export format (json, js)
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Dict with exported scene data
|
||
|
|
"""
|
||
|
|
scene_dict = self.scene_graph.to_dict()
|
||
|
|
|
||
|
|
if format == "json":
|
||
|
|
return {
|
||
|
|
"success": True,
|
||
|
|
"format": "json",
|
||
|
|
"data": json.dumps(scene_dict, indent=2),
|
||
|
|
"summary": {
|
||
|
|
"rooms": len(self.scene_graph.rooms),
|
||
|
|
"portals": len(self.scene_graph.portals),
|
||
|
|
"lights": len(self.scene_graph.lights),
|
||
|
|
"architecture_elements": len(self.scene_graph.architecture),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
elif format == "js":
|
||
|
|
# Generate JavaScript module
|
||
|
|
js_code = f"""// Nexus Scene Export
|
||
|
|
// Generated: {__import__('datetime').datetime.now().isoformat()}
|
||
|
|
|
||
|
|
export const sceneConfig = {json.dumps(scene_dict, indent=2)};
|
||
|
|
|
||
|
|
export function loadScene(scene) {{
|
||
|
|
// TODO: Implement scene loader
|
||
|
|
console.log('Loading scene with', sceneConfig.rooms.length, 'rooms');
|
||
|
|
}}
|
||
|
|
"""
|
||
|
|
return {
|
||
|
|
"success": True,
|
||
|
|
"format": "js",
|
||
|
|
"data": js_code,
|
||
|
|
"summary": {
|
||
|
|
"rooms": len(self.scene_graph.rooms),
|
||
|
|
"portals": len(self.scene_graph.portals),
|
||
|
|
"lights": len(self.scene_graph.lights),
|
||
|
|
"architecture_elements": len(self.scene_graph.architecture),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else:
|
||
|
|
return {"success": False, "error": f"Unknown format: {format}"}
|
||
|
|
|
||
|
|
def get_scene_summary(self) -> Dict[str, Any]:
|
||
|
|
"""Get a summary of the current scene state."""
|
||
|
|
return {
|
||
|
|
"rooms": [
|
||
|
|
{
|
||
|
|
"name": name,
|
||
|
|
"theme": room.theme.value,
|
||
|
|
"connected_portals": [
|
||
|
|
p.name for p in self.scene_graph.portals.values()
|
||
|
|
if p.source_room == name or p.target_room == name
|
||
|
|
]
|
||
|
|
}
|
||
|
|
for name, room in self.scene_graph.rooms.items()
|
||
|
|
],
|
||
|
|
"portal_network": [
|
||
|
|
{"name": p.name, "source": p.source_room, "target": p.target_room}
|
||
|
|
for p in self.scene_graph.portals.values()
|
||
|
|
],
|
||
|
|
"total_lights": len(self.scene_graph.lights),
|
||
|
|
"total_architecture": len(self.scene_graph.architecture),
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
# =============================================================================
|
||
|
|
# Tool Entry Points
|
||
|
|
# =============================================================================
|
||
|
|
|
||
|
|
# Global architect instance (per-session)
|
||
|
|
_nexus_architect: Optional[NexusArchitect] = None
|
||
|
|
|
||
|
|
|
||
|
|
def get_architect() -> NexusArchitect:
|
||
|
|
"""Get or create the NexusArchitect instance."""
|
||
|
|
global _nexus_architect
|
||
|
|
if _nexus_architect is None:
|
||
|
|
_nexus_architect = NexusArchitect()
|
||
|
|
return _nexus_architect
|
||
|
|
|
||
|
|
|
||
|
|
def nexus_design_room(
|
||
|
|
name: str,
|
||
|
|
theme: str,
|
||
|
|
dimensions: Optional[Dict[str, float]] = None,
|
||
|
|
features: Optional[List[str]] = None,
|
||
|
|
lighting_profile: str = "default",
|
||
|
|
mental_state: Optional[Dict] = None,
|
||
|
|
) -> str:
|
||
|
|
"""
|
||
|
|
Design a new room in the Nexus.
|
||
|
|
|
||
|
|
Creates a room configuration and generates an LLM prompt for Three.js code generation.
|
||
|
|
"""
|
||
|
|
architect = get_architect()
|
||
|
|
result = architect.design_room(
|
||
|
|
name=name,
|
||
|
|
theme=theme,
|
||
|
|
dimensions=dimensions,
|
||
|
|
features=features,
|
||
|
|
lighting_profile=lighting_profile,
|
||
|
|
mental_state=mental_state,
|
||
|
|
)
|
||
|
|
return json.dumps(result, ensure_ascii=False)
|
||
|
|
|
||
|
|
|
||
|
|
def nexus_create_portal(
|
||
|
|
name: str,
|
||
|
|
source_room: str,
|
||
|
|
target_room: str,
|
||
|
|
position: Optional[Dict[str, float]] = None,
|
||
|
|
style: str = "circular",
|
||
|
|
color: str = "#00ffff",
|
||
|
|
) -> str:
|
||
|
|
"""
|
||
|
|
Create a portal connecting two rooms.
|
||
|
|
|
||
|
|
Generates configuration and prompt for portal Three.js code.
|
||
|
|
"""
|
||
|
|
architect = get_architect()
|
||
|
|
result = architect.create_portal(
|
||
|
|
name=name,
|
||
|
|
source_room=source_room,
|
||
|
|
target_room=target_room,
|
||
|
|
position=position,
|
||
|
|
style=style,
|
||
|
|
color=color,
|
||
|
|
)
|
||
|
|
return json.dumps(result, ensure_ascii=False)
|
||
|
|
|
||
|
|
|
||
|
|
def nexus_add_lighting(
|
||
|
|
room_name: str,
|
||
|
|
lights: List[Dict[str, Any]],
|
||
|
|
) -> str:
|
||
|
|
"""
|
||
|
|
Add lighting elements to a room.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
room_name: Target room name
|
||
|
|
lights: List of light configs with name, type, position, color, intensity, cast_shadow
|
||
|
|
"""
|
||
|
|
architect = get_architect()
|
||
|
|
result = architect.add_lighting(room_name, lights)
|
||
|
|
return json.dumps(result, ensure_ascii=False)
|
||
|
|
|
||
|
|
|
||
|
|
def nexus_validate_scene(code: str, strict_mode: bool = False) -> str:
|
||
|
|
"""
|
||
|
|
Validate generated Three.js code for syntax and safety.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
code: JavaScript/Three.js code to validate
|
||
|
|
strict_mode: Enable stricter validation rules
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
JSON with validation results including is_valid, errors, warnings, safety_score
|
||
|
|
"""
|
||
|
|
architect = get_architect()
|
||
|
|
result = architect.validate_scene_code(code, strict_mode)
|
||
|
|
return json.dumps(result, ensure_ascii=False)
|
||
|
|
|
||
|
|
|
||
|
|
def nexus_export_scene(format: str = "json") -> str:
|
||
|
|
"""
|
||
|
|
Export the current scene configuration.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
format: Export format - "json" or "js"
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
JSON with exported scene data
|
||
|
|
"""
|
||
|
|
architect = get_architect()
|
||
|
|
result = architect.export_scene(format)
|
||
|
|
return json.dumps(result, ensure_ascii=False)
|
||
|
|
|
||
|
|
|
||
|
|
def nexus_get_summary() -> str:
|
||
|
|
"""Get a summary of the current Nexus scene state."""
|
||
|
|
architect = get_architect()
|
||
|
|
result = architect.get_scene_summary()
|
||
|
|
return json.dumps(result, ensure_ascii=False)
|
||
|
|
|
||
|
|
|
||
|
|
def check_nexus_architect_requirements() -> bool:
|
||
|
|
"""Check if the Nexus Architect tool is available (no external deps required)."""
|
||
|
|
return True
|
||
|
|
|
||
|
|
|
||
|
|
# =============================================================================
|
||
|
|
# Tool Schemas
|
||
|
|
# =============================================================================
|
||
|
|
|
||
|
|
NEXUS_ARCHITECT_SCHEMAS = {
|
||
|
|
"nexus_design_room": {
|
||
|
|
"name": "nexus_design_room",
|
||
|
|
"description": (
|
||
|
|
"Design a new 3D room in the Nexus virtual environment. "
|
||
|
|
"Creates room configuration and generates an LLM prompt for Three.js code generation. "
|
||
|
|
"The room can be themed (meditation, tech_lab, nature, crystal_cave, library, void) "
|
||
|
|
"and include specific features. Returns a prompt that should be sent to an LLM "
|
||
|
|
"to generate the actual Three.js code."
|
||
|
|
),
|
||
|
|
"parameters": {
|
||
|
|
"type": "object",
|
||
|
|
"properties": {
|
||
|
|
"name": {
|
||
|
|
"type": "string",
|
||
|
|
"description": "Unique name for the room (e.g., 'meditation_chamber', 'tech_lab_alpha')"
|
||
|
|
},
|
||
|
|
"theme": {
|
||
|
|
"type": "string",
|
||
|
|
"enum": ["meditation", "tech_lab", "nature", "crystal_cave", "library", "void", "custom"],
|
||
|
|
"description": "Visual theme for the room"
|
||
|
|
},
|
||
|
|
"dimensions": {
|
||
|
|
"type": "object",
|
||
|
|
"properties": {
|
||
|
|
"width": {"type": "number", "default": 10},
|
||
|
|
"height": {"type": "number", "default": 5},
|
||
|
|
"depth": {"type": "number", "default": 10}
|
||
|
|
},
|
||
|
|
"description": "Room dimensions in meters"
|
||
|
|
},
|
||
|
|
"features": {
|
||
|
|
"type": "array",
|
||
|
|
"items": {"type": "string"},
|
||
|
|
"description": "List of features to include (e.g., 'water_feature', 'floating_lanterns', 'holographic_display')"
|
||
|
|
},
|
||
|
|
"lighting_profile": {
|
||
|
|
"type": "string",
|
||
|
|
"default": "default",
|
||
|
|
"description": "Lighting preset name"
|
||
|
|
},
|
||
|
|
"mental_state": {
|
||
|
|
"type": "object",
|
||
|
|
"description": "Optional context about agent's current mood/energy for design decisions",
|
||
|
|
"properties": {
|
||
|
|
"mood": {"type": "string"},
|
||
|
|
"energy": {"type": "number"},
|
||
|
|
"focus": {"type": "string"}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"required": ["name", "theme"]
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"nexus_create_portal": {
|
||
|
|
"name": "nexus_create_portal",
|
||
|
|
"description": (
|
||
|
|
"Create a portal connecting two rooms in the Nexus. "
|
||
|
|
"Portals enable navigation between rooms with visual effects. "
|
||
|
|
"Generates a prompt for LLM to create the portal Three.js code."
|
||
|
|
),
|
||
|
|
"parameters": {
|
||
|
|
"type": "object",
|
||
|
|
"properties": {
|
||
|
|
"name": {
|
||
|
|
"type": "string",
|
||
|
|
"description": "Unique portal name"
|
||
|
|
},
|
||
|
|
"source_room": {
|
||
|
|
"type": "string",
|
||
|
|
"description": "Source room identifier (must exist)"
|
||
|
|
},
|
||
|
|
"target_room": {
|
||
|
|
"type": "string",
|
||
|
|
"description": "Target room identifier (must exist)"
|
||
|
|
},
|
||
|
|
"position": {
|
||
|
|
"type": "object",
|
||
|
|
"properties": {
|
||
|
|
"x": {"type": "number", "default": 0},
|
||
|
|
"y": {"type": "number", "default": 0},
|
||
|
|
"z": {"type": "number", "default": 0}
|
||
|
|
},
|
||
|
|
"description": "Portal position in source room"
|
||
|
|
},
|
||
|
|
"style": {
|
||
|
|
"type": "string",
|
||
|
|
"enum": ["circular", "rectangular", "stargate", "dissolve", "glitch"],
|
||
|
|
"default": "circular",
|
||
|
|
"description": "Visual style of the portal"
|
||
|
|
},
|
||
|
|
"color": {
|
||
|
|
"type": "string",
|
||
|
|
"default": "#00ffff",
|
||
|
|
"description": "Portal color in hex format"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"required": ["name", "source_room", "target_room"]
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"nexus_add_lighting": {
|
||
|
|
"name": "nexus_add_lighting",
|
||
|
|
"description": (
|
||
|
|
"Add lighting elements to a Nexus room. "
|
||
|
|
"Supports ambient, directional, point, spot, and hemisphere lights. "
|
||
|
|
"Generates prompt for LLM to create lighting Three.js code."
|
||
|
|
),
|
||
|
|
"parameters": {
|
||
|
|
"type": "object",
|
||
|
|
"properties": {
|
||
|
|
"room_name": {
|
||
|
|
"type": "string",
|
||
|
|
"description": "Target room name"
|
||
|
|
},
|
||
|
|
"lights": {
|
||
|
|
"type": "array",
|
||
|
|
"items": {
|
||
|
|
"type": "object",
|
||
|
|
"properties": {
|
||
|
|
"name": {"type": "string"},
|
||
|
|
"type": {"type": "string", "enum": ["ambient", "directional", "point", "spot", "hemisphere"]},
|
||
|
|
"position": {
|
||
|
|
"type": "object",
|
||
|
|
"properties": {"x": {"type": "number"}, "y": {"type": "number"}, "z": {"type": "number"}}
|
||
|
|
},
|
||
|
|
"color": {"type": "string", "default": "#ffffff"},
|
||
|
|
"intensity": {"type": "number", "default": 1.0},
|
||
|
|
"cast_shadow": {"type": "boolean", "default": True}
|
||
|
|
},
|
||
|
|
"required": ["name", "type"]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"required": ["room_name", "lights"]
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"nexus_validate_scene": {
|
||
|
|
"name": "nexus_validate_scene",
|
||
|
|
"description": (
|
||
|
|
"Validate generated Three.js code for syntax correctness and security. "
|
||
|
|
"Checks for banned patterns, syntax errors, and Three.js API safety. "
|
||
|
|
"Returns validation results with safety score."
|
||
|
|
),
|
||
|
|
"parameters": {
|
||
|
|
"type": "object",
|
||
|
|
"properties": {
|
||
|
|
"code": {
|
||
|
|
"type": "string",
|
||
|
|
"description": "JavaScript/Three.js code to validate"
|
||
|
|
},
|
||
|
|
"strict_mode": {
|
||
|
|
"type": "boolean",
|
||
|
|
"default": False,
|
||
|
|
"description": "Enable stricter validation rules"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"required": ["code"]
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"nexus_export_scene": {
|
||
|
|
"name": "nexus_export_scene",
|
||
|
|
"description": (
|
||
|
|
"Export the current Nexus scene configuration to JSON or JavaScript format. "
|
||
|
|
"Useful for saving scene state or generating scene loader code."
|
||
|
|
),
|
||
|
|
"parameters": {
|
||
|
|
"type": "object",
|
||
|
|
"properties": {
|
||
|
|
"format": {
|
||
|
|
"type": "string",
|
||
|
|
"enum": ["json", "js"],
|
||
|
|
"default": "json",
|
||
|
|
"description": "Export format"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"nexus_get_summary": {
|
||
|
|
"name": "nexus_get_summary",
|
||
|
|
"description": (
|
||
|
|
"Get a summary of the current Nexus scene including rooms, portals, and connectivity. "
|
||
|
|
"Useful for understanding the current world state."
|
||
|
|
),
|
||
|
|
"parameters": {
|
||
|
|
"type": "object",
|
||
|
|
"properties": {}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
# =============================================================================
|
||
|
|
# Registry Integration
|
||
|
|
# =============================================================================
|
||
|
|
from tools.registry import registry
|
||
|
|
|
||
|
|
registry.register(
|
||
|
|
name="nexus_design_room",
|
||
|
|
toolset="nexus_architect",
|
||
|
|
schema=NEXUS_ARCHITECT_SCHEMAS["nexus_design_room"],
|
||
|
|
handler=lambda args, **kw: nexus_design_room(
|
||
|
|
name=args["name"],
|
||
|
|
theme=args["theme"],
|
||
|
|
dimensions=args.get("dimensions"),
|
||
|
|
features=args.get("features"),
|
||
|
|
lighting_profile=args.get("lighting_profile", "default"),
|
||
|
|
mental_state=args.get("mental_state"),
|
||
|
|
),
|
||
|
|
check_fn=check_nexus_architect_requirements,
|
||
|
|
emoji="🏛️",
|
||
|
|
)
|
||
|
|
|
||
|
|
registry.register(
|
||
|
|
name="nexus_create_portal",
|
||
|
|
toolset="nexus_architect",
|
||
|
|
schema=NEXUS_ARCHITECT_SCHEMAS["nexus_create_portal"],
|
||
|
|
handler=lambda args, **kw: nexus_create_portal(
|
||
|
|
name=args["name"],
|
||
|
|
source_room=args["source_room"],
|
||
|
|
target_room=args["target_room"],
|
||
|
|
position=args.get("position"),
|
||
|
|
style=args.get("style", "circular"),
|
||
|
|
color=args.get("color", "#00ffff"),
|
||
|
|
),
|
||
|
|
check_fn=check_nexus_architect_requirements,
|
||
|
|
emoji="🌀",
|
||
|
|
)
|
||
|
|
|
||
|
|
registry.register(
|
||
|
|
name="nexus_add_lighting",
|
||
|
|
toolset="nexus_architect",
|
||
|
|
schema=NEXUS_ARCHITECT_SCHEMAS["nexus_add_lighting"],
|
||
|
|
handler=lambda args, **kw: nexus_add_lighting(
|
||
|
|
room_name=args["room_name"],
|
||
|
|
lights=args["lights"],
|
||
|
|
),
|
||
|
|
check_fn=check_nexus_architect_requirements,
|
||
|
|
emoji="💡",
|
||
|
|
)
|
||
|
|
|
||
|
|
registry.register(
|
||
|
|
name="nexus_validate_scene",
|
||
|
|
toolset="nexus_architect",
|
||
|
|
schema=NEXUS_ARCHITECT_SCHEMAS["nexus_validate_scene"],
|
||
|
|
handler=lambda args, **kw: nexus_validate_scene(
|
||
|
|
code=args["code"],
|
||
|
|
strict_mode=args.get("strict_mode", False),
|
||
|
|
),
|
||
|
|
check_fn=check_nexus_architect_requirements,
|
||
|
|
emoji="🔒",
|
||
|
|
)
|
||
|
|
|
||
|
|
registry.register(
|
||
|
|
name="nexus_export_scene",
|
||
|
|
toolset="nexus_architect",
|
||
|
|
schema=NEXUS_ARCHITECT_SCHEMAS["nexus_export_scene"],
|
||
|
|
handler=lambda args, **kw: nexus_export_scene(
|
||
|
|
format=args.get("format", "json"),
|
||
|
|
),
|
||
|
|
check_fn=check_nexus_architect_requirements,
|
||
|
|
emoji="📦",
|
||
|
|
)
|
||
|
|
|
||
|
|
registry.register(
|
||
|
|
name="nexus_get_summary",
|
||
|
|
toolset="nexus_architect",
|
||
|
|
schema=NEXUS_ARCHITECT_SCHEMAS["nexus_get_summary"],
|
||
|
|
handler=lambda args, **kw: nexus_get_summary(),
|
||
|
|
check_fn=check_nexus_architect_requirements,
|
||
|
|
emoji="📊",
|
||
|
|
)
|