360 Viewer — Free Open-Source Panorama Viewer

Embed 360° panoramic images on any website or app using the free, open-source Phong 360 Viewer. Lightweight, modular, and fully customizable.

Last updated: 2026-03-15

360 Viewer — Open-Source Panorama Viewer

Phong 360 Viewer is a free, open-source, ultra-lightweight panoramic image viewer built on Three.js. Use it to display your 360 Hextile creations on any website, portfolio, or app — no server required.

View on GitHub

License: MIT — free for commercial and personal use.


Why 360 Viewer?

Phong 360 Viewer Photo Sphere Viewer Pannellum Marzipano
Core Size 30 KB 180 KB 75 KB 95 KB
Modular Layers 3 progressive layers No No No
Template Engine 9 built-in renderers No No No
Theme System Light / Dark / Auto No No No
Build Tools Required No Yes No Partial

360 Viewer is purpose-built for displaying 360° panoramic images — the same kind you create with 360 Hextile. It's the easiest way to share your work on the web.


Architecture: Pick Your Layer

360 Viewer uses a "Russian Doll" architecture. Load only what you need:

Layer What You Get Size
Layer 1 — Core Three.js renderer, mouse/touch/keyboard controls, projection switching ~30 KB
Layer 2 — Multi-Image Multiple image management, adaptive resolution, user preferences +15 KB
Layer 3 — Full UI Sidebar gallery, toolbar, info bar, template engine, theming +25 KB

Most websites only need Layer 1 for embedding a single panorama.


Quick Start: Embed a Single 360° Image

This is the simplest way to show a 360 image on your website. Just three files — no build tools, no bundler, no framework needed.

1. Include the Dependencies

<!-- Three.js (required) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>

<!-- 360 Viewer Core -->
<script src="360-viewer/core/phong-360-viewer-core.js"></script>
<link rel="stylesheet" href="360-viewer/css/styles.css">

2. Add a Container

<div id="viewer" style="width: 100%; height: 600px;"></div>

3. Initialize the Viewer

<script>
const viewer = new Phong360ViewerCore({
  containerId: 'viewer',
  imageUrl: 'my-360-panorama.jpg',
  config: {
    viewRotation: { autoRotate: true }
  }
});
</script>

That's it — your 360 image is now interactive on the page. Users can click and drag to look around, scroll to zoom, and double-click for fullscreen.


For a complete gallery experience with sidebar navigation, sections, themes, and templates, use all three layers:

1. Include All Layers

<!-- Three.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>

<!-- Layer 1: Core Viewer -->
<script src="360-viewer/core/phong-360-viewer-core.js"></script>
<link rel="stylesheet" href="360-viewer/css/styles.css">

<!-- Layer 2: Multi-Image (required for gallery) -->
<script src="360-viewer/extensions/phong-360-multi-image.js"></script>

<!-- Layer 3: Full Gallery UI -->
<script src="360-viewer/extensions/phong-360-library-ui.js"></script>
<link rel="stylesheet" href="360-viewer/css/phong-360-ui.css">

<!-- Icons (optional, for UI icons) -->
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.1.1/src/regular/style.css">
<div id="viewer" style="width: 100%; height: 100vh;"></div>

<script>
const gallery = new Phong360LibraryUI({
  containerId: 'viewer',
  libraryUrl: 'library/library.json',
  configUrl: '360-viewer.json',
  baseUrl: 'library/',
  theme: 'auto'
});
</script>

3. Create Your Configuration

Create a 360-viewer.json file to customize the gallery:

{
  "context": {
    "type": "profile",
    "title": "My 360 Gallery",
    "subtitle": "360° Photography",
    "avatar": "assets/avatar.jpg",
    "theme": "dark",
    "accent": "#ff9f95",
    "panelWidth": 420,
    "infoBar": "center",
    "favicon": "🌐",
    "links": [
      { "url": "https://yoursite.com", "label": "Website" },
      { "url": "https://instagram.com/you", "label": "Instagram" }
    ]
  },
  "sections": {
    "landscapes": {
      "title": "Landscapes",
      "icon": "mountains",
      "template": "grid"
    },
    "interiors": {
      "title": "Interior Spaces",
      "icon": "house",
      "template": "feed"
    }
  }
}

