Skip to content

A blazingly fast, lightweight WebView framework for DCC (Digital Content Creation) software, built with Rust and Python bindings.

License

Notifications You must be signed in to change notification settings

loonghao/auroraview

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

831 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

AuroraView Logo

δΈ­ζ–‡ζ–‡ζ‘£ | English

PyPI Version Python Versions Downloads Codecov PR Checks License: MIT

Rust Platform CI Build Wheels Release

CodeQL Security Audit Latest Release pre-commit

GitHub Stars GitHub Downloads Last Commit Commit Activity

Open Issues Open PRs Contributors Conventional Commits

release-please Dependabot Code Style: ruff Type Checked: mypy

Code of Conduct β€’ Security Policy β€’ Issue Tracker

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.

⚠️ Development Status: This project is under active development. APIs may change before v1.0.0 release. The project has not been extensively tested on Linux and macOS platforms.

Quick Try

Try AuroraView instantly without installation using uvx:

uvx auroraview --url baidu.com

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.

Key Features

  • Lightweight: ~5MB package size vs ~120MB for Electron
  • Fast: Native Rust performance with minimal memory footprint
  • Seamless Integration: Easy Python API for all major DCC tools
  • Modern Web Stack: Use React, Vue, or any web framework
  • Safe: Rust's memory safety guarantees
  • Cross-Platform: Windows, macOS, and Linux support
  • DCC-First Design: Built specifically for DCC software integration
  • Type-Safe: Full type checking with Rust + Python

[POINTER] DCC Integration Guide - Learn how to integrate AuroraView into Maya, Houdini, Nuke, and other DCC applications.

Architecture

AuroraView Architecture

