# AuroraView

> A lightweight WebView framework for DCC (Digital Content Creation) software, built with Rust and Python bindings. Perfect for Maya, 3ds Max, Houdini, Blender, and more.

## Overview

AuroraView provides a modern web-based UI solution for professional DCC applications like Maya, 3ds Max, Houdini, Blender, Photoshop, and Unreal Engine. Built on Rust's Wry library with PyO3 bindings, it offers native performance with minimal overhead.

- **Package**: `pip install auroraview`
- **Python**: 3.7+
- **Platforms**: Windows, macOS, Linux
- **License**: MIT

## Quick Start

### Installation

```bash
# Windows/macOS
pip install auroraview

# With Qt support (for Maya, Houdini, Nuke)
pip install auroraview[qt]
```

### Basic Usage

```python
from auroraview import WebView

# Create and show WebView
webview = WebView.create("My App", url="http://localhost:3000")
webview.show()
```

## Core API Reference

### WebView Class

The main class for creating WebView windows.

#### Constructor Parameters

```python
WebView(
    title: str = "AuroraView",      # Window title
    width: int = 800,               # Window width
    height: int = 600,              # Window height
    url: str = None,                # URL to load
    html: str = None,               # HTML content to load
    debug: bool = True,             # Enable DevTools (F12)
    context_menu: bool = True,      # Enable right-click menu
    resizable: bool = True,         # Allow window resize
    frame: bool = True,             # Show window frame
    parent: int = None,             # Parent HWND for embedding
    mode: str = None,               # "owner" or "child" mode
    asset_root: str = None,         # Root for auroraview:// protocol
    allow_file_protocol: bool = False,  # Enable file:// URLs
    always_on_top: bool = False,    # Keep window on top
    transparent: bool = False,      # Transparent window
)
```

#### Factory Methods

```python
# Recommended way to create WebView
webview = WebView.create(
    title="My App",
    url="http://localhost:3000",
    width=800,
    height=600,
    parent=hwnd,           # Optional: parent window handle
    mode="auto",           # "auto", "owner", "child"
    debug=True,            # Enable DevTools
    singleton="my_tool",   # Optional: singleton key
)

# For DCC embedding with HWND
webview = WebView.create_for_dcc(
    parent_hwnd=hwnd,
    title="DCC Tool",
    width=800,
    height=600,
    url="http://localhost:3000",
)

# Convenience helper for embedded mode
webview = WebView.run_embedded(
    title="Tool",
    url="http://localhost:3000",
    parent=hwnd,
)
```

#### Content Loading

```python
# Load URL
webview.load_url("http://localhost:3000")

# Load HTML
webview.load_html("<h1>Hello World</h1>")

# Load local file
webview.load_file("path/to/index.html")
```

#### JavaScript Execution

```python
# Execute JavaScript
webview.eval_js("console.log('Hello from Python')")

# Execute with callback
webview.eval_js_async(
    "document.title",
    callback=lambda result: print(f"Title: {result}"),
    timeout_ms=5000
)
```

#### Window Control

```python
webview.show()              # Show window
webview.hide()              # Hide window
webview.close()             # Close window
webview.resize(1024, 768)   # Resize window
webview.move(100, 100)      # Move window
webview.minimize()          # Minimize
webview.maximize()          # Maximize
webview.toggle_fullscreen() # Toggle fullscreen
webview.focus()             # Focus window
```

#### Properties

```python
webview.title               # Get/set window title
webview.width               # Window width (read-only)
webview.height              # Window height (read-only)
webview.x                   # Window x position
webview.y                   # Window y position
```

### Python → JavaScript Communication

```python
# Emit event to JavaScript
webview.emit("update_data", {"frame": 120, "objects": ["cube", "sphere"]})
```

```javascript
// JavaScript: Listen for Python events
window.auroraview.on('update_data', (data) => {
    console.log('Frame:', data.frame);
});
```

### JavaScript → Python Communication

#### Method 1: Events (fire-and-forget)

```javascript
// JavaScript: Send event to Python
window.auroraview.send_event('export_scene', {
    path: '/path/to/export.fbx',
    format: 'fbx'
});
```

```python
# Python: Register event handler
@webview.on("export_scene")
def handle_export(data):
    print(f"Exporting to: {data['path']}")
```

#### Method 2: RPC with Return Value

```javascript
// JavaScript: Call Python method and get result
const result = await auroraview.api.get_hierarchy({ root: 'scene' });
console.log(result);  // { children: [...], count: 2 }
```

```python
# Python: Bind callable method
@webview.bind_call("api.get_hierarchy")
def get_hierarchy(root=None):
    return {"children": ["group1", "mesh_cube"], "count": 2}
```

### API Binding

```python
# Bind single method
@webview.bind_call("api.echo")
def echo(message: str = "") -> dict:
    return {"message": message}

# Bind all methods of an object
class API:
    def get_data(self) -> dict:
        return {"items": [1, 2, 3]}

    def save_item(self, name: str = "", value: int = 0) -> dict:
        return {"ok": True, "name": name}

webview.bind_api(API(), namespace="api")
```

### Custom Protocol Handler

```python
# Enable built-in auroraview:// protocol
webview = WebView(
    title="My App",
    asset_root="./assets"  # Files accessible via auroraview://
)

# Register custom protocol
def handle_maya_protocol(uri: str) -> dict:
    path = uri.replace("maya://", "")
    try:
        with open(f"C:/maya_projects/{path}", "rb") as f:
            return {
                "data": f.read(),
                "mime_type": "image/png",
                "status": 200
            }
    except FileNotFoundError:
        return {"data": b"Not Found", "mime_type": "text/plain", "status": 404}

webview.register_protocol("maya", handle_maya_protocol)
```