Configuration Reference

Viewer Options

Option Type Default Description
containerId string required ID of the HTML container element
imageUrl string URL to a single 360° image (Layer 1)
libraryUrl string Path to library.json (Layer 3)
configUrl string Path to 360-viewer.json (Layer 3)
baseUrl string '' Base path for image URLs
theme string 'auto' 'light', 'dark', or 'auto'

Context Config (360-viewer.json)

Field Type Description
title string Gallery or profile name
subtitle string Tagline or description
avatar string Path to avatar image
theme string 'light', 'dark', or 'auto'
accent string Hex color for UI accents (e.g. '#ff9f95')
panelWidth number Sidebar width in pixels
infoBar string Position: 'top', 'center', or 'bottom'
favicon string Single emoji character for the tab icon
links array Social/nav links ({ url, label })

Section Config

Field Type Description
title string Section display name
icon string Phosphor icon name (without ph- prefix)
template string Renderer template (see below)

Sections can use different visual layouts:

Template Best For
grid Thumbnail grid — default browsing
feed Vertical list with large thumbnails — featured content
accordion Collapsible sections — category organization
hero Single large featured image — spotlight
list Compact rows — search results or long lists
carousel Horizontal scrolling strip — trending content
avatar-row Circular avatars in a row — creator highlights
avatar-grid Avatar cards in a grid — creator directory
empty-state Placeholder when no content is available

Controls

Action Mouse Keyboard Touch
Look around Click & drag WASD / Arrow keys Swipe
Zoom in Scroll up + or = Pinch out
Zoom out Scroll down - or _ Pinch in
Fullscreen Double-click Double-tap
Switch projection Button P Button

Installation

git submodule add https://github.com/ansonphong/360-VIEWER.git 360-viewer

This keeps the viewer updatable. Pull new versions with:

cd 360-viewer && git pull origin main

Option B: Direct Clone

git clone https://github.com/ansonphong/360-VIEWER.git 360-viewer

Option C: Download

Download the latest release from the GitHub releases page and extract it into your project.


Building Your Image Library

360 Viewer includes a Python script to process your 360 images into multi-resolution versions for adaptive loading:

cd 360-viewer/library
python build_library.py --input /path/to/your/images --output ./

This generates a library.json manifest and creates optimized versions at multiple resolutions (2K, 4K, 8K) so the viewer can serve the right size for each device.


File Structure

After setup, your project should look like this:

your-website/
├── index.html              ← Your page with the viewer
├── 360-viewer.json         ← Gallery configuration
├── assets/
│   └── avatar.jpg          ← Your avatar (optional)
├── library/
│   ├── library.json        ← Generated image manifest
│   └── images/             ← Your 360° images
└── 360-viewer/             ← The viewer (submodule or clone)
    ├── core/
    │   └── phong-360-viewer-core.js
    ├── extensions/
    │   ├── phong-360-multi-image.js
    │   └── phong-360-library-ui.js
    └── css/
        ├── styles.css
        └── phong-360-ui.css

Customization & Theming

360 Viewer uses CSS custom properties, making it easy to match your website's design:

:root {
  --viewer-accent: #ff9f95;
  --viewer-bg: #1a1a2e;
  --viewer-text: #e0e0e0;
  --viewer-panel-bg: rgba(0, 0, 0, 0.85);
}

For full theming documentation, see the Theming Guide on GitHub.


Forking & Contributing

360 Viewer is MIT-licensed — fork it, customize it, make it yours. Some ideas:

  • Custom templates — Create new gallery layout renderers
  • Branding — Restyle the UI to match your brand
  • Integration — Embed it in React, Vue, or Svelte apps
  • Features — Add hotspots, annotations, or video support

To contribute back:

  1. Fork the repository on GitHub
  2. Create a feature branch
  3. Submit a pull request

More Resources

Esc
Searching...
No results found.
Type to search the documentation
Navigate Select Esc Close

We use cookies for analytics to understand how visitors use our site. Privacy Policy