## Technical Framework
  • Core stack: Rust 1.75+, PyO3 0.22 (abi3), Wry 0.47, Tao 0.30
  • Web engines: Windows (WebView2), macOS (WKWebView), Linux (WebKitGTK)
  • Packaging: maturin with abi3 β†’ one wheel works for CPython 3.7-3.13
  • Event loop: blocking show() by default; nonblocking mode planned for host loops
  • Deferred loading: URL/HTML set before show() are stored then applied at creation
  • IPC: bidirectional event bus (Python ↔ JavaScript via CustomEvent)
  • Protocols: custom scheme/resource loaders for local assets (e.g., dcc://)
  • Embedding: parent window handle (HWND/NSView/WId) roadmap for DCC hosts
  • Security: optin devtools, CSP hooks, remote URL allowlist (planned)
  • Performance targets: <150ms first paint (local HTML), <50MB baseline RSS

Technical Details

  • Python API: auroraview.WebView wraps Rust core with ergonomic helpers
  • Rust core: interiormutable config (Arc<Mutex<...>>) enables safe preshow updates
  • Lifecycle: create WebView on show(), then apply lastwritewins URL/HTML
  • JS bridge: emit(event, data) from Python; window.dispatchEvent(new CustomEvent('py', {detail:{event:'xyz', data:{...}}})) from JS back to Python via IpcHandler
  • Logging: tracing on Rust side; logging on Python side
  • Testing: pytest unit smoke + cargo tests; wheels built in CI for 3 OSes

Features

Core Features

  • [OK] Native WebView Integration: Uses system WebView (WebView2/WKWebView/WebKitGTK) for minimal footprint
  • [OK] Bidirectional Communication: Python ↔ JavaScript IPC with async/await support
  • [OK] Custom Protocol Handler: Load resources from DCC projects (auroraview://, custom protocols)
  • [OK] Event System: Node.js-style EventEmitter with on(), once(), off(), emit()
  • [OK] Multi-Window Support: WindowManager for creating/managing multiple windows with cross-window events
  • [OK] Thread-Safe: Rust-guaranteed memory safety and concurrent operations

Storage & Data

  • [OK] localStorage/sessionStorage: Full CRUD operations for web storage
  • [OK] Cookie Management: set/get/delete/clear cookies
  • [OK] Browsing Data: Clear cache, cookies, history with clear_browsing_data()

Window & Navigation

  • [OK] File Dialogs: open_file, save_file, select_folder, select_folders
  • [OK] Message Dialogs: confirm, alert, error, ok_cancel dialogs
  • [OK] Navigation Control: go_back, go_forward, reload, stop, can_go_back/forward
  • [OK] Window Events: on_window_show/hide/focus/blur/resize, on_fullscreen_changed
  • [OK] File Drop Events: Native drag-and-drop with full file paths (file_drop, file_drop_hover, file_paste)
  • [OK] Cancellable Events: Event handlers can cancel events (e.g., prevent window closing)
  • [OK] Event Utilities: Debounce/throttle helpers for high-frequency events

DCC Integration

  • [OK] Lifecycle Management: Automatic cleanup when parent DCC application closes
  • [OK] Qt Backend: QtWebView for seamless Qt-based DCC integration
  • [OK] WebView2 Warmup: Pre-initialize WebView2 for faster DCC startup
  • [OK] Performance Monitoring: get_performance_metrics(), get_ipc_stats()

Desktop Features

  • [OK] System Tray: System tray icon with context menu, hide to tray, click to show
  • [OK] Tool Window: Hide from taskbar/Alt+Tab with tool_window=True (WS_EX_TOOLWINDOW)
  • [OK] Floating Panels: Frameless, transparent windows for AI assistants and tool palettes
  • [OK] Owner Mode: Window follows parent minimize/restore with embed_mode="owner"

Plugin System

  • [OK] Rust Plugin Architecture: High-performance plugin system with IPC
  • [OK] Process Plugin: Run external processes with stdout/stderr streaming
  • [OK] File System Plugin: Native file operations (read, write, copy, move)
  • [OK] Dialog Plugin: Native file/folder dialogs and message boxes
  • [OK] Shell Plugin: Execute commands, open URLs, reveal in file manager
  • [OK] Clipboard Plugin: System clipboard read/write access

Chrome Extension API Compatibility

  • [OK] 25+ Chrome APIs: Full polyfill layer for Chrome Extension APIs
  • [OK] Storage API: chrome.storage.local/sync/session with persistent storage
  • [OK] Bookmarks API: Create, search, update, delete bookmarks
  • [OK] History API: Search and manage browsing history
  • [OK] Downloads API: Download files with progress tracking
  • [OK] Cookies API: Get, set, remove cookies
  • [OK] Notifications API: System notifications with actions
  • [OK] TTS API: Text-to-speech synthesis
  • [OK] Idle/Power API: User activity detection and power management
  • [OK] WXT Framework: Compatible with modern extension development

Gallery Application

  • [OK] Interactive Showcase: React-based gallery demonstrating all features
  • [OK] Example Runner: Run any example with live stdout/stderr output
  • [OK] Category Browser: Organized examples by category with search
  • [OK] Pack Command: Build standalone Gallery executable with auroraview pack

Security

  • [OK] CSP Configuration: Content Security Policy support
  • [OK] CORS Control: Cross-Origin Resource Sharing management
  • [OK] Permission System: Fine-grained permission controls

Quick Start

Installation

Windows and macOS

Basic installation (Native backend only):

pip install auroraview

With Qt support (for Qt-based DCCs like Maya, Houdini, Nuke):

pip install auroraview[qt]

Note for DCC Integration: Qt-based DCC applications (Maya, Houdini, Nuke, 3ds Max) require QtPy as a middleware layer to handle different Qt versions across DCC applications. The [qt] extra installs QtPy automatically.

Linux

Linux wheels are not available on PyPI due to webkit2gtk system dependencies. Install from GitHub Releases:

# Install system dependencies first
sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev  # Debian/Ubuntu
# sudo dnf install gtk3-devel webkit2gtk3-devel      # Fedora/CentOS
# sudo pacman -S webkit2gtk                          # Arch Linux

# Download and install wheel from GitHub Releases
pip install https://github.com/loonghao/auroraview/releases/latest/download/auroraview-{version}-cp37-abi3-linux_x86_64.whl

Or build from source:

pip install auroraview --no-binary :all:

Integration Modes

AuroraView provides three main integration modes for different use cases:

Mode Class Best For Docking Support
Qt Native QtWebView Maya, Houdini, Nuke, 3ds Max βœ… QDockWidget
HWND AuroraView Unreal Engine, non-Qt apps βœ… via HWND API
Standalone run_standalone Desktop applications N/A

WebView vs AuroraView: Choosing the Right API

AuroraView provides three recommended APIs for different use cases:

API Best For Description
QtWebView Maya, Houdini, Nuke, 3ds Max Qt widget with docking support
AuroraView Unreal Engine, non-Qt apps HWND-based for window handle access
run_desktop() Desktop applications One-liner for standalone apps
auroraview.core.WebView Advanced users Low-level API (not recommended)

Example: QtWebView (Qt DCC integration)

from auroraview import QtWebView

# For Maya, Houdini, Nuke, 3ds Max
webview = QtWebView(
    parent=dcc_main_window(),
    url="http://localhost:3000"
)
webview.bind_api(my_api_object)  # Manual API binding
webview.show()

Example: AuroraView (HWND wrapper)

from auroraview import AuroraView

# For Unreal Engine or non-Qt apps
webview = AuroraView(
    url="http://localhost:3000",
    api=my_api_object  # Auto-bound at construction
)
webview.show()

Example: run_desktop (Desktop apps)

from auroraview import run_desktop

# Simplest API - one function call
run_desktop(title="My App", url="http://localhost:3000")

Note: Direct use of auroraview.core.WebView is not recommended for most use cases. Use QtWebView for Qt-based DCC apps or AuroraView for HWND-based apps.

1. Qt Native Mode (QtWebView)

Best for Qt-based DCC applications - Maya, Houdini, Nuke, 3ds Max.

This mode creates a true Qt widget that can be docked, embedded in layouts, and managed by Qt's parent-child system.

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

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

# Create embedded 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 - WebView closes automatically with parent
dialog.show()
webview.show()

Key features:

  • βœ… Works with QDockWidget for dockable panels
  • βœ… Automatic lifecycle management (closes with parent)
  • βœ… Native Qt event integration
  • βœ… Supports all Qt layout managers

2. HWND Mode (AuroraView)

Best for Unreal Engine and non-Qt applications that need direct window handle access.

from auroraview import AuroraView

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

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

Key features:

  • βœ… Direct HWND access via get_hwnd()
  • βœ… Works with any application that accepts HWND
  • βœ… No Qt dependency required
  • βœ… Full control over window positioning

3. Standalone Mode

Best for desktop applications - quick one-liner for standalone apps.

from auroraview import run_standalone

# Launch standalone app (blocks until closed)
run_standalone(
    title="My App",
    url="https://example.com",
    width=1024,
    height=768
)

Key features:

  • βœ… Simplest API - one function call
  • βœ… Automatic event loop management
  • βœ… No parent window required

Quick Start

Desktop App (one-liner):

from auroraview import run_desktop

# Launch standalone app - blocks until closed
run_desktop(title="My App", url="http://localhost:3000")

Maya integration (Qt-based):

from auroraview import QtWebView
import maya.OpenMayaUI as omui

# Create WebView as Qt widget
webview = QtWebView(
    parent=maya_main_window(),
    url="http://localhost:3000",
    width=800,
    height=600
)
webview.show()  # Non-blocking, auto timer

Houdini integration (Qt-based):

from auroraview import QtWebView
import hou

webview = QtWebView(
    parent=hou.qt.mainWindow(),
    url="http://localhost:3000"
)
webview.show()  # Non-blocking, auto timer

Unreal Engine integration (HWND-based):

from auroraview import AuroraView

webview = AuroraView(url="http://localhost:3000")
webview.show()

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

Command-Line Interface

AuroraView includes a CLI for quickly launching WebView windows:

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

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

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

# Using with uvx (no installation required)
uvx auroraview --url https://example.com

Note for Python 3.7 on Windows: Due to a uv/uvx limitation, use python -m auroraview instead:

uvx --python 3.7 --from auroraview python -m auroraview --url https://example.com

See CLI Documentation for more details.

Custom Window Icon

AuroraView displays the default AuroraView icon by default. You can customize it with your own icon:

from auroraview import run_desktop

# Use custom icon
run_desktop(
    title="My App",
    url="http://localhost:3000",
    icon="path/to/my-icon.png"  # Custom icon path
)

Icon Requirements:

Property Recommendation
Format PNG (recommended), ICO, JPEG, BMP, GIF
Size 32Γ—32 (taskbar), 64Γ—64 (alt-tab), 256Γ—256 (high-DPI)
Color Depth 32-bit RGBA for transparency support
Best Practice Use a square image; non-square images will be stretched

Tip: For best results across all Windows UI elements, provide a 32Γ—32 PNG with transparency.

Nuke integration (Qt-based):

from auroraview import QtWebView
from qtpy import QtWidgets

main = QtWidgets.QApplication.activeWindow()
webview = QtWebView(parent=main, url="http://localhost:3000")
webview.show()  # Non-blocking, auto timer

Blender integration (standalone):

from auroraview import run_desktop

# Blender runs standalone (no parent window)
run_desktop(title="Blender Tool", url="http://localhost:3000")

Usage Patterns

AuroraView supports multiple API styles to fit your development workflow. Choose the pattern that best matches your project's complexity and team's preferences.

Pattern 1: AuroraView with API Object (Simplest)

Best for: Quick prototypes, simple tools, one-off scripts

from auroraview import AuroraView

class MyAPI:
    def get_data(self) -> dict:
        """Called from JS: await auroraview.api.get_data()"""
        return {"items": [1, 2, 3], "count": 3}

    def save_file(self, path: str = "", content: str = "") -> dict:
        """Called from JS: await auroraview.api.save_file({path: "/tmp/a.txt", content: "hello"})"""
        with open(path, "w") as f:
            f.write(content)
        return {"ok": True, "path": path}

# Create WebView with API auto-binding
view = AuroraView(url="http://localhost:3000", api=MyAPI())
view.show()

JavaScript side:

// Call API methods (with return value)
const data = await auroraview.api.get_data();
console.log(data.items);  // [1, 2, 3]

const result = await auroraview.api.save_file({ path: "/tmp/test.txt", content: "Hello" });
console.log(result.ok);  // true

// Listen for Python events
auroraview.on("data_updated", (data) => {
    console.log("Data updated:", data);
});

Pattern 2: QtWebView for DCC Integration (Recommended)

Best for: Maya, Houdini, Nuke, 3ds Max integration

from auroraview import QtWebView

class SceneTool(QtWebView):
    """A DCC tool with Qt widget integration."""

    def __init__(self, parent=None):
        super().__init__(
            parent=parent,
            url="http://localhost:3000",
            width=400,
            height=600
        )

    def on_ready(self):
        """Called when WebView is ready."""
        self.emit("tool_ready", {"version": "1.0"})

# Usage in Maya
webview = SceneTool(parent=maya_main_window())
webview.show()

Pattern 3: Advanced - Low-level WebView (For Experts)

Best for: Advanced customization, custom protocols, maximum control

Note: Use auroraview.core.WebView only if you need low-level control. For most use cases, prefer QtWebView or AuroraView.

from auroraview.core import WebView
from auroraview import Signal

class OutlinerTool(WebView):
    """A Maya-style outliner tool demonstrating Qt-like patterns."""

    # Signal Definitions (Python -> JS notifications)
    selection_changed = Signal(list)
    progress_updated = Signal(int, str)
    scene_loaded = Signal(str)

    def __init__(self):
        super().__init__(
            title="Outliner Tool",
            url="http://localhost:3000",
            width=400,
            height=600
        )
        self._setup_api()
        self._setup_connections()

    def _setup_api(self):
        """Bind API methods for JavaScript access."""
        # Bind all public methods of self under "api" namespace
        self.bind_api(self, namespace="api")

    # ─── API Methods (JS β†’ Python) ───
    def get_hierarchy(self, root: str = None) -> dict:
        """Get scene hierarchy. JS: await auroraview.api.get_hierarchy()"""
        return {
            "children": ["group1", "mesh_cube", "camera1"],
            "count": 3
        }

    def rename_object(self, old_name: str = "", new_name: str = "") -> dict:
        """Rename scene object. JS: await auroraview.api.rename_object({old_name: "a", new_name: "b"})"""
        return {"ok": True, "old": old_name, "new": new_name}

    def delete_objects(self, names: list = None) -> dict:
        """Delete objects. JS: await auroraview.api.delete_objects({names: ["obj1", "obj2"]})"""
        names = names or []
        return {"ok": True, "deleted": len(names)}

    # ─── Event Handlers ───
    def _setup_connections(self):
        """Setup event handlers and signal connections."""
        @self.on("item_selected")
        def handle_selection(data: dict):
            items = data.get("items", [])
            self.selection_changed.emit(items)

        @self.on("viewport_orbit")
        def handle_orbit(data: dict):
            dx, dy = data.get("dx", 0), data.get("dy", 0)
            print(f"Orbiting: dx={dx}, dy={dy}")

        # Connect signals to handlers
        self.selection_changed.connect(self._log_selection)

    def _log_selection(self, items: list):
        """Internal handler for selection changes."""
        print(f"Selection changed: {items}")

# Usage
tool = OutlinerTool()
tool.show()

JavaScript side:

// Call API methods
const hierarchy = await auroraview.api.get_hierarchy();
const result = await auroraview.api.rename_object({ old_name: "cube1", new_name: "hero_cube" });

// Send events to Python
auroraview.send_event("item_selected", { items: ["mesh1", "mesh2"] });
auroraview.send_event("viewport_orbit", { dx: 10, dy: 5 });

// Listen for Python signals
auroraview.on("selection_changed", (items) => {
    highlightItems(items);
});

auroraview.on("progress_updated", (percent, message) => {
    updateProgressBar(percent, message);
});

Pattern 3: Explicit Binding (Advanced)

Best for: Dynamic configurations, plugin systems, runtime customization

from auroraview import WebView

view = WebView(title="Plugin Host", url="http://localhost:3000")

# Define functions separately
def get_plugins() -> dict:
    return {"plugins": ["plugin_a", "plugin_b"]}

def load_plugin(name: str) -> dict:
    print(f"Loading plugin: {name}")
    return {"ok": True, "plugin": name}

def on_plugin_event(data: dict):
    print(f"Plugin event: {data}")

# Explicitly bind at runtime
view.bind_call("get_plugins", get_plugins)
view.bind_call("load_plugin", load_plugin)

# Connect to built-in signals
view.on_ready.connect(lambda: print("WebView is ready!"))
view.on_navigate.connect(lambda url: print(f"Navigated to: {url}"))

# Register event handlers
view.register_callback("plugin_event", on_plugin_event)

# Dynamic binding based on configuration
config = {"features": ["export", "import"]}
if "export" in config["features"]:
    view.bind_call("export_data", lambda fmt: {"data": "...", "format": fmt})
if "import" in config["features"]:
    view.bind_call("import_data", lambda data: {"ok": True})

view.show()

JavaScript side:

// Call dynamically bound methods
const plugins = await auroraview.api.get_plugins();
const result = await auroraview.api.load_plugin({ name: "plugin_a" });

// Call feature-specific methods (if enabled)
if (await auroraview.api.export_data) {
    const exported = await auroraview.api.export_data({ fmt: "json" });
}

// Emit events
auroraview.emit("plugin_event", { type: "activated", plugin: "plugin_a" });

Pattern Comparison

Aspect Decorator Class Inheritance Explicit Binding
Complexity ⭐ Simple ⭐⭐ Medium ⭐⭐⭐ Advanced
Best For Prototypes Production Plugins
Signal Support ❌ βœ… Full ⚠️ Limited
Auto-binding ❌ Manual βœ… via bind_api ❌ Manual
Type Hints βœ… βœ… βœ…
Qt Familiarity Low High Medium
Testability Good Excellent Good

Recommendation: Start with Pattern 1 for prototypes, graduate to Pattern 2 for production tools. Use Pattern 3 when building extensible systems.

See the examples/ directory for complete, runnable examples of each pattern.

Advanced Usage

Load HTML content:

from auroraview import WebView

html = """
<!DOCTYPE html>
<html>
<body>
    <h1>Hello from AuroraView!</h1>
    <button onclick="alert('Hello!')">Click Me</button>
</body>
</html>
"""

webview = WebView.create("My App", html=html)
webview.show()

Custom configuration:

from auroraview import WebView

webview = WebView.create(
    title="My App",
    url="http://localhost:3000",
    width=1024,
    height=768,
    resizable=True,
    frame=True,  # Show window frame
    debug=True,  # Enable dev tools
    context_menu=False,  # Disable native context menu for custom menus
)
webview.show()

Embedded mode helper (2025):

from auroraview import WebView

# Convenience helper = create(..., auto_show=True, auto_timer=True)
webview = WebView.run_embedded(
    "My Tool", url="http://localhost:3000", parent=parent_hwnd, mode="owner"
)

Window Events System:

AuroraView provides a comprehensive window event system for tracking window lifecycle:

from auroraview import WebView
from auroraview.core.events import WindowEvent, WindowEventData

webview = WebView(title="My App", width=800, height=600)

# Register window event handlers using decorators
@webview.on_shown
def on_shown(data: WindowEventData):
    print("Window is now visible")

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

@webview.on_blurred
def on_blurred(data: WindowEventData):
    print("Window lost focus")

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

@webview.on_moved
def on_moved(data: WindowEventData):
    print(f"Window moved to ({data.x}, {data.y})")

@webview.on_closing
def on_closing(data: WindowEventData):
    print("Window is closing...")
    return True  # Return True to allow close, False to cancel

# Window control methods
webview.resize(1024, 768)
webview.move(100, 100)
webview.minimize()
webview.maximize()
webview.restore()
webview.toggle_fullscreen()
webview.focus()
webview.hide()

# Read-only window properties
print(f"Size: {webview.width}x{webview.height}")
print(f"Position: ({webview.x}, {webview.y})")

Callback deregistration (EventTimer):

from auroraview import EventTimer

timer = EventTimer(webview, interval_ms=16)

def _on_close(): ...

timer.on_close(_on_close)
# Later, to remove the handler:
timer.off_close(_on_close)  # also available: off_tick(handler)

Shared State (PyWebView-inspired):

AuroraView provides automatic bidirectional state synchronization between Python and JavaScript:

from auroraview import WebView

webview = WebView.create("My App", width=800, height=600)

# Access shared state (dict-like interface)
webview.state["user"] = "Alice"
webview.state["theme"] = "dark"
webview.state["count"] = 0

# Track state changes
@webview.state.on_change
def on_state_change(key: str, value, old_value):
    print(f"State changed: {key} = {value} (was {old_value})")

# In JavaScript:
# window.auroraview.state.user = "Bob";  // Syncs to Python
# console.log(window.auroraview.state.theme);  // "dark"

Command System (Tauri-inspired):

Register Python functions as RPC-style commands callable from JavaScript:

from auroraview import WebView

webview = WebView.create("My App", width=800, height=600)

# Register commands using decorator
@webview.command
def greet(name: str) -> str:
    return f"Hello, {name}!"

@webview.command("add_numbers")
def add(x: int, y: int) -> int:
    return x + y

# In JavaScript:
# const msg = await auroraview.invoke("greet", {name: "World"});
# const sum = await auroraview.invoke("add_numbers", {x: 1, y: 2});

Channel Streaming:

Stream large data from Python to JavaScript using channels:

from auroraview import WebView

webview = WebView.create("My App", width=800, height=600)

# Create a channel for streaming data
with webview.create_channel() as channel:
    for i in range(100):
        channel.send({"progress": i, "data": f"chunk_{i}"})

# In JavaScript:
# const channel = auroraview.channel("channel_id");
# channel.onMessage((data) => console.log("Received:", data));
# channel.onClose(() => console.log("Stream complete"));

Custom Protocol Handlers (Solve CORS Issues):

AuroraView provides custom protocol handlers to load local resources without CORS restrictions:

from auroraview import WebView

# 1. Built-in auroraview:// protocol for static assets
webview = WebView.create(
    title="My App",
    asset_root="C:/projects/my_app/assets"  # Enable auroraview:// protocol
)

# Now you can use auroraview:// in HTML
html = """
<html>
    <head>
        <link rel="stylesheet" href="auroraview://css/style.css">
    </head>
    <body>
        <img src="auroraview://icons/logo.png">
        <script src="auroraview://js/app.js"></script>
    </body>
</html>
"""
webview.load_html(html)

# 2. Register custom protocols for DCC-specific resources
def handle_fbx_protocol(uri: str) -> dict:
    """Load FBX files from Maya project"""
    path = uri.replace("fbx://", "")
    full_path = f"C:/maya_projects/current/{path}"

    try:
        with open(full_path, "rb") as f:
            return {
                "data": f.read(),
                "mime_type": "application/octet-stream",
                "status": 200
            }
    except FileNotFoundError:
        return {
            "data": b"Not Found",
            "mime_type": "text/plain",
            "status": 404
        }

webview.register_protocol("fbx", handle_fbx_protocol)

# Now you can use fbx:// in JavaScript
# fetch('fbx://models/character.fbx').then(r => r.arrayBuffer())

Benefits:

  • βœ… No CORS restrictions (unlike file:// URLs)
  • βœ… Clean URLs (auroraview://logo.png vs file:///C:/long/path/logo.png)
  • βœ… Security (limited to configured directories)
  • βœ… Cross-platform path handling

Custom Protocol Best Practices

Automatic URL Conversion

AuroraView automatically converts local file paths and file:// URLs to the custom protocol format. This ensures consistent handling across all platforms.

Source Input Converted URL
file:// URL file:///C:/path/to/file.html https://auroraview.localhost/type:file/C:/path/to/file.html
Local path C:/path/to/file.html https://auroraview.localhost/type:local/C:/path/to/file.html
Unix path /path/to/file.html https://auroraview.localhost/type:local/path/to/file.html

The type: prefix distinguishes the source of the path for debugging and logging:

  • type:file - Converted from file:// URLs
  • type:local - Converted from local file paths

Usage:

from auroraview import WebView

# All these are automatically converted to auroraview protocol
webview = WebView.create("My App")

# Load from file:// URL
webview.load_url("file:///C:/projects/app/index.html")
# β†’ https://auroraview.localhost/type:file/C:/projects/app/index.html

# Load from local path (Windows)
webview.load_url("C:/projects/app/index.html")
# β†’ https://auroraview.localhost/type:local/C:/projects/app/index.html

# Load from local path (Unix)
webview.load_url("/home/user/app/index.html")
# β†’ https://auroraview.localhost/type:local/home/user/app/index.html

Platform-Specific URL Format

The auroraview:// protocol uses different URL formats on each platform:

Platform URL Format Example
Windows https://auroraview.localhost/path https://auroraview.localhost/index.html
macOS auroraview://path auroraview://index.html
Linux auroraview://path auroraview://index.html

Note: On Windows, wry (the underlying WebView library) maps custom protocols to HTTP/HTTPS format. We use .localhost as the host for security reasons.

Why .localhost is Secure

The .localhost TLD provides strong security guarantees:

  1. IANA Reserved - .localhost is a reserved TLD (RFC 6761) that cannot be registered by anyone
  2. Local Only - Browsers treat .localhost as a local address (127.0.0.1)
  3. Pre-DNS Interception - Our protocol handler intercepts requests BEFORE DNS resolution
  4. No Network Traffic - Requests never leave the local machine

Comparing Local Resource Loading Methods

Method Security Recommendation
auroraview:// with asset_root βœ… High - Access restricted to specified directory Recommended
allow_file_protocol=True ⚠️ Low - Access to ANY file on system Use with caution
HTTP server βœ… High - Controlled access Good for development

Recommended approach (using asset_root with relative paths):

WebView.create()run_standalone()
from auroraview import WebView

# Secure: Only files under assets/ are accessible
webview = WebView.create(
    title="My App",
    asset_root="./assets",
)

# Use relative paths in HTML - they resolve to asset_root
html = """
<html>
<body>
    <img src="./images/logo.png">
    <img src="./images/animation.gif">
</body>
</html>
"""
webview.load_html(html)
from auroraview import run_standalone

# Secure: Only files under assets/ are accessible
# Use relative paths - they resolve to asset_root
html = """
<html>
<body>
    <img src="./images/logo.png">
    <img src="./images/animation.gif">
</body>
</html>
"""

run_standalone(
    title="My App",
    html=html,
    asset_root="./assets",
)

Less secure approach (using file:// protocol):

WebView.create()run_standalone()
from auroraview import WebView
from auroraview import path_to_file_url

# ⚠️ Warning: Allows access to ANY file
gif_url = path_to_file_url("C:/path/to/animation.gif")

webview = WebView.create(
    title="My App",
    allow_file_protocol=True,
)

html = f'<img src="{gif_url}">'
webview.load_html(html)
from auroraview import run_standalone
from auroraview import path_to_file_url

# ⚠️ Warning: Allows access to ANY file
gif_url = path_to_file_url("C:/path/to/animation.gif")

html = f'<img src="{gif_url}">'

run_standalone(
    title="My App",
    html=html,
    allow_file_protocol=True,
)

Note: The path_to_file_url() helper converts local paths to proper file:/// URLs. Example: C:\images\logo.gif β†’ file:///C:/images/logo.gif

See examples/custom_protocol_example.py and examples/local_assets_example.py for complete examples.

2. Qt Backend

Integrates as a Qt widget for seamless integration with Qt-based DCCs. Requires pip install auroraview[qt].

from auroraview import QtWebView

# Create WebView as Qt widget
webview = QtWebView(
    parent=maya_main_window(),  # Any QWidget (optional)
    title="My Tool",
    width=800,
    height=600
)

# Load content
webview.load_url("http://localhost:3000")
# Or load HTML
webview.load_html("<html><body><h1>Hello from Qt!</h1></body></html>")

# Show the widget
webview.show()

# ✨ Event processing is automatic - no need to call process_events()!
# The Qt backend automatically handles all JavaScript execution and events

WebView2 Pre-warming (Automatic)

QtWebView automatically pre-warms WebView2 on first instantiation, reducing subsequent creation time by ~50%. No manual setup required:

from auroraview.integration.qt import QtWebView

# First QtWebView automatically triggers pre-warming
webview = QtWebView(parent=maya_main_window())
webview.load_url("http://localhost:3000")
webview.show()

For advanced users who want explicit control over pre-warming timing:

from auroraview.integration.qt import WebViewPool, QtWebView

# Explicit pre-warm at DCC startup (e.g., in userSetup.py)
WebViewPool.prewarm()

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

# Disable auto-prewarm if using explicit control
webview = QtWebView(parent=maya_main_window(), auto_prewarm=False)

# Cleanup when done (optional, called automatically on exit)
WebViewPool.cleanup()

Benefits:

  • βœ… Automatic pre-warming on first QtWebView creation
  • βœ… Reduces WebView creation time by ~50%
  • βœ… Thread-safe and idempotent (safe to call multiple times)
  • βœ… Automatic cleanup on application exit

When to use Qt backend:

  • [OK] Your DCC already has Qt loaded (Maya, Houdini, Nuke)
  • [OK] You want seamless Qt widget integration
  • [OK] You need to use Qt layouts and signals/slots
  • [OK] You want automatic event processing (no manual process_events() calls)

When to use Native backend:

  • [OK] Maximum compatibility across all platforms
  • [OK] Standalone applications
  • [OK] DCCs without Qt (Blender, 3ds Max)
  • [OK] Minimal dependencies

Bidirectional Communication

AuroraView provides a complete bidirectional communication system between Python and JavaScript.

Communication API Overview

Direction JavaScript API Python API Use Case
JS β†’ Python auroraview.call(method, params) @webview.bind_call RPC with return value
JS β†’ Python auroraview.send_event(event, data) @webview.on(event) Fire-and-forget events
Python β†’ JS - webview.emit(event, data) Push notifications
JS only auroraview.on(event, handler) - Receive Python events
JS only auroraview.trigger(event, data) - Local JS events (not sent to Python)

Important: auroraview.trigger() is for JavaScript-side local events only. To send events to Python, use auroraview.send_event().

Python β†’ JavaScript (Push Events)

# Python side: emit events to JavaScript
webview.emit("update_data", {"frame": 120, "objects": ["cube", "sphere"]})
webview.emit("selection_changed", {"items": ["mesh1", "mesh2"]})
// JavaScript side: listen for Python events
window.auroraview.on('update_data', (data) => {
    console.log('Frame:', data.frame);
    console.log('Objects:', data.objects);
});

window.auroraview.on('selection_changed', (data) => {
    highlightItems(data.items);
});

JavaScript β†’ Python (Events)

// JavaScript side: send events to Python
window.auroraview.send_event('export_scene', {
    path: '/path/to/export.fbx',
    format: 'fbx'
});

window.auroraview.send_event('viewport_orbit', { dx: 10, dy: 5 });
# Python side: register event handlers
@webview.on("export_scene")
def handle_export(data):
    print(f"Exporting to: {data['path']}")
    # Your DCC export logic here

@webview.on("viewport_orbit")
def handle_orbit(data):
    rotate_camera(data['dx'], data['dy'])

JavaScript β†’ Python (RPC with Return Value)

For request-response patterns, use auroraview.call() with bind_call:

// JavaScript side: call Python method and get result
const hierarchy = await auroraview.call('api.get_hierarchy', { root: 'scene' });
console.log('Scene hierarchy:', hierarchy);

const result = await auroraview.call('api.rename_object', {
    old_name: 'cube1',
    new_name: 'hero_cube'
});
if (result.ok) {
    console.log('Renamed successfully');
}
# Python side: bind callable methods
@webview.bind_call("api.get_hierarchy")
def get_hierarchy(root=None):
    # Return value is sent back to JavaScript
    return {"children": ["group1", "mesh_cube"], "count": 2}

@webview.bind_call("api.rename_object")
def rename_object(old_name, new_name):
    # Perform rename in DCC
    cmds.rename(old_name, new_name)
    return {"ok": True, "old": old_name, "new": new_name}

Common Mistakes

// WRONG: trigger() is JS-local only, won't reach Python
auroraview.trigger('my_event', data);  // Python won't receive this!

// WRONG: dispatchEvent is browser API, won't reach Python
window.dispatchEvent(new CustomEvent('my_event', {detail: data}));  // Python won't receive!

// CORRECT: use send_event() for fire-and-forget
auroraview.send_event('my_event', data);  // Python receives via @webview.on()

// CORRECT: use call() for request-response
const result = await auroraview.call('api.my_method', data);  // Python receives via @webview.bind_call()

Advanced Features

Lifecycle Management

Automatically close WebView when parent DCC application closes:

from auroraview import WebView

# Get parent window handle (HWND on Windows)
parent_hwnd = get_maya_main_window_hwnd()  # Your DCC-specific function

webview = WebView(
    title="My Tool",
    width=800,
    height=600,
    parent_hwnd=parent_hwnd,  # Monitor this parent window
    parent_mode="owner"  # Use owner mode for cross-thread safety
)

webview.show()
# WebView will automatically close when parent window is destroyed

Third-Party Website Integration

Inject JavaScript into third-party websites and establish bidirectional communication:

from auroraview import WebView

webview = WebView(title="AI Chat", width=1200, height=800, dev_tools=True)

# Register event handlers
@webview.on("get_scene_info")
def handle_get_scene_info(data):
    # Get DCC scene data
    selection = maya.cmds.ls(selection=True)
    webview.emit("scene_info_response", {"selection": selection})

@webview.on("execute_code")
def handle_execute_code(data):
    # Execute AI-generated code in DCC
    code = data.get("code", "")
    exec(code)
    webview.emit("execution_result", {"status": "success"})

# Load third-party website
webview.load_url("https://ai-chat-website.com")

# Inject custom JavaScript
injection_script = """
(function() {
    // Add custom button to the page
    const btn = document.createElement('button');
    btn.textContent = 'Get DCC Selection';
    btn.onclick = () => {
        window.dispatchEvent(new CustomEvent('get_scene_info', {
            detail: { timestamp: Date.now() }
        }));
    };
    document.body.appendChild(btn);

    // Listen for responses
    window.addEventListener('scene_info_response', (e) => {
        console.log('DCC Selection:', e.detail);
    });
})();
"""

import time
time.sleep(1)  # Wait for page to load
webview.eval_js(injection_script)

webview.show()

For detailed guide, see Third-Party Integration Guide.

System Tray Support

Create desktop applications with system tray integration:

from auroraview import run_desktop

# Launch app with system tray support
run_desktop(
    title="My Background App",
    html=my_html,
    width=400,
    height=300,
    system_tray=True,  # Enable system tray
    hide_on_close=True,  # Minimize to tray instead of closing
)

Floating Tool Windows

Create floating panels for AI assistants or tool palettes:

from auroraview import WebView

# Create a floating tool window
webview = WebView.create(
    title="AI Assistant",
    html=panel_html,
    width=320,
    height=400,
    frame=False,  # Frameless window
    transparent=True,  # Transparent background
    always_on_top=True,  # Keep on top
    tool_window=True,  # Hide from taskbar/Alt+Tab
    parent=parent_hwnd,  # Optional: follow parent window
    mode="owner",  # Window follows parent minimize/restore
)
webview.show()

Gallery Application

AuroraView includes an interactive Gallery showcasing all features:

# Run the Gallery
just gallery

# Or build a standalone Gallery executable
just gallery-pack

The Gallery provides:

  • Interactive example browser with categories
  • Live example runner with stdout/stderr streaming
  • Settings panel for runtime configuration
  • Search functionality across all examples

Install CLI

Install auroraview-cli using the install script:

Linux/macOS (bash):

curl -fsSL https://raw.githubusercontent.com/loonghao/auroraview/main/scripts/install.sh | bash

Windows (PowerShell):

irm https://raw.githubusercontent.com/loonghao/auroraview/main/scripts/install.ps1 | iex

Manual Download:

Download pre-built binaries from GitHub Releases.

Platform Download
Windows x64 auroraview-cli-{version}-x86_64-pc-windows-msvc.zip
Linux x64 auroraview-cli-{version}-x86_64-unknown-linux-gnu.tar.gz
macOS x64 auroraview-cli-{version}-x86_64-apple-darwin.tar.gz
macOS ARM64 auroraview-cli-{version}-aarch64-apple-darwin.tar.gz

Build from source:

cargo build -p auroraview-cli --release

Application Packaging

AuroraView provides a powerful packaging system to create standalone executables. Use auroraview-cli (Rust CLI) for packaging:

# Pack a URL-based application
auroraview-cli pack --url https://example.com --output myapp

# Pack a frontend project (React, Vue, etc.)
auroraview-cli pack --frontend ./dist --output myapp

# Pack a fullstack application (frontend + Python backend)
auroraview-cli pack --config auroraview.pack.toml

Configuration file example (auroraview.pack.toml):

[package]
name = "my-app"
version = "1.0.0"

[app]
title = "My Application"
frontend_path = "./dist"

[window]
width = 1200
height = 800
resizable = true

[bundle]
# Unified icon configuration (supports PNG, JPG, ICO)
# PNG/JPG: Auto-converted to multi-resolution ICO (16-256px) for Windows
# ICO: Auto-extracts PNG for window title bar icon
# Recommended: Use 256x256 or larger PNG for best quality
icon = "./assets/my-app-icon.png"

# Windows-specific configuration
# Note: Use [bundle.platform.windows] NOT [bundle.windows]!
# This clearly separates [window] (runtime behavior) from platform bundling
[bundle.platform.windows]
# Hide console window (no black command prompt window)
# console = false (default) -> GUI application, no console
# console = true -> Console application, shows black window
console = false
# Optional: Override with specific ICO file (if auto-conversion not desired)
# icon = "./assets/my-app-icon.ico"

[python]
entry_point = "main:main"
include_paths = ["./backend"]
strategy = "standalone"  # Embeds Python runtime for offline use

Note: The unified icon configuration automatically handles format conversion - just provide a single PNG image and it will be used for both the Windows executable icon (converted to multi-resolution ICO) and the window title bar icon. See examples/pack-example.toml for a complete configuration example.

CLI Options for Icon and Console:

# Specify custom icon via CLI (supports PNG, JPG, ICO)
auroraview pack --config app.toml --icon ./my-icon.png --build

# Force show console (for debugging)
auroraview pack --config app.toml --console --build

# Force hide console (override manifest)
auroraview pack --config app.toml --no-console --build

Bundle Strategies:

Strategy Offline Size Description
standalone (default) Yes ~50-80MB Embeds Python runtime, extracts on first run
embedded No ~15MB Requires system Python
portable Yes ~50-80MB Directory structure with Python
pyoxidizer Yes ~30-50MB Requires PyOxidizer installed

Key Features:

  • Single executable distribution
  • Embedded Python runtime (no system Python required)
  • First-run extraction to user cache directory
  • Environment variable injection
  • License/token validation support
  • Custom hooks for additional files

Documentation

DCC Software Support

DCC Software Status Python Version Example
Maya [OK] Supported 3.7+ Maya Outliner Example
3ds Max [OK] Supported 3.7+ -
Houdini [OK] Supported 3.7+ -
Blender [OK] Supported 3.7+ -
Photoshop [CONSTRUCTION] Planned 3.7+ -
Unreal Engine [CONSTRUCTION] Planned 3.7+ -

πŸ“š Examples: For a complete working example, check out the Maya Outliner Example - a modern, web-based Maya Outliner built with AuroraView, Vue 3, and TypeScript.

Development

Prerequisites

  • Rust 1.75+
  • Python 3.7+
  • Node.js 18+ (for examples)

Build from Source

# Clone the repository
git clone https://github.com/loonghao/auroraview.git
cd auroraview

# Install Rust dependencies and build
cargo build --release

# Install Python package in development mode
pip install -e .

Run Tests

# Rust tests
cargo test

# Python tests
pytest tests/

Project Structure

auroraview/
β”œβ”€β”€ src/                    # Rust core library
β”œβ”€β”€ python/                 # Python bindings
β”œβ”€β”€ tests/                  # Test suites
β”œβ”€β”€ docs/                   # Documentation
└── benches/                # Performance benchmarks

Testing

AuroraView provides a comprehensive testing framework with multiple backends for different testing scenarios.

HeadlessWebView - Unified Testing Framework

AuroraView includes a unified headless testing framework that supports multiple backends:

from auroraview.testing import HeadlessWebView

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

# Or explicitly use Playwright backend
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 Recommended for CI/CD
Xvfb HeadlessWebView.virtual_display() Linux Real WebView testing
WebView2 CDP HeadlessWebView.webview2_cdp(url) Windows Real WebView2 testing

Features:

  • Unified API across all backends
  • Automatic backend selection with HeadlessWebView.auto()
  • Full Playwright API access (locators, screenshots, network interception)
  • Pytest fixtures included
  • CI/CD ready

Requirements: pip install playwright && playwright install chromium

Pytest Integration

import pytest
from auroraview.testing import HeadlessWebView

# Using context manager
def test_basic_navigation():
    with HeadlessWebView.playwright() as webview:
        webview.goto("https://example.com")
        assert "Example" in webview.title()

# Using pytest fixture
def test_with_fixture(headless_webview):
    headless_webview.load_html("<button id='btn'>Click</button>")
    headless_webview.click("#btn")

Running Tests

# Using nox (recommended)
uvx nox -s pytest          # Test without Qt
uvx nox -s pytest-qt       # Test with Qt
uvx nox -s pytest-all      # Run all tests

# Or using pytest directly
uv run pytest tests/python/ -v

# Run headless WebView tests
uv run pytest tests/python/integration/test_headless_webview.py -v

CI/CD Configuration

# GitHub Actions example
- name: Install dependencies
  run: |
    pip install playwright
    playwright install chromium

- name: Run tests
  run: pytest tests/ -v

Available Nox Sessions

uvx nox -l                 # List all sessions
uvx nox -s pytest          # Test without Qt
uvx nox -s pytest-qt       # Test with Qt
uvx nox -s pytest-all      # Run all tests
uvx nox -s lint            # Run linting
uvx nox -s coverage        # Generate coverage report

Contributing

Contributions are welcome! Please read our Contributing Guide for details.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • Wry - Cross-platform WebView library
  • PyO3 - Rust bindings for Python
  • Tauri - Inspiration and ecosystem

Contact

About

A blazingly fast, lightweight WebView framework for DCC (Digital Content Creation) software, built with Rust and Python bindings.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •