DLUX Wallet Auto-Injection
The DLUX wallet automatically injects networking capabilities into any post content through intelligent content detection. When visiting a post page (/@author/permlink
), the wallet scans the content and provides appropriate networking features based on what it finds.
Auto-Detection System
Three Integration Modes
- Networked A-Frame (NAF) - Existing A-Frame scenes with NAF get enhanced
- A-Frame Auto-Enhancement - Basic A-Frame scenes get NAF added automatically
- Generic Room API - Any application gets universal networking capabilities
Detection Process
// 1. Extract post context from URL
const postMatch = window.location.pathname.match(/\/@([^\/]+)\/([^\/]+)/);
const [, author, permlink] = postMatch;
// 2. Scan page content
const aframeScene = document.querySelector('a-scene');
const hasNetworkedScene = aframeScene?.hasAttribute('networked-scene');
// 3. Apply appropriate integration
if (hasNetworkedScene) {
enhanceExistingNAF(aframeScene, author, permlink);
} else if (aframeScene) {
autoEnhanceAFrame(aframeScene, author, permlink);
} else {
exposeGenericRoomAPI(author, permlink);
}
Room API (window.dluxRoom
)
Universal networking API available in all posts:
// Room identification
dluxRoom.author // "disregardfiat"
dluxRoom.permlink // "my-awesome-post"
dluxRoom.roomId // "disregardfiat/my-awesome-post:main"
dluxRoom.subspace // "main" (default)
// Connection management
dluxRoom.connected // Boolean connection status
dluxRoom.socket // WebSocket connection
// Event system
dluxRoom.on(event, callback)
dluxRoom.off(event, callback)
dluxRoom.emit(event, data)
// Messaging
dluxRoom.send(message)
// Sub-rooms
dluxRoom.joinSubRoom(name)
dluxRoom.getAvailableSubRooms()
// WebRTC
dluxRoom.getWebRTCCredentials()
Sub-Room Architecture
Main Room
Every post gets a default main room: author/permlink:main
Sub-Rooms
Create specialized rooms for different features:
// Chess game sub-room
const chessRoom = await dluxRoom.joinSubRoom('chess-game1');
// Full ID: "author/permlink:main-chess-game1"
// Private chat sub-room
const privateChat = await dluxRoom.joinSubRoom('private-alice-bob');
// Full ID: "author/permlink:main-private-alice-bob"
// Listening room sub-room
const musicRoom = await dluxRoom.joinSubRoom('listen-music');
// Full ID: "author/permlink:main-listen-music"
A-Frame Integration
Auto-Enhancement Process
When basic A-Frame is detected:
- Load NAF Library - Inject networked-aframe.js
- Add Default Avatar - Create avatar template
- Enhance Camera - Add networking to camera entity
- Configure Scene - Set up networked-scene attributes
- Connect to Server - Auto-connect to presence.dlux.io
Enhanced Scene Example
<!-- Before: Basic A-Frame -->
<a-scene>
<a-entity camera wasd-controls look-controls></a-entity>
<a-box position="0 1 -5" color="red"></a-box>
</a-scene>
<!-- After: Auto-Enhanced -->
<a-scene networked-scene="app:dlux-vr;room:author-permlink-main">
<a-assets>
<template id="avatar-template">
<a-entity class="avatar">
<a-sphere class="head" color="#5985ff" scale="0.45 0.5 0.38"></a-sphere>
<a-cylinder class="body" color="#5985ff" scale="0.25 0.7 0.25"></a-cylinder>
<a-text class="nametag" align="center" position="0 2.2 0"></a-text>
</a-entity>
</template>
</a-assets>
<a-entity camera wasd-controls look-controls
networked="template:#avatar-template;attachTemplateToLocal:false">
</a-entity>
<a-box position="0 1 -5" color="red" networked></a-box>
</a-scene>
Custom Override
Provide your own templates to override defaults:
<a-scene>
<a-assets>
<!-- Your custom avatar overrides default -->
<template id="avatar-template">
<a-gltf-model src="#my-avatar-model"></a-gltf-model>
</template>
</a-assets>
<a-entity camera networked="template:#avatar-template"></a-entity>
</a-scene>
Application Examples
Real-Time Chat
<div id="chat-container">
<div id="messages"></div>
<input id="message-input" placeholder="Type message...">
<button onclick="sendMessage()">Send</button>
</div>
<script>
window.addEventListener('vr:generic_room_ready', (event) => {
const { roomAPI } = event.detail;
// Listen for chat messages
roomAPI.on('chat-message', (event) => {
const { user, message, timestamp } = event.detail;
displayMessage(user, message, timestamp);
});
});
function sendMessage() {
const input = document.getElementById('message-input');
const message = input.value.trim();
if (message) {
dluxRoom.send({
type: 'chat-message',
user: dluxRoom.author,
message: message,
timestamp: Date.now()
});
input.value = '';
}
}
</script>
Collaborative Canvas
<canvas id="canvas" width="800" height="600"></canvas>
<div id="tools">
<input type="color" id="color" value="#000000">
<input type="range" id="size" min="1" max="50" value="5">
</div>
<script>
window.addEventListener('vr:generic_room_ready', (event) => {
const { roomAPI } = event.detail;
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// Receive drawing data
roomAPI.on('draw-data', (event) => {
const { x, y, color, size } = event.detail;
drawPoint(ctx, x, y, color, size);
});
// Send drawing data
canvas.addEventListener('mousemove', (e) => {
if (e.buttons === 1) { // Left mouse button
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
roomAPI.send({
type: 'draw-data',
x: x,
y: y,
color: document.getElementById('color').value,
size: document.getElementById('size').value
});
}
});
});
</script>
Multi-Player Game
<canvas id="game-canvas" width="800" height="600"></canvas>
<div id="game-ui">
<div id="player-list"></div>
<div id="score">Score: <span id="score-value">0</span></div>
</div>
<script>
let players = {};
let localPlayer = { x: 400, y: 300, score: 0 };
window.addEventListener('vr:generic_room_ready', (event) => {
const { roomAPI } = event.detail;
// Player movements
roomAPI.on('player-move', (event) => {
const { user, x, y } = event.detail;
if (user !== roomAPI.author) {
players[user] = { x, y };
updateGameDisplay();
}
});
// Score updates
roomAPI.on('score-update', (event) => {
const { user, score } = event.detail;
players[user].score = score;
updatePlayerList();
});
// Game input
document.addEventListener('keydown', (e) => {
let moved = false;
switch(e.code) {
case 'ArrowUp': localPlayer.y -= 10; moved = true; break;
case 'ArrowDown': localPlayer.y += 10; moved = true; break;
case 'ArrowLeft': localPlayer.x -= 10; moved = true; break;
case 'ArrowRight': localPlayer.x += 10; moved = true; break;
}
if (moved) {
roomAPI.send({
type: 'player-move',
user: roomAPI.author,
x: localPlayer.x,
y: localPlayer.y
});
updateGameDisplay();
}
});
});
function updateGameDisplay() {
const canvas = document.getElementById('game-canvas');
const ctx = canvas.getContext('2d');
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw local player
ctx.fillStyle = 'blue';
ctx.fillRect(localPlayer.x - 10, localPlayer.y - 10, 20, 20);
// Draw other players
ctx.fillStyle = 'red';
Object.values(players).forEach(player => {
ctx.fillRect(player.x - 10, player.y - 10, 20, 20);
});
}
</script>
WebRTC Voice Integration
Voice communication is automatically available:
window.addEventListener('vr:generic_room_ready', async (event) => {
const { roomAPI } = event.detail;
// Get WebRTC credentials
const credentials = await roomAPI.getWebRTCCredentials();
// Set up peer connection
const peerConnection = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:presence.dlux.io:3478' },
{
urls: 'turn:presence.dlux.io:3478',
username: credentials.username,
credential: credentials.credential
}
]
});
// Add local audio stream
const stream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: false
});
stream.getTracks().forEach(track => {
peerConnection.addTrack(track, stream);
});
// Handle remote audio streams
peerConnection.ontrack = (event) => {
const remoteAudio = document.createElement('audio');
remoteAudio.srcObject = event.streams[0];
remoteAudio.autoplay = true;
document.body.appendChild(remoteAudio);
};
});
Events Reference
Connection Events
vr:generic_room_ready
- Room API is availablevr:aframe_enhanced
- A-Frame scene enhanced with NAFvr:naf_ready
- NAF connection established
Room Events
connected
- Connected to roomdisconnected
- Disconnected from roomuser-joined
- User joined roomuser-left
- User left roommessage
- Message receivederror
- Connection error
Custom Events
Any event type can be sent/received:
// Send custom event
dluxRoom.send({
type: 'custom-event',
data: { /* any data */ }
});
// Listen for custom event
dluxRoom.on('custom-event', (event) => {
console.log('Custom event:', event.detail);
});
Best Practices
1. Wait for Ready Events
function initializeApp() {
if (window.dluxRoom) {
setupNetworking();
} else {
window.addEventListener('vr:generic_room_ready', setupNetworking);
}
}
document.addEventListener('DOMContentLoaded', initializeApp);
2. Handle Disconnections
dluxRoom.on('disconnected', () => {
// Show offline indicator
document.getElementById('status').textContent = 'Offline';
// Attempt reconnection
setTimeout(() => {
if (!dluxRoom.connected) {
dluxRoom.socket.reconnect();
}
}, 5000);
});
3. Validate Messages
dluxRoom.on('message', (event) => {
const message = event.detail;
// Validate required fields
if (!message.type || !message.user) {
console.warn('Invalid message:', message);
return;
}
// Check timestamp (prevent old messages)
if (Date.now() - message.timestamp > 30000) {
console.warn('Old message discarded:', message);
return;
}
// Process valid message
handleMessage(message);
});
4. Clean Up Resources
window.addEventListener('beforeunload', () => {
if (dluxRoom?.connected) {
dluxRoom.disconnect();
}
});
Troubleshooting
Common Issues
Room API Not Available
- Check if on valid post page (
/@author/permlink
) - Verify network connectivity
- Wait for
vr:generic_room_ready
event
A-Frame Not Enhanced
- Ensure
<a-scene>
exists before wallet loads - Check browser console for errors
- Verify scene is visible
Voice Chat Not Working
- Check microphone permissions
- Verify HTTPS (required for WebRTC)
- Test TURN connectivity
Debug Information
// Check room status
console.log('Room ID:', dluxRoom?.roomId);
console.log('Connected:', dluxRoom?.connected);
console.log('Socket state:', dluxRoom?.socket?.readyState);
// Monitor all events
dluxRoom.on('*', (event) => {
console.log('Room event:', event.type, event.detail);
});
The DLUX wallet auto-injection system provides seamless networking capabilities to any post content, enabling rich collaborative experiences without manual setup or external dependencies.