Skip to content

360 Videos in Hubs

Posted on:March 25, 2023

360 images edited in Blender have been used to great effect in the Mozilla Hubs community but did you know this functionality is (sort of) built into Hubs already?

Spoke and the Blender Add-on has options to project textures onto spheres. These options inspired me to add an in-room convert image to 360 feature to my custom client and is a neat trick the Hubs client can do but what about 360 video?

Someone made this great template if you are just looking for an easy way to show your video with webXR and deploy it really quickly: 360 video template (spoke).

With the template, you can upload your video, publish and have a sharable 360 web space right away!

Although the Hubs client code doesn’t currently support equiangular-to-cube map conversion or stereo 360 videos, it should be possible to use three.js for this purpose. If you know of any examples in the wild, please share them with me.

Considerations for doing 360 Video with Hubs

1.) Projection with Blender and Spoke

You can project the video to a 360 view with options in Blender and Spoke with the projection properties.

Projection Blender

2.) Video Controls Accessibility

If you enable video controls, they are not very accessible from inside the sphere by default. Great opportunity for a plug-in here!

video controls spoke

3.) Cursor Hover Effect

The video is subject to the cursor hover effect and this is why it appears to dim when hovered on desktop.

Here is a quick sample scene to check out so you can see what all this looks like:

You can customize a lot more around 360 photos and videos with custom code.

The trick as it’s done in Hubs:

if (projection === "360-equirectangular") {
        geometry = new THREE.SphereBufferGeometry(1, 64, 32);
        // invert the geometry on the x-axis so that all of the faces point inward
        geometry.scale(-1, 1, 1);

        // Flip uvs on the geometry
        if (!texture.flipY) {
          const uvs = geometry.attributes.uv.array;

          for (let i = 1; i < uvs.length; i += 2) {
            uvs[i] = 1 - uvs[i];