Accessing Avatar and Profile

Learn how to display player information and use VIVERSE avatars in your game.

This tutorial shows you how to display a player tag above the character by accessing the user profile information from VIVERSE.

Here's a preview of what we'll build in this tutorial:

import { Sky } from '@react-three/drei'
import { Canvas } from '@react-three/fiber'
import { Viverse, SimpleCharacter, FixedBvhPhysicsBody, PrototypeBox } from '@react-three/viverse'
import { PlayerTag } from "./Playertag"

export default function App() {
return (
  <Canvas shadows style={{ position: "absolute", inset: "0", touchAction: "none" }}>
    <Viverse>
      <Sky />
      <directionalLight intensity={1.2} position={[-10, 10, -10]} castShadow />
      <ambientLight intensity={1} />
      <SimpleCharacter>
        <PlayerTag />
      </SimpleCharacter>
      <FixedBvhPhysicsBody>
        <PrototypeBox scale={[10, 1, 15]} position={[0, -0.5, 0]} />
      </FixedBvhPhysicsBody>
    </Viverse>
  </Canvas>
)
}

First, we use the useViverseProfile() hook to fetch the current user's profile from VIVERSE, including their name and avatar information. We provide a fallback for when the user isn't logged in:

const profile = useViverseProfile() ?? {
  name: 'Anonymous',
  activeAvatar: { headIconUrl: 'https://picsum.photos/200' },
}

Next, we need a 3D ui library, install it via

npm install @react-three/uikit

UIKit provides HTML-like components (Root, Image, Text) that work in 3D space. We create a card-like layout with flexbox:

<Root
  depthTest={false}
  renderOrder={1}
  backgroundOpacity={0.5}
  borderRadius={10}
  paddingX={2}
  height={20}
  backgroundColor="white"
  flexDirection="row"
  alignItems="center"
  gap={4}
>
  <Image 
    width={16} 
    height={16} 
    borderRadius={14} 
    src={profile.activeAvatar?.headIconUrl} 
  />
  <Text fontWeight="bold" fontSize={12} marginRight={3}>
    {profile.name}
  </Text>
</Root>

Next, we use useFrame to constantly update the tag's rotation to match the camera:

import { Group } from 'three'


const ref = useRef<Group>(null)

useFrame((state) => {
  if (ref.current == null) {
    return
  }
  ref.current.quaternion.copy(state.camera.quaternion)
})

The full PlayerTag component looks like this:

import { useViverseProfile } from '@react-three/viverse'
import { Root, Image, Text } from '@react-three/uikit'
import { useRef } from 'react'
import { useFrame } from '@react-three/fiber'
import { Group } from 'three'

export function PlayerTag() {
  const profile = useViverseProfile() ?? {
    name: 'Anonymous',
    activeAvatar: { headIconUrl: 'https://picsum.photos/200' },
  }
  
  const ref = useRef<Group>(null)
  
  // Make the tag always face the camera
  useFrame((state) => {
    if (ref.current == null) {
      return
    }
    ref.current.quaternion.copy(state.camera.quaternion)
  })

  return (
    <group ref={ref} position-y={2.15}>
      <Root
        depthTest={false}
        renderOrder={1}
        backgroundOpacity={0.5}
        borderRadius={10}
        paddingX={2}
        height={20}
        backgroundColor="white"
        flexDirection="row"
        alignItems="center"
        gap={4}
      >
        <Image 
          width={16} 
          height={16} 
          borderRadius={14} 
          src={profile.activeAvatar?.headIconUrl} 
        />
        <Text fontWeight="bold" fontSize={12} marginRight={3}>
          {profile.name}
        </Text>
      </Root>
    </group>
  )
}

Now finally lets add the PlayerTag as a child of SimpleCharacter to display it

<SimpleCharacter>
  <PlayerTag />
</SimpleCharacter>