Translations: Japanese

Get started (A-FRAME)

This is a brief introduction on how to incorporate VerseEngine using A-FRAMEopen in new window and VerseEngine's simple library verse-three.

Alternatively, you can download the complete source code from here (github.com)open in new window.

Step 0: Create the world

First, a simple space is created in A-FRAME.
For more information, see the A-FRAME manualopen in new window.

<html>
  <head>
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1,viewport-fit=cover"
    />
    <style>
      .a-enter-ar {
        display: none;
      }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/aframe-master.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/aframe-environment-component.min.js"></script>
  </head>
  <body>
    <a-scene environment="ground: flat" renderer="colorManagement: true;">
    </a-scene>
  </body>
</html>

Step 1: Prepare to add processing every frame

...
  <script>
    if (!window.__extendAnimationLoop) {
      window.__extendAnimationLoop = () => {};
    }
    AFRAME.registerSystem("extend-animation-loop", {
      tick: function (time, timeDelta) {
        window.__extendAnimationLoop(time, timeDelta);
      },
    });
  </script>
</head>
...

 
 
 
 
 
 
 
 
 
 


Step 2: Set up the player

...
<body>
  <a-scene environment="ground: flat" renderer="colorManagement: true;">
    <a-entity id="player">
      <a-entity id="headOffset">
        <a-entity id="head" camera position="0 1.6 0"></a-entity>
      </a-entity>
    </a-entity>
  </a-scene>
</body>
...



 
 
 
 
 



Step 3: Load VerseEngine

Load the IIFE version of verse-three and the three-vrmopen in new window used inside the verse-three.

  ...
  <script src="https://cdn.jsdelivr.net/npm/@pixiv/[email protected]/lib/three-vrm.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/@verseengine/[email protected]/dist/index.min.js"></script>
</head>
...

 
 


Step 4: Connect with VerseEngine

You can prepare your own animation and avatar files, though, You can also download verse-three exampleopen in new window and try it out quickly.

setup-verse.js

(() => {
  const { VerseThree, THREE } = window;
  const VERSE_WASM_URL =
    "https://cdn.jsdelivr.net/npm/@verseengine/[email protected]/dist/verse_core_bg.wasm";
  const ENTRANCE_SERVER_URL = "https://entrance.verseengine.cloud";
  // Animation files
  const ANIMATION_MAP = {
    idle: "./asset/animation/idle.fbx",
    walk: "./asset/animation/walk.fbx",
  };
  // Avatar files
  const range = (n) => [...Array(n).keys()];
  export const PRESET_AVATARS = [
    ...range(3).map((i) => `f${i}`),
    ...range(3).map((i) => `m${i}`),
  ].map((n) => ({
    thumbnailURL: `./asset/avatar/${n}.png`,
    avatarURL: `./asset/avatar/${n}.vrm`,
  }));
  const DEFAULT_AVATAR_URL =
    PRESET_AVATARS[Math.floor(Math.random() * PRESET_AVATARS.length)].avatarURL;
  const ICE_SERVERS = [
    { urls: "stun:stun.l.google.com:19302" },
    { urls: "stun:stun1.l.google.com:19302" },
  ];

  async function waitForAframeLoad(scene) {
    if (scene.hasLoaded) { return; }
    return new Promise((resolve) => scene.addEventListener("loaded", resolve));
  }

  main();

  function main() {
    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", _main);
    } else {
      _main();
    }
  }

  async function _main() {
    const scene = document.querySelector("a-scene");
    await waitForAframeLoad(scene);

    let collisionObjects = []; // obstacle
    let teleportTargetObjects = []; // VR teleport destination
    let interactableObjects = []; // clickable object
    let collisionBoxes = []; // Bounding boxes for collisionObjects and teleportTargetObjects

    const updateCollisionBoxes = () => {
      collisionBoxes.length = 0;
      [...collisionObjects, ...teleportTargetObjects].map((el) => {
        el.traverse((c) => {
          if (!c.isMesh) { return; }
          collisionBoxes.push(new THREE.Box3().setFromObject(c));
        });
      });
    };
    const queryObjects = (q) =>  [...scene.querySelectorAll(q)].map((v) => v.object3D).filter((v) => v.visible);
    const updateCollisionObjects = () => {
      collisionObjects = queryObjects(".collider,.wall");
      teleportTargetObjects = queryObjects(".ground,.environmentGround");
      interactableObjects = queryObjects(".clickable");
      updateCollisionBoxes();
    };

    scene.object3D.updateMatrixWorld();
    updateCollisionObjects();

    const adapter = new VerseThree.AFrameEnvAdapter(
      scene,
      document.getElementById("headOffset").object3D,
      document.getElementById("player").object3D,
      () => collisionBoxes,
      () => collisionObjects,
      () => teleportTargetObjects,
      {
        getInteractableObjects: () => interactableObjects,
        onSelectDown: (o, _point) => {
          if (!o.el || !o.el.classList.contains("clickable")) {
            return;
          }
          o.el.emit("click", {intersectedEl: o.el});
        },
        isLowSpecMode: true, // Improve performance by omitting hair and other shaking
      }
    );
    const mayBeLowSpecDevice = VerseThree.isLowSpecDevice();
    const res = await VerseThree.start(adapter, scene.object3D,
      VERSE_WASM_URL, ENTRANCE_SERVER_URL, DEFAULT_AVATAR_URL,
      ANIMATION_MAP, ICE_SERVERS,
      {
        maxNumberOfPeople: mayBeLowSpecDevice ? 8 : 16,
        maxNumberOfParallelFileTransfers: mayBeLowSpecDevice ? 1 : 4,
        presetAvatars: PRESET_AVATARS,
      }
    );

    // Set processing for every frame
    window.__extendAnimationLoop = (_time, timeDelta) => {
      res.tick(timeDelta / 1000);
    };
  }
})();

index.html

  ...
  <script src="./setup-verse.js"></script>
</head>
...

 


For more detailed usage, see verse-three referenceopen in new window.

Tips

WARNING

VerseEngine builds a network of users for each web page URL.
When using localhost or local IP (e.g. 192.168.xxx.xxx) for development, some URLs may connect to strangers.
Either assign a dedicated name to the IP address in the hosts file,
Alternatively, you can work around it by giving the html file a sufficiently long random filename.

# https://very-long-name12345678/
127.0.0.1 very-long-name12345678

TIP

To use all functions, you must communicate via HTTPS.

Examples of services that can easily support HTTPS for web servers

Tools to create local development certificates

Example of starting HTTPS Server for local development on Mac

# Install mkcert using Homebrew
brew install mkcert
mkcert -install
# Create a certificate (change the IP address to match your environment)
mkdir cert
cd cert
mkcert localhost 127.0.0.1 192.168.10.2
cd ..
# Start the server
npx http-server -c-1 --ssl --key ./cert/localhost+2-key.pem --cert ./cert/localhost+2.pem -p 8080
Last Updated: