Skip to content

Commit b2510e7

Browse files
committed
feat: create WebXR core components and integration files for VR experience
1 parent 1641863 commit b2510e7

21 files changed

+5356
-4
lines changed

index.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,25 @@ import { JSDOM } from 'jsdom';
1212
import PptxGenJS from 'pptxgenjs';
1313
import TurndownService from 'turndown';
1414

15+
// Import the WebXR integration
16+
import { integrateWebXR } from './webxr/hono-integration.js';
17+
1518
// Load environment variables
1619
dotenvFlow.config();
1720

1821
const __dirname = path.dirname(fileURLToPath(import.meta.url));
1922
const app = new Hono();
2023

24+
// Integrate WebXR experience at /webxr path
25+
integrateWebXR(app);
26+
2127
// SPA routing middleware - all routes without extensions go to index.html
2228
app.use('*', async (c, next) => {
2329
const url = new URL(c.req.url);
2430
const pathname = url.pathname;
2531

26-
// Skip API routes
27-
if (pathname.startsWith('/api/')) {
32+
// Skip API routes and WebXR routes
33+
if (pathname.startsWith('/api/') || pathname.startsWith('/webxr/')) {
2834
return next();
2935
}
3036

@@ -55,8 +61,8 @@ app.get('*', async (c) => {
5561

5662
console.log(`Fallback handler for: ${pathname}`);
5763

58-
// If we got here and it's not an API route or a file with extension, serve index.html
59-
if (!pathname.startsWith('/api/') && !pathname.includes('.')) {
64+
// If we got here and it's not an API route, WebXR route, or a file with extension, serve index.html
65+
if (!pathname.startsWith('/api/') && !pathname.startsWith('/webxr/') && !pathname.includes('.')) {
6066
const indexPath = path.join(__dirname, 'public', 'index.html');
6167
try {
6268
const indexContent = await fs.readFile(indexPath, 'utf-8');
@@ -403,5 +409,6 @@ serve({
403409
console.log(`- HTML to PowerPoint endpoint: http://localhost:${info.port}/api/1/html-to-ppt`);
404410
console.log(`- HTML to Markdown endpoint: http://localhost:${info.port}/api/1/html-to-markdown`);
405411
console.log(`- Markdown to HTML endpoint: http://localhost:${info.port}/api/1/markdown-to-html`);
412+
console.log(`- WebXR Experience: http://localhost:${info.port}/webxr`);
406413
console.log(`- Web interface: http://localhost:${info.port}`);
407414
});

webxr/README.md

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
# Generic WebXR Experience
2+
3+
A flexible and reusable WebXR boilerplate that can be easily forked and customized for various VR projects.
4+
5+
## Features
6+
7+
- **VR Scene Setup**: Basic responsive scene using Three.js and WebXR API
8+
- **Navigation and Interaction**: Teleportation, controller input handling, and object interaction
9+
- **Responsive UI System**: VR-compatible UI panels that adapt to different devices
10+
- **Controller Input Handling**: Support for various VR controllers with standardized input mapping
11+
- **Environment Loader**: Support for loading custom 3D models and skyboxes
12+
- **Spatial Audio**: Immersive audio system with 3D positioning
13+
- **Performance Monitoring**: Built-in FPS counter and performance tools
14+
- **Multiplayer Support**: Basic networking infrastructure for multi-user experiences
15+
- **Fallback Mechanisms**: Graceful fallback to non-VR mode when WebXR is unavailable
16+
17+
## Project Structure
18+
19+
```
20+
webxr/
21+
├── index.html # Main entry point
22+
├── src/
23+
│ ├── core/ # Core WebXR functionality
24+
│ │ ├── main.js # Main application entry point
25+
│ │ ├── xr-session.js # WebXR session management
26+
│ │ ├── environment.js # 3D environment setup
27+
│ │ ├── controllers.js # VR controller handling
28+
│ ├── ui/ # User interface components
29+
│ │ ├── styles.css # CSS styles
30+
│ │ ├── ui-panel.js # UI management
31+
│ ├── utils/ # Utility functions
32+
│ │ ├── input-manager.js # Input handling
33+
│ │ ├── performance-monitor.js # Performance tracking
34+
│ ├── audio/ # Audio system
35+
│ │ ├── audio-manager.js # Spatial audio management
36+
│ ├── network/ # Networking components
37+
│ │ ├── multiplayer.js # Multiplayer functionality
38+
│ ├── assets/ # Assets (models, textures, audio)
39+
│ ├── models/ # 3D models
40+
│ ├── textures/ # Textures
41+
│ ├── audio/ # Audio files
42+
├── packaging/ # Distribution packaging guides
43+
├── pwa/ # Progressive Web App packaging
44+
├── quest/ # Meta Quest Store packaging
45+
├── steamvr/ # SteamVR/PCVR packaging
46+
```
47+
48+
## Getting Started
49+
50+
### Prerequisites
51+
52+
- A WebXR-compatible browser (Chrome, Firefox, Edge with WebXR support)
53+
- A VR headset (Oculus Quest, HTC Vive, Valve Index, etc.) for full VR experience
54+
- Basic knowledge of HTML, CSS, and JavaScript
55+
56+
### Running the Experience
57+
58+
1. Clone this repository
59+
2. Serve the files using a local web server:
60+
- Using Python: `python -m http.server`
61+
- Using Node.js: `npx serve`
62+
3. Open the browser and navigate to the local server (typically `http://localhost:8000` or `http://localhost:3000`)
63+
4. Click the "Enter VR" button to start the VR experience
64+
65+
### Desktop Controls
66+
67+
When not in VR mode, you can navigate the scene using:
68+
69+
- **WASD** or **Arrow Keys**: Move around
70+
- **Mouse**: Look around
71+
- **Space**: Move up
72+
- **Shift**: Move down
73+
- **F**: Toggle fullscreen
74+
- **R**: Reset position
75+
- **Escape**: Exit pointer lock
76+
77+
## VR Controls
78+
79+
In VR mode, you can interact with the environment using:
80+
81+
- **Right Controller Trigger**: Teleport
82+
- **Left Controller Trigger**: Interact with objects
83+
- **Left Controller Grip**: Toggle settings panel
84+
- **Right Controller Thumbstick**: Rotate (snap or smooth turning based on settings)
85+
- **Left Controller Thumbstick**: Move (if smooth locomotion is enabled)
86+
87+
## Distribution Options
88+
89+
This WebXR experience can be distributed in several ways:
90+
91+
### 1. Browser-based WebXR
92+
93+
The simplest approach is to host the files on a web server with HTTPS support. Users can access the experience directly in a WebXR-compatible browser.
94+
95+
### 2. Progressive Web App (PWA)
96+
97+
You can enhance the experience as a Progressive Web App that can be installed from the browser:
98+
99+
- Provides offline support
100+
- Installable on the home screen
101+
- More app-like experience
102+
103+
See the [PWA Packaging Guide](./packaging/pwa/README.md) for details.
104+
105+
### 3. Meta Quest Store App
106+
107+
For distribution on the Meta Quest Store, you can package the experience as a native Android app:
108+
109+
- Full app store presence
110+
- Better integration with Quest features
111+
- Access to Quest-specific APIs
112+
113+
See the [Meta Quest Packaging Guide](./packaging/quest/README.md) for details.
114+
115+
### 4. SteamVR/PCVR App
116+
117+
For distribution on Steam and other PCVR platforms, you can package the experience as an Electron app:
118+
119+
- Distribution on Steam
120+
- Better integration with SteamVR
121+
- Access to desktop features
122+
123+
See the [SteamVR/PCVR Packaging Guide](./packaging/steamvr/README.md) for details.
124+
125+
For a comprehensive overview of all packaging options, see the [Packaging Guide](./packaging/README.md).
126+
127+
## Customization
128+
129+
### Changing the Environment
130+
131+
To customize the environment, modify the `environment.js` file:
132+
133+
```javascript
134+
// Add custom environment objects
135+
addEnvironmentObjects() {
136+
// Add your custom objects here
137+
}
138+
139+
// Load a custom environment model
140+
this.loadEnvironmentModel('path/to/your/model.glb');
141+
142+
// Load a custom skybox
143+
this.loadPanoramicSkybox('path/to/your/skybox.jpg');
144+
```
145+
146+
### Adding Interaction
147+
148+
To make objects interactive, register them with the controller manager:
149+
150+
```javascript
151+
// Create an object
152+
const myObject = new THREE.Mesh(
153+
new THREE.BoxGeometry(1, 1, 1),
154+
new THREE.MeshStandardMaterial({ color: 0xff0000 })
155+
);
156+
myObject.position.set(0, 1, -2);
157+
scene.add(myObject);
158+
159+
// Make it interactive
160+
controllerManager.registerInteractable(myObject);
161+
```
162+
163+
### Adding Sounds
164+
165+
To add spatial audio:
166+
167+
```javascript
168+
// Load and play a sound at a specific position
169+
audioManager.loadSound('mySound', 'path/to/sound.mp3', {
170+
spatial: true,
171+
volume: 0.8,
172+
loop: false
173+
}).then(() => {
174+
audioManager.playSound('mySound', new THREE.Vector3(0, 1, -2));
175+
});
176+
```
177+
178+
## Performance Considerations
179+
180+
- Use the built-in performance monitor to track FPS and optimize as needed
181+
- Adjust the quality settings for different devices
182+
- Use the `updateQuality` method in `environment.js` to adjust visual quality based on performance
183+
184+
## Browser Compatibility
185+
186+
This experience works best in browsers with full WebXR support:
187+
- Chrome 79+
188+
- Firefox 76+
189+
- Edge 79+
190+
- Oculus Browser 7.0+
191+
192+
## Integration with Existing Applications
193+
194+
The WebXR experience is designed as a standalone module that can be integrated with existing applications in various ways. For detailed instructions on how to integrate the WebXR experience with your main application, see the [Integration Guide](./integration.md).
195+
196+
### Hono.js Integration
197+
198+
The WebXR experience is primarily designed to be integrated with the main application using Hono.js and served at the `/webxr` URL path. A ready-to-use integration file is provided in [hono-integration.js](./hono-integration.js).
199+
200+
```javascript
201+
// In your main application
202+
import { integrateWebXR } from './webxr/hono-integration.js';
203+
204+
// Integrate WebXR experience at /webxr path
205+
integrateWebXR(app);
206+
```
207+
208+
### Other Integration Options
209+
210+
Alternative integration options include:
211+
- Serving as a separate experience
212+
- Linking from your main application
213+
- Embedding within an iframe
214+
- Direct code integration
215+
216+
## License
217+
218+
This project is available for use under the MIT License.
219+
220+
## Acknowledgments
221+
222+
- Three.js for 3D rendering
223+
- WebXR API for VR functionality
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/**
2+
* How to Expose the /webxr Route to the Main App
3+
*
4+
* This example shows the minimal code needed to expose the WebXR experience
5+
* at the /webxr route in your main application.
6+
*/
7+
8+
// Step 1: Import the necessary modules in your main app's index.js
9+
import { Hono } from 'hono';
10+
import { serveStatic } from '@hono/node-server/serve-static';
11+
import path from 'path';
12+
import { fileURLToPath } from 'url';
13+
14+
// Step 2: Create your main Hono app instance
15+
const mainApp = new Hono();
16+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
17+
18+
// Step 3: Create a sub-router for the WebXR experience
19+
const webxrRouter = new Hono();
20+
21+
// Step 4: Configure the WebXR router to serve the WebXR files
22+
// Serve the WebXR index.html for the root path
23+
webxrRouter.get('/', async (c) => {
24+
const indexPath = path.join(__dirname, '..', 'webxr', 'index.html');
25+
try {
26+
const indexContent = await fs.readFile(indexPath, 'utf-8');
27+
return c.html(indexContent);
28+
} catch (error) {
29+
console.error(`Error serving WebXR index.html: ${error.message}`);
30+
return c.text('Internal Server Error', 500);
31+
}
32+
});
33+
34+
// Serve static files from the WebXR directory
35+
webxrRouter.use('/*', serveStatic({ root: './webxr' }));
36+
37+
// Step 5: Mount the WebXR router at the /webxr path in your main app
38+
mainApp.route('/webxr', webxrRouter);
39+
40+
// Step 6: Make sure your SPA routing middleware doesn't interfere with WebXR routes
41+
mainApp.use('*', async (c, next) => {
42+
const url = new URL(c.req.url);
43+
const pathname = url.pathname;
44+
45+
// Skip API routes and WebXR routes
46+
if (pathname.startsWith('/api/') || pathname.startsWith('/webxr/')) {
47+
return next();
48+
}
49+
50+
// Handle other SPA routes...
51+
// ...
52+
53+
return next();
54+
});
55+
56+
// Rest of your main app code...
57+
// ...
58+
59+
/**
60+
* Alternative: Using the provided integration helper
61+
*
62+
* Instead of the steps above, you can use the provided integration helper:
63+
*/
64+
65+
// Import the integration helper
66+
import { integrateWebXR } from '../hono-integration.js';
67+
68+
// Create your main Hono app
69+
const exampleApp = new Hono();
70+
71+
// Integrate WebXR with one line of code
72+
integrateWebXR(exampleApp);
73+
74+
// Rest of your main app code...
75+
// ...
76+
77+
/**
78+
* How It Works
79+
*
80+
* 1. The WebXR router is created to handle requests to the /webxr path
81+
* 2. It serves the WebXR index.html file for the root path (/webxr/)
82+
* 3. It serves all static files from the WebXR directory for other paths (/webxr/*)
83+
* 4. The WebXR router is mounted at the /webxr path in the main app
84+
* 5. The SPA routing middleware is configured to skip WebXR routes
85+
*
86+
* This ensures that:
87+
* - The WebXR experience is accessible at http://your-domain.com/webxr
88+
* - All WebXR assets (JS, CSS, etc.) are properly served
89+
* - The WebXR routes don't interfere with the main app's routing
90+
*/

0 commit comments

Comments
 (0)