Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:05:02 +08:00
commit 265175ed82
23 changed files with 3329 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
# Async Programming in Vuer
## Overview
Vuer supports asynchronous programming patterns for handling parallel routines and callbacks. The tutorial demonstrates creating a server with background tasks running concurrently.
## Key Components
### Server Setup
The framework uses `Vuer()` to instantiate a server with configuration options via query parameters like `reconnect=True` and `collapseMenu=True`.
### Main Function Decorator
The `@app.spawn(start=True)` decorator marks the entry point as an async function that starts the application immediately.
### Task Management
Sessions provide `spawn_task()` method for launching background operations. Tasks can be cancelled with `.cancel()` when no longer needed.
## Code Pattern Example
The tutorial shows a main loop that:
- Spawns independent background tasks
- Updates scene objects continuously using `sess.upsert`
- Manages task lifecycle by cancelling long-running operations after conditions are met
- Uses `await sleep()` for non-blocking delays
## Complete Example
```python
from vuer import Vuer
from vuer.schemas import Scene, Box
import asyncio
import numpy as np
app = Vuer(
queries=dict(
reconnect=True,
collapseMenu=True,
),
)
async def background_task(session):
"""A background task that runs independently"""
count = 0
while True:
print(f"Background task running: {count}")
count += 1
await asyncio.sleep(1.0)
@app.spawn(start=True)
async def main(session):
# Spawn a background task
task = session.spawn_task(background_task(session))
# Main animation loop
for i in range(100):
theta = i * 0.1
x = 0.5 * np.cos(theta)
z = 0.5 * np.sin(theta)
# Update the box position
session.upsert @ Box(
args=[0.1, 0.1, 0.1],
position=[x, 0.05, z],
color="red",
materialType="standard",
key="animated-box",
)
await asyncio.sleep(0.05)
# Cancel the background task when done
task.cancel()
app.run()
```
## Practical Features
The demonstration animates a red box moving in a circular path while background tasks execute independently, illustrating how multiple asynchronous operations coexist within a single VuerSession without blocking the main rendering loop.
## Best Practices
1. **Use `session.spawn_task()`** for background operations
2. **Always use `await asyncio.sleep()`** for delays to avoid blocking
3. **Cancel tasks** when they're no longer needed to free resources
4. **Use `session.upsert`** for updating scene components
## Source
Documentation: https://docs.vuer.ai/en/latest/tutorials/basics/async_programming.html

View File

@@ -0,0 +1,145 @@
# Serving Dynamic HTML Content in Vuer
## Overview
Vuer allows you to serve dynamic content by adding custom route handlers to your application server.
## Implementation Method
You can register a dynamic HTML handler using the `add_route()` method.
## Basic Example
```python
from vuer import Vuer
app = Vuer()
counter = 0
def dynamic_html_handler():
global counter
counter += 1
template = f"""
<!DOCTYPE html>
<html>
<head><title>Dynamic HTML</title></head>
<body>
<h1>Counter Value: {counter}</h1>
</body>
</html>
"""
return template
app.add_route("/dynamic", dynamic_html_handler, method="GET")
app.run()
```
## Usage
After starting the server, visit `http://localhost:8012/dynamic` to see the dynamically generated content. The counter value will update on each page reload.
## Key Parameters
- **Route path**: Specify the URL endpoint (e.g., "/dynamic")
- **Handler function**: Returns HTML content as a string
- **HTTP method**: Specify the request method (e.g., "GET")
## Advanced Example with JSON Response
```python
from vuer import Vuer
import json
app = Vuer()
def json_api_handler():
data = {
"status": "success",
"data": {
"message": "Hello from Vuer!",
"timestamp": time.time()
}
}
return json.dumps(data)
app.add_route("/api/data", json_api_handler, method="GET")
app.run()
```
## Multiple Routes
You can add multiple routes to your application:
```python
from vuer import Vuer
app = Vuer()
def home_handler():
return "<h1>Home Page</h1>"
def about_handler():
return "<h1>About Page</h1>"
def api_handler():
return '{"status": "ok"}'
app.add_route("/", home_handler, method="GET")
app.add_route("/about", about_handler, method="GET")
app.add_route("/api/status", api_handler, method="GET")
app.run()
```
## Best Practices
1. **Return strings**: Handler functions should return HTML or text as strings
2. **Use templates**: Consider using template engines for complex HTML
3. **Handle errors**: Add error handling in your route handlers
4. **Set content types**: For JSON responses, consider setting appropriate headers
## Combining with 3D Scenes
You can serve both dynamic HTML content and 3D scenes from the same Vuer application:
```python
from vuer import Vuer
from vuer.schemas import Scene, Box
import asyncio
app = Vuer()
# Add dynamic HTML route
def stats_handler():
return f"""
<html>
<body>
<h1>Vuer Statistics</h1>
<p>Server running on port 8012</p>
</body>
</html>
"""
app.add_route("/stats", stats_handler, method="GET")
# Add 3D scene
@app.spawn
async def main(session):
session.set @ Scene(
Box(
args=[0.1, 0.1, 0.1],
position=[0, 0, 0],
key="box",
),
)
while True:
await asyncio.sleep(1.0)
app.run()
```
## Source
Documentation: https://docs.vuer.ai/en/latest/tutorials/basics/adding_html_handler.html

