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.
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.
Full Gallery: Multiple Images with UI
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">
2. Initialize the Gallery
<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) |
Gallery Templates
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
Option A: Git Submodule (Recommended)
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:
- Fork the repository on GitHub
- Create a feature branch
- Submit a pull request
More Resources
- GitHub Repository — Source code, issues, and releases
- Quick Start Guide — 5-minute setup
- API Reference — Full API for all layers
- Library Format Spec —
library.jsonformat - Templates Guide — Template system docs
- Deployment Guide — Production deployment
- Fork Guide — Full setup & config reference