### Window Events

```python
@webview.on_shown
def on_shown(data):
    print("Window is now visible")

@webview.on_focused
def on_focused(data):
    print("Window gained focus")

@webview.on_resized
def on_resized(data):
    print(f"Window resized to {data.width}x{data.height}")

@webview.on_closing
def on_closing(data):
    return True  # Return True to allow close, False to cancel
```

### Signals (Qt-like Pattern)

```python
from auroraview import WebView, Signal

class MyTool(WebView):
    selection_changed = Signal(list)
    progress_updated = Signal(int, str)

    def __init__(self):
        super().__init__(title="My Tool")
        self.selection_changed.connect(self._on_selection)

    def _on_selection(self, items):
        print(f"Selection: {items}")

    def update_selection(self, items):
        self.selection_changed.emit(items)
```

## Qt Integration (QtWebView)

For Qt-based DCC applications (Maya, Houdini, Nuke, 3ds Max).

```python
from auroraview import QtWebView
from qtpy.QtWidgets import QDialog, QVBoxLayout

# Create dialog
dialog = QDialog(maya_main_window())
layout = QVBoxLayout(dialog)

# Create WebView as Qt widget
webview = QtWebView(
    parent=dialog,
    width=800,
    height=600
)
layout.addWidget(webview)

# Load content
webview.load_url("http://localhost:3000")

# Show
dialog.show()
webview.show()
```

### WebView2 Pre-warming

```python
from auroraview.integration.qt import WebViewPool

# Pre-warm at DCC startup (optional - happens automatically)
WebViewPool.prewarm()

# Check status
if WebViewPool.has_prewarmed():
    print(f"Pre-warm took {WebViewPool.get_prewarm_time():.2f}s")
```

## HWND Integration (AuroraView)

For Unreal Engine and non-Qt applications.

```python
from auroraview import AuroraView

# Create standalone WebView
webview = AuroraView(url="http://localhost:3000")
webview.show()

# Get HWND for external embedding
hwnd = webview.get_hwnd()
if hwnd:
    # Unreal Engine integration
    import unreal
    unreal.parent_external_window_to_slate(hwnd)
```

## Standalone Mode

```python
from auroraview import run_standalone

# One-liner for standalone apps
run_standalone(
    title="My App",
    url="https://example.com",
    width=1024,
    height=768
)
```

## Command Line Interface

```bash
# Load URL
auroraview --url https://example.com

# Load local HTML
auroraview --html /path/to/file.html

# Custom configuration
auroraview --url https://example.com --title "My App" --width 1024 --height 768

# Using uvx
uvx auroraview --url https://example.com
```

## Testing Framework

### HeadlessWebView

```python
from auroraview.testing import HeadlessWebView

# Auto-detect best backend
with HeadlessWebView.auto() as webview:
    webview.goto("https://example.com")
    webview.click("#button")
    assert webview.text("#result") == "Success"

# Explicitly use Playwright
with HeadlessWebView.playwright() as webview:
    webview.load_html("<h1>Test</h1>")
    assert webview.text("h1") == "Test"
    webview.screenshot("test.png")
```

### Available Backends

| Backend | Method | Platform | Use Case |
|---------|--------|----------|----------|
| Playwright | `HeadlessWebView.playwright()` | All | CI/CD |
| Xvfb | `HeadlessWebView.virtual_display()` | Linux | Real WebView |
| WebView2 CDP | `HeadlessWebView.webview2_cdp(url)` | Windows | Real WebView2 |

## DCC Software Support

| Software | Status | Python | Notes |
|----------|--------|--------|-------|
| Maya | ✅ | 3.7+ | Qt Native (QtWebView) |
| 3ds Max | ✅ | 3.7+ | Qt Native (QtWebView) |
| Houdini | ✅ | 3.7+ | Qt Native (QtWebView) |
| Blender | ✅ | 3.7+ | Standalone mode |
| Nuke | ✅ | 3.7+ | Qt Native (QtWebView) |
| Unreal Engine | ✅ | 3.7+ | HWND mode (AuroraView) |
| Photoshop | 🚧 | 3.7+ | Planned |

## JavaScript API Reference

### window.auroraview

```javascript
// Call Python method (returns Promise)
const result = await auroraview.call('api.method_name', { param: value });

// Call via api proxy (shorthand)
const result = await auroraview.api.method_name({ param: value });

// Send event to Python (fire-and-forget)
auroraview.send_event('event_name', { data: value });

// Listen for Python events
const unsubscribe = auroraview.on('event_name', (data) => {
    console.log('Received:', data);
});

// Unsubscribe
auroraview.off('event_name', handler);
// or
unsubscribe();

// Local JS event (does NOT reach Python)
auroraview.trigger('local_event', data);
```

### Ready Event

```javascript
window.addEventListener('auroraviewready', () => {
    // Safe to use auroraview API
    auroraview.api.init();
});
```

## Key Imports

```python
from auroraview import (
    # Core
    WebView,
    Signal,

    # Integration
    AuroraView,      # HWND mode
    QtWebView,       # Qt mode
    run_standalone,  # Standalone mode

    # Utilities
    EventTimer,
    path_to_file_url,
)
```

## Links

- **Repository**: https://github.com/loonghao/auroraview
- **PyPI**: https://pypi.org/project/auroraview/
- **Documentation**: https://github.com/loonghao/auroraview/tree/main/docs
- **Examples**: https://github.com/loonghao/auroraview/tree/main/examples