View File

@@ -0,0 +1,111 @@
# Setting Up Your First Scene in Vuer
## Overview
This tutorial guides you through creating a basic 3D scene using Vuer, a Python framework for building interactive 3D visualizations. The example demonstrates how to establish a server, add scene components, lighting, and interactive elements.
## Step 1: Initialize the Vuer Server
Begin by importing and instantiating the application:
```python
from vuer import Vuer
app = Vuer(
queries=dict(
reconnect=True,
collapseMenu=True,
),
)
```
The queries parameter configures the scene via URL parameters. Launch the server with `app.run()`, which produces output showing the local connection URL.
## Step 2: Create an Async Session
The framework uses WebSocket sessions to connect clients with the Python server. Bind an async function to handle each session using the spawn decorator:
```python
@app.spawn
async def session(sess: VuerSession):
print("Example: we have started a websocket session!")
```
## Step 3: Build Your Scene
Within the session, construct the scene by setting Scene objects containing various components:
```python
sess.set @ Scene(
Box(
args=[0.1, 0.1, 0.1, 101, 101, 101],
position=[0, 0.05, 0],
color="red",
materialType="standard",
material=dict(color="#23aaff"),
key="fox-1",
),
...
)
```
## Key Components
### Box
A 3D cube primitive with position, color, and material properties.
### SpotLight
Provides directional lighting within the scene, wrapped in a Movable component to allow interactive repositioning.
### Movable
Enables user interaction, allowing scene elements to be dragged and manipulated in the 3D viewport.
## Essential Pattern
Always include `await asyncio.sleep(0.0)` after scene modifications to ensure proper asynchronous handling and client synchronization.
## Complete Example
```python
from vuer import Vuer
from vuer.schemas import Scene, Box, SpotLight, Movable
import asyncio
app = Vuer(
queries=dict(
reconnect=True,
collapseMenu=True,
),
)
@app.spawn
async def session(sess):
print("Example: we have started a websocket session!")
sess.set @ Scene(
Box(
args=[0.1, 0.1, 0.1, 101, 101, 101],
position=[0, 0.05, 0],
color="red",
materialType="standard",
material=dict(color="#23aaff"),
key="fox-1",
),
Movable(
SpotLight(
intensity=3.0,
distance=10.0,
decay=0.0,
position=[0, 2, 0],
key="spotlight",
),
),
)
await asyncio.sleep(0.0)
app.run()
```
## Source
Documentation: https://docs.vuer.ai/en/latest/tutorials/basics/setting_a_scene.html

View File

