Skip to content

Design Philosophy

AuroraView is built with specific design principles that guide its architecture and API decisions. Understanding these principles will help you make the most of the framework.

Core Principles

1. DCC-First Design

Unlike general-purpose WebView frameworks, AuroraView is specifically designed for Digital Content Creation software integration.

What this means:

  • Qt widget integration for Maya, Houdini, Nuke, 3ds Max
  • HWND-based embedding for Unreal Engine and non-Qt applications
  • Lifecycle management that respects DCC application patterns
  • Non-blocking operations that don't freeze the host application

Design decisions influenced by this:

  • QtWebView creates a true Qt widget, not a wrapper around a native window
  • Event processing integrates with Qt's event loop, not a separate thread
  • Parent window monitoring for automatic cleanup

2. Zero Python Dependencies

The core auroraview package has no Python dependencies beyond the standard library.

Why:

  • DCC applications often have constrained Python environments
  • Avoid version conflicts with DCC-bundled packages
  • Minimize installation complexity
  • Single .pyd file distribution

Exception: The [qt] extra installs QtPy for Qt version abstraction.

3. Rust for Performance and Safety

The core is written in Rust with PyO3 bindings.

Benefits:

  • Memory safety without garbage collection pauses
  • ~5MB package size vs ~120MB for Electron
  • Native performance for IPC and event handling
  • Thread-safe message passing

4. Backend Abstraction

AuroraView uses a backend abstraction layer that allows different implementations:

┌─────────────────────────────────────────┐
│           Python API Layer              │
│  (WebView, QtWebView, AuroraView)       │
└─────────────────────────────────────────┘


┌─────────────────────────────────────────┐
│        Backend Abstraction Layer        │
│         (WebViewBackend trait)          │
└─────────────────────────────────────────┘

        ┌───────────┴───────────┐
        ▼                       ▼
┌───────────────┐       ┌───────────────┐
│ Native Backend│       │  Qt Backend   │
│ (Wry/WebView2)│       │ (Qt Widget)   │
└───────────────┘       └───────────────┘

This enables:

  • Platform-specific optimizations
  • Future backend additions (CEF, WebKitGTK, etc.)
  • Consistent API across backends

5. Convention over Configuration

AuroraView provides sensible defaults while allowing customization.

Examples:

python
# Minimal configuration - works out of the box
webview = WebView.create("My App", url="http://localhost:3000")
webview.show()

# Full customization when needed
webview = WebView.create(
    title="My App",
    url="http://localhost:3000",
    width=1024,
    height=768,
    resizable=True,
    frame=True,
    debug=True,
    context_menu=False,
    asset_root="./assets",
)

API Design Patterns

1. Multiple API Styles

AuroraView supports different API styles for different use cases:

PatternBest ForComplexity
AuroraView with api=Quick prototypesSimple
QtWebView subclassDCC integrationMedium
WebView with bind_callAdvanced controlAdvanced

Example: Simple API Object

python
class MyAPI:
    def get_data(self) -> dict:
        return {"items": [1, 2, 3]}

view = AuroraView(url="...", api=MyAPI())

Example: Qt-style Class

python
class MyTool(QtWebView):
    selection_changed = Signal(list)
    
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.bind_api(self)

2. Explicit over Implicit

API methods clearly indicate their behavior:

python
# Clear distinction between blocking and non-blocking
webview.show()           # Blocking in standalone mode
webview.show(wait=False) # Non-blocking

# Clear distinction between event types
auroraview.send_event()  # Fire-and-forget (JS → Python)
auroraview.call()        # Request-response (JS → Python)
webview.emit()           # Push notification (Python → JS)

3. Qt-Inspired Signal System

For developers familiar with Qt:

python
from auroraview import Signal

class MyTool(WebView):
    # Signal definitions
    selection_changed = Signal(list)
    progress_updated = Signal(int, str)
    
    def _on_selection(self, items):
        self.selection_changed.emit(items)

JavaScript API Design

Unified Namespace

All JavaScript APIs are under window.auroraview:

javascript
// RPC calls
await auroraview.call('api.method', params);

// Events
auroraview.send_event('event_name', data);
auroraview.on('event_name', handler);

// API proxy (pywebview-style)
await auroraview.api.method(params);

// Shared state
auroraview.state.key = value;

Protocol Design

The IPC protocol follows a request/response pattern:

Request (JS → Python):

json
{
  "type": "call",
  "id": "unique-id",
  "method": "api.get_data",
  "params": {"key": "value"}
}

Response (Python → JS):

The backend resolves the Promise by triggering an internal event:

  • event name: __auroraview_call_result
  • payload:
json
{
  "id": "unique-id",
  "ok": true,
  "result": {"data": "..."}
}

Security Considerations

Custom Protocol Security

The auroraview:// protocol uses .localhost TLD for security:

  1. IANA Reserved - Cannot be registered by anyone
  2. Local Only - Treated as 127.0.0.1
  3. Pre-DNS Interception - Requests intercepted before DNS
  4. No Network Traffic - Never leaves local machine

Resource Access Control

python
# Secure: Only assets/ directory accessible
webview = WebView.create(
    title="My App",
    asset_root="./assets",  # Restricted access
)

# Less secure: Full filesystem access
webview = WebView.create(
    title="My App",
    allow_file_protocol=True,  # Use with caution
)

Performance Philosophy

Lazy Initialization

WebView is only created when show() is called:

python
webview = WebView.create("My App")  # No WebView created yet
webview.load_url("...")             # URL stored, not loaded
webview.show()                      # WebView created and URL loaded

Message Batching

IPC messages are processed in batches:

rust
let messages = message_queue.drain();
for message in messages {
    // Process each message
}

Lock-Free Data Structures

  • DashMap: Concurrent HashMap for callbacks
  • crossbeam-channel: Lock-free MPMC for message queue

Extensibility

Plugin Architecture

Built-in Rust plugins provide native performance:

PluginDescription
ProcessRun external processes with streaming
File SystemNative file operations
DialogNative file/folder dialogs
ShellExecute commands, open URLs
ClipboardSystem clipboard access

Custom Protocols

Register custom protocol handlers:

python
def handle_maya_protocol(uri: str) -> dict:
    path = uri.replace("maya://", "")
    return {
        "data": load_maya_resource(path),
        "mime_type": "application/octet-stream",
        "status": 200
    }

webview.register_protocol("maya", handle_maya_protocol)

Migration Paths

From pywebview

AuroraView provides pywebview-compatible APIs:

python
# pywebview style
class Api:
    def get_data(self):
        return {"items": [1, 2, 3]}

# Works with AuroraView
view = AuroraView(url="...", api=Api())
javascript
// Same JavaScript API
const data = await auroraview.api.get_data();

From Electron

Key differences:

  • Single process (no separate main/renderer)
  • Python backend instead of Node.js
  • Native system WebView instead of bundled Chromium
  • ~5MB vs ~120MB package size

Released under the MIT License.