NAF is the networking protocol used for synchronizing 3D objects and avatar states in virtual environments.
import { NafMessageBuilder } from '@metatell/bot-sdk'
// For frequent position updates (unreliable)
const nafUpdate = new NafMessageBuilder()
.withDataType('um')
.withNetworkId(sessionId)
.withOwner(sessionId)
.withCreator(sessionId)
.withPosition({ x: 1, y: 2, z: 3 })
.build()
await messageService.sendNAF(nafUpdate)
// For critical state changes (reliable) - e.g., spawning an avatar
const spawnMessage = new NafMessageBuilder()
.withDataType('u')
.withNetworkId(sessionId)
.withOwner(sessionId)
.withCreator(sessionId)
.withFirstSync(true)
.withAvatar({
avatarSrc: `https://storage.metatell.app/avatars/${avatarId}/avatar.gltf`,
avatarType: 'skinnable'
})
.build()
await messageService.sendNAFR(spawnMessage)
// Listen for unreliable updates
messageService.on('naf', (data) => {
// Handle frequent updates (position, rotation, etc.)
})
// Listen for reliable messages
messageService.on('nafr', (data) => {
// Handle critical state changes
})
NAF messages follow this general structure:
interface NAFMessage {
dataType: string // Message type ('u', 'um', 'r', etc.)
data: unknown // Message payload
from_session_id?: string // Sender session ID
}
'u': User spawn/initial state'um': User update (position/rotation)'r': Remove/despawnNAF uses numeric IDs to identify component types:
0: Position1: Velocity2: Scale3: Avatar4: Head Rotation5: Left Hand Rotation6: Right Hand Rotation7: Left Hand Position8: Right Hand Position9: Hand Raised10: Pin Position11: Pin Scale12: Face Snapshot Enabled13: Face Snapshot / VRM Avatar Status (also used for animation state)14: Body RotationNote: Component ID 13 is used both for face snapshots and VRM avatar animation states for compatibility with vrm-avatar-status-manager.
graph TD
A[Client sends NAF] --> B[Server receives]
B --> C[Server broadcasts to other clients]
C --> D[Clients receive 'naf' event]
E[Client sends NAFR] --> F[Server receives + ACK]
F --> G[Server broadcasts to other clients]
G --> H[Clients receive 'nafr' event]
H --> I[Clients send ACK back]
Enable NAF message debugging:
// Enable debug mode to see NAF traffic
appSettings.setDebugMode(true)
This will log all incoming NAF/NAFR messages with [NAF RECEIVED] and [NAFR RECEIVED] prefixes.
createMetatellClient({ debug: true }) enables the same debug mode.