Skip to content

Whitebox Plugin - Three.js for VideoJS

This is a plugin for whitebox that provides Three.js integration VideoJS players.

Video360 projection and leveling contract

DualFisheyeProjectedVideo keeps the horizontal 2:1 dual-fisheye layout identified by whitebox.video360.dual-fisheye-hstack.v1: stream 0 is the left square half and stream 1 is the right square half. The shader owns that projection; equirectangular inputs are not supported.

The optional projection prop defaults to that profile. The optional onLevelingReady callback receives a generation-bound capability after the Three.js sphere and renderer are ready, and receives null when that generation is retired. Existing options and onReady behavior is unchanged.

The capability contains only:

{
  projection: "whitebox.video360.dual-fisheye-hstack.v1",
  frame: "whitebox.video360.leveling-root.v1",
  apply({ frame, gravity }),
  clear(),
}

The leveling-root frame is the right-handed Three.js root/world frame: +X world (viewer-left with the current +Z camera target), +Y up, and +Z target-forward. Device producers own camera-specific raw-to-root calibration. gravity is a finite three-element unit vector expressed in that frame. The renderer defensively normalizes values within 1e-3 of unit length and rejects all other values. Gravity contains no yaw information; root leveling applies the shortest deterministic rotation directly from root gravity to world down [0, -1, 0] and adds no intentional twist. OrbitControls and the user camera remain independent of leveling.

Independently, the shader source direction and THREE.SphereGeometry vertex use different numeric bases for the same UV. The dual-fisheye projection domain maps source (x, y, z) to sphere vertex (z, y, -x) using the fixed +90° Y basis matrix:

    [ 0  0  1 ]
B = [ 0  1  0 ]
    [-1  0  0 ]

This basis belongs only to panorama texture sampling and projection tests. It must not be applied to root leveling, OrbitControls, or the camera. Keeping the projection mapping separate preserves shader presentation while canonical side and front/back gravity rotate around the visible roll and pitch axes.

SphereGeometry stores its vertical UV as 1-v. The shader therefore uses (vUv.y - 0.5) * pi for its internal source latitude so source and geometry Y have the same sign. Its final fisheye texture V calculation uses the paired opposite sign, 0.5 - fy * 0.5; these two signs must change together. Their effects cancel algebraically, preserving the existing sampled texture exactly.

apply and clear return promises. A promise resolves true only after a render used that exact latest root transform. Superseded or retired work resolves false; invalid frame/vector input rejects and resets the source root to neutral. Leveling never modifies the camera, OrbitControls, Video.js player, texture, or shader resources.

Each post-initialization Video.js loadstart retires the old leveling source generation, resets its root to neutral, and publishes a fresh capability. When the tech and video element are unchanged, this does not recreate player or Three.js resources.

Installation

Install the plugin to whitebox:

poetry add whitebox-plugin-videojs-threejs

Additional Instructions