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, BvhPhysicsBody, 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>
      <BvhPhysicsBody>
        <PrototypeBox scale={[10, 1, 15]} position={[0, -0.5, 0]} />
      </BvhPhysicsBody>
    </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 (Container, Image, Text) that work in 3D space. We create a card-like layout with flexbox:

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

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 { Container, 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}>
      <Container
        depthTest={false}
        renderOrder={1}
        borderRadius={10}
        paddingX={2}
        height={20}
        backgroundColor="rgba(255, 255, 255, 0.5)"
        flexDirection="row"
        alignItems="center"
        gap={4}
      >
        <Image
          depthTest={false}
          renderOrder={1}
          width={16}
          height={16}
          borderRadius={14}
          src={profile.activeAvatar?.headIconUrl}
        />
        <Text depthTest={false} renderOrder={1} fontWeight="bold" fontSize={12} marginRight={3}>
          {profile.name}
        </Text>
      </Container>
    </group>
  )
}

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

<SimpleCharacter>
  <PlayerTag />
</SimpleCharacter>