New version

Photo Sphere Viewer 4 is not compatible with version 3. For the previous versions please use the version selector on the top-right of the page.
Or check the Migration guide to start using version 4.


Photo Sphere Viewer is a JavaScript library which renders 360° panoramas shots with Photo Sphere, the new camera mode of Android 4.2 Jelly Bean and above. It also supports cube panoramas.

Photo Sphere Viewer is pure JS and based on Three.js, allowing very good performances on WebGL enabled systems (most recent browsers) and reasonably good performances on other systems supporting HTML Canvas.

And it works with touch screens too !

Thanks to @JeremyHeleine

I forked the original Photo Sphere Viewer by Jérémy Heleine to provide a better JS architecture and a bunch of new features.

Getting started

Download Photo Sphere Viewer 4.0.0-alpha.2


Let's go!

Include all JS & CSS files in your page manually or with your favorite bundler and init the viewer.

<div id="viewer"></div>

  #viewer {
    width: 100vw;
    height: 50vh;

  const viewer = new PhotoSphereViewer({
    container: document.querySelector('#viewer'),
    panorama: 'path/to/panorama.jpg'

Cropped panoramas

If your image is not covering a full 360°×180° sphere, it will be deformed. You can fix it by providing cropping data.

Canvas rendering

In order to get Photo Sphere Viewer working on browsers without WebGL you will need some additional files from Three.js examples :

Gyroscope support

In order to be able to respond to device gyroscope, Photo Sphere Viewer requires the following file from Three.js examples :


VR support

In order to be able to display the panorama in VR mode, Photo Sphere Viewer requires the following files from Three.js examples :

As well as the NoSleep.js library.


Angles definition

Photo Sphere Viewer uses a lot of angles for it's configuration, most of them can be defined in radians by using a simple number (3.5) or in degrees using the "deg" prefix ('55deg').

Positions definition

Some methods take a position parameter. It is an object with either longitude and latitude properties (radians or degrees) or x and y properies (corresponding to the pixel position on the source panorama file).

Speeds definition

The autorotateSpeed option and the animate method both accept a speed value that can be expressed in various units.


Name type default description
container HTMLElement
required HTML element which will contain the panorama, or identifier of the element.
panorama String
Object<String, String>
required Path to the panorama image(s). It must be a single string for equirectangular panoramas and an array or an object for cubemaps.
caption String null A text (can contain HTML) displayed in the navbar. If the navbar is disabled it will be shown anyway but with no button.
markers Array [] List of markers.
minFov integer 30 Minimal field of view (corresponds to max zoom), between 1 and 179.
maxFov integer 90 Maximal field of view (corresponds to min zoom), between 1 and 179.
defaultZoomLvl integer 50 Initial zoom level, between 0 (for maxFov) and 100 (for minfov).
fisheye boolean|integer false Enable fisheye effect with true or specify effect strength (true = 1.0). This mode can have side-effects on markers rendering.
defaultLong double 0 Initial longitude, between 0 and 2π.
defaultLat double 0 Initial latitude, between -π/2 and π/2.
sphereCorrection object {pan:0, tilt:0, roll: 0} Sphere rotation angles, in radians.
longitudeRange double[] Viewable longitude range. Examples:
[0, Math.PI], [-3*Math.PI/4, 3*Math.PI/4].
latitudeRange double[] [π/2, -π/2] Viewable latitude range.
autorotateDelay integer null Delay in milliseconds before the panorama automatically starts rotating.
autorotateSpeed string '2rpm' Automatic rotation speed.
autorotateLat double defaultLat Latitude at which the automatic rotation is performed.
navbar boolean|array Enable or disable the navigation bar, you can also choose which buttons are displayed and even add custom buttons. See below.
lang Object Text of navbar buttons tooltips.
loadingImg String null Path to an image displayed in the center of the loading circle.
loadingTxt String 'Loading...' Text displayed in the center of the loading circle, only if loading_img is not provided.
mousewheel boolean true Enables zoom with the mouse wheel.
mousemove boolean true Enables panorama rotation with the mouse cursor.
mousemoveHover boolean false Rotate the panorama just by moving the cursor above the view instead of click+move.
touchmoveTwoFingers boolean false Requires two fingers to rotate the panorama. This allows standard touch-scroll navigation in the page containing the viewer. If enabled, an overlay asking the user to use two fingers is displayed when only one touch is detected.
keyboard Object | boolean Enable and configure keyboard navigation in fullscreen. It is a map defining key code->action. Set to false to disable.
size Object null The final size if the panorama container (e.g. {width: 500, height: 300}. By default the size of container is used and is followed during window resizes.
transition Object Configuration of the transition effect between panoramas.
withCredentials boolean false Set to true to use credentials for HTTP requests.

Advanced options

Name type default description
moveSpeed double 1 Speed multiplicator for manual moves.
zoomSpeed double 2 Speed multiplicator for zooms (with mouse wheel or fingers pinch).
useXmpData boolean true Read real image size from XMP data, must be kept true if the panorama has been cropped after shot.
panoData object Manually define cropping config (if useXmpData = false or no XMP tag is found) example.
cacheTexture integer 0 Number of texture objects to cache into memory, this is to prevent network overload when calling setPanorama multiple times.
moveInertia boolean true Enabled smooth animation after a manual move.
clickEventOnMarker boolean false A click on a marker will trigger a click event as well as select-marker.
mousewheelFactor double 1 Zoom speed multiplicator when using the mouse wheel.


All useful methods are documented in the API documentation

To call a method you need to keep a reference to the viewer (created with new keyword). It's good practice to wait for the ready event before doing anything.

viewer.on('ready', function() {
    x: 1500,
    y: 1000


On the viewer you can also use the on method to listen to various events.

navbar is an array which can contain the following core buttons: autorotate, zoom, download, markers, gyroscope, stereo, fullscreen, as well as caption and objects to create custom buttons :

Name description
id The unique identifier of the button.
title The button tooltip.
content The content of the button.
className A CSS class added to the button element.
onClick Function called when the button is clicked.
disabled If the button must be disabled by default.
hidden If the button must be hidden by default.

This example uses some core buttons and a custom one.

new PhotoSphereViewer({
  container: 'container-id',
  panorama: 'path/to/panorama.jpg',
  navbar: [
      id: 'my-button',
      title: 'Hello world',
      className: 'custom-button',
      content: 'Custom',
      onClick: function() {
        alert('Hello from custom button');

Altering the buttons

After the viewer creation you cannot add or remove buttons but you can change their visibility. Use the navbar.getButton(id) method the get a button by its id (works for core buttons too). You will get an object with the following methods: disable(), enable(), hide(), show().