@@ -0,0 +1,102 @@
# Vuer Component Life Cycle
## Core Concept
This tutorial demonstrates the basic **CRUD operations** for components in Vuer: adding a component, updating in-place, and removing.
## Life Cycle Operations
### 1. Adding Components
Create new components using `session.upsert`:
```python
session.upsert @ Obj(
src="/static/model.obj",
position=[0, 0, 0],
key="my-model",
)
```
### 2. Updating Components
Modify existing components by reusing the same key:
```python
session.upsert @ Obj(
src="/static/model.obj",
position=[1, 0, 0], # Changed position
key="my-model", # Same key updates the existing component
)
```
### 3. Removing Components
Delete components with `session.remove`:
```python
session.remove @ "my-model"
```
## Complete Example
```python
from vuer import Vuer
from vuer.schemas import Obj
import asyncio
app = Vuer()
@app.spawn
async def main(session):
# Create/Update: Add a wireframe mesh
for i in range(80):
wireframe = i % 2 == 0
# Toggle wireframe on and off
session.upsert @ Obj(
src="/static/model.obj",
position=[0, 0, 0],
wireframe=wireframe,
key="primary-mesh",
)
await asyncio.sleep(0.01)
# Add a second component
session.upsert @ Obj(
src="/static/model.obj",
position=[1, 0, 0],
wireframe=True,
key="secondary-mesh",
)
await asyncio.sleep(0.8)
# Remove the second component
session.remove @ "secondary-mesh"
# Keep the session alive
while True:
await asyncio.sleep(1.0)
app.run()
```
## Key Patterns
### Using Keys
- **Unique keys** identify components in the scene
- **Reusing a key** updates the existing component
- **Different keys** create new components
### Update Frequency
The example toggles wireframe every 0.01 seconds (100 times per second), demonstrating how Vuer handles rapid updates efficiently.
### Timing
Components can be added and removed at any time during the session, allowing for dynamic scene management.
## Visual Effect
This creates an animated effect showing two mesh versions (solid and wireframe) alternating visibility, demonstrating how components can be dynamically managed throughout an application's runtime.
## Source
Documentation: https://docs.vuer.ai/en/latest/tutorials/basics/simple_life_cycle.html

View File

@@ -0,0 +1,121 @@
# Setting Up SSL Proxy for WebXR
## Overview
Vuer requires secure connections for WebXR functionality. Both the web client and WebSocket connections must use TLS/SSL encryption.
## Key Configuration Points
### WebSocket Endpoint Setup
Pass the secure WebSocket URL via query parameter to the web client:
```
https://vuer.ai?ws=wss://xxxxx.ngrok.io
```
### Static File Serving
Update component source paths to use the correct HTTPS domain. For example, change:
```python
# Before (insecure)
src='http://localhost:8012/static/urdf/robot.urdf'
```
To:
```python
# After (secure)
src='https://<your-domain-with-ssl>/static/urdf/robot.urdf'
```
## Recommended Proxy Solutions
### Option 1: ngrok (Recommended)
ngrok converts local HTTP/WebSocket connections to secure HTTPS/WSS:
- `ws://localhost:8012``wss://xxxx.ngrok.io`
- `http://localhost:8012/static/``https://xxxx.ngrok.io/static/`
**Installation:**
Visit [ngrok's website](https://ngrok.com) for installation instructions.
**Usage:**
```bash
ngrok http 8012
```
This will provide a secure URL like `https://xxxx.ngrok.io` that you can use for WebXR.
### Option 2: localtunnel
Free alternative requiring a passcode.
**Installation:**
```bash
npm install -g localtunnel
```
**Usage:**
```bash
lt --port 8012
```
**Documentation:** https://localtunnel.me
### Option 3: Let's Encrypt Self-Signed Certificate
Generate and use your own SSL certificate.
**Launch Vuer with Certificate:**
```bash
vuer --cert cert.pem --key key.pem --port 8012
```
**Generate Certificate:**
Follow Let's Encrypt's localhost certificate guide for implementation details.
## Complete Example with ngrok
```python
from vuer import Vuer
from vuer.schemas import Scene, Urdf
app = Vuer()
@app.spawn
async def main(session):
# Use the ngrok HTTPS domain for static files
session.set @ Scene(
Urdf(
src='https://xxxx.ngrok.io/static/urdf/robot.urdf',
position=[0, 0, 0],
key="robot",
),
)
while True:
await asyncio.sleep(1.0)
app.run()
```
Then access your app at:
```
https://vuer.ai?ws=wss://xxxx.ngrok.io
```
## Troubleshooting
### WebSocket Connection Fails
- Ensure you're using `wss://` (not `ws://`)
- Verify the ngrok tunnel is running
- Check firewall settings
### Static Files Not Loading
- Confirm HTTPS domain is correct
- Verify static files are being served
- Check browser console for mixed content warnings
## Source
Documentation: https://docs.vuer.ai/en/latest/tutorials/basics/ssl_proxy_webxr.html