{"_id":"@ansonphong/360-viewer","_rev":"6-b119c00d446e7d65b60f7248ba7278ef","name":"@ansonphong/360-viewer","dist-tags":{"latest":"6.0.5"},"versions":{"6.0.0":{"name":"@ansonphong/360-viewer","version":"6.0.0","license":"MIT","_id":"@ansonphong/360-viewer@6.0.0","maintainers":[{"name":"ansonphong","email":"phong@phong.com"}],"dist":{"shasum":"ae157398adec45c6839e8a74fa45334edd310e57","tarball":"https://registry.npmjs.org/@ansonphong/360-viewer/-/360-viewer-6.0.0.tgz","fileCount":6,"integrity":"sha512-mCHJezUUZNm1oE6H4Le/GmhYW1q+bmdETOcwtA+XVno5CCRCDp/mUWP+8sfSLfLiZlizL4lTrjHuzCmfjgC/bg==","signatures":[{"sig":"MEUCIHR8BhGhlGRGTsS1isoSrSvXeYtvgbrUrdk5HhS+gNdqAiEAtlM8cqab+n0fR090LDRxXET3DQAdNhReW+z2ZK1qZIg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":183230},"main":"./dist/viewer.umd.js","module":"./dist/viewer.esm.js","exports":{".":{"import":"./dist/viewer.esm.js","require":"./dist/viewer.umd.js"},"./viewer.css":"./dist/viewer.css"},"gitHead":"582f91c15cd8ef557009968d71dabc0d0f570edc","scripts":{"build":"node build.mjs"},"_npmUser":{"name":"ansonphong","email":"phong@phong.com"},"_npmVersion":"10.9.4","description":"Headless 360 panorama renderer — no DOM beyond canvas","directories":{},"_nodeVersion":"22.22.1","_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.25.0","typescript":"^5.7.0"},"peerDependencies":{"three":"^0.128.0"},"_npmOperationalInternal":{"tmp":"tmp/360-viewer_6.0.0_1778849741244_0.3991373941622296","host":"s3://npm-registry-packages-npm-production"}},"6.0.1":{"name":"@ansonphong/360-viewer","version":"6.0.1","license":"MIT","_id":"@ansonphong/360-viewer@6.0.1","maintainers":[{"name":"ansonphong","email":"phong@phong.com"}],"dist":{"shasum":"6fdac53ba64805fa9dcafdcc5517d6116b82ffa6","tarball":"https://registry.npmjs.org/@ansonphong/360-viewer/-/360-viewer-6.0.1.tgz","fileCount":6,"integrity":"sha512-RC5Q2lG+KEMyWKXPcb8GZsgRwGYwt78Uxb4d9C9E5fISfeDCUIJ/mq1zhhUX4xY7QOvsmSyoj+55rSpmL3FByw==","signatures":[{"sig":"MEUCIQDEx5ZgmdMtxPVYdwsJ+jRk6gmkCpbDeIzMWfw5c0NT8gIgGUkgjsWHkEbtLqUtj/qM40qPaft0BIGBo3rtENlOvAU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":183324},"main":"./dist/viewer.umd.js","module":"./dist/viewer.esm.js","exports":{".":{"import":"./dist/viewer.esm.js","require":"./dist/viewer.umd.js"},"./viewer.css":"./dist/viewer.css"},"gitHead":"8264b1113f0e9d62ba9abea713e2b10a72e69b1b","scripts":{"build":"node build.mjs"},"_npmUser":{"name":"ansonphong","email":"phong@phong.com"},"_npmVersion":"10.9.4","description":"Headless 360 panorama renderer — no DOM beyond canvas","directories":{},"_nodeVersion":"22.22.1","_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.25.0","typescript":"^5.7.0"},"peerDependencies":{"three":"^0.128.0"},"_npmOperationalInternal":{"tmp":"tmp/360-viewer_6.0.1_1778853106045_0.15181247228508354","host":"s3://npm-registry-packages-npm-production"}},"6.0.2":{"name":"@ansonphong/360-viewer","version":"6.0.2","license":"MIT","_id":"@ansonphong/360-viewer@6.0.2","maintainers":[{"name":"ansonphong","email":"phong@phong.com"}],"dist":{"shasum":"a04441822cc8258a53cf63509b39e56029a04c3c","tarball":"https://registry.npmjs.org/@ansonphong/360-viewer/-/360-viewer-6.0.2.tgz","fileCount":6,"integrity":"sha512-68Dzl219E22Fi9izVk+wG8IUMqN9K6OmiC5BpdHqMzGVBiQPKhrlTTrzxo3M5LBh9r27OZoid/TsCI3hsALf7Q==","signatures":[{"sig":"MEUCIQC8nfhLGmlFHe1m7/ouKPLUdGmDhZ4EuWslJBKF3L20rgIgau1LZBiK0yJeqh5x+4367wQlYwZosZu23kJOwQRAlhg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":183331},"main":"./dist/viewer.umd.js","module":"./dist/viewer.esm.js","exports":{".":{"import":"./dist/viewer.esm.js","require":"./dist/viewer.umd.js"},"./viewer.css":"./dist/viewer.css"},"gitHead":"8735792c1cf2a5f8238ff3724ffec1acdb6198c8","scripts":{"build":"node build.mjs"},"_npmUser":{"name":"ansonphong","email":"phong@phong.com"},"_npmVersion":"10.9.4","description":"Headless 360 panorama renderer — no DOM beyond canvas","directories":{},"_nodeVersion":"22.22.1","_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.25.0","typescript":"^5.7.0"},"peerDependencies":{"three":"^0.128.0"},"_npmOperationalInternal":{"tmp":"tmp/360-viewer_6.0.2_1778853234014_0.18871846150758387","host":"s3://npm-registry-packages-npm-production"}},"6.0.3":{"name":"@ansonphong/360-viewer","version":"6.0.3","license":"MIT","_id":"@ansonphong/360-viewer@6.0.3","maintainers":[{"name":"ansonphong","email":"phong@phong.com"}],"dist":{"shasum":"3d0d9a9bf12c57e30e12088ad5723cc678df9dfd","tarball":"https://registry.npmjs.org/@ansonphong/360-viewer/-/360-viewer-6.0.3.tgz","fileCount":6,"integrity":"sha512-SYq23vdsdXBb+BzMMPzWgGl6eQuT5Cu3NdwHvYXQs5jKcMN+wKwioMYsGc9rHUBi2hFDIvM643E/IAhQEpiCBA==","signatures":[{"sig":"MEYCIQCFxlCj/JfqlU6Rc8ixJ9dYdF5cjEAU5e0rzi7jbAsTbQIhAOh/pN45FitprumiVLol5Fr5FpZu/n3/FivAOJXFfk8U","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":183321},"main":"./dist/viewer.umd.js","module":"./dist/viewer.esm.js","exports":{".":{"import":"./dist/viewer.esm.js","require":"./dist/viewer.umd.js"},"./viewer.css":"./dist/viewer.css"},"gitHead":"69beaac76a4fc6c480c5a3e05e6529c7c5780eb8","scripts":{"build":"node build.mjs"},"_npmUser":{"name":"ansonphong","email":"phong@phong.com"},"_npmVersion":"10.9.4","description":"Headless 360 panorama renderer — no DOM beyond canvas","directories":{},"_nodeVersion":"22.22.1","_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.25.0","typescript":"^5.7.0"},"peerDependencies":{"three":"^0.128.0"},"_npmOperationalInternal":{"tmp":"tmp/360-viewer_6.0.3_1778855236001_0.6651526327439568","host":"s3://npm-registry-packages-npm-production"}},"6.0.4":{"name":"@ansonphong/360-viewer","version":"6.0.4","keywords":["360","panorama","viewer","equirectangular","vr","threejs","three","webgl","immersive","photography","little-planet"],"author":{"url":"https://phong.com","name":"Phong"},"license":"MIT","_id":"@ansonphong/360-viewer@6.0.4","maintainers":[{"name":"ansonphong","email":"phong@phong.com"}],"homepage":"https://github.com/ansonphong/360-VIEWER#readme","bugs":{"url":"https://github.com/ansonphong/360-VIEWER/issues"},"dist":{"shasum":"645fb5df50e28d29807154243da535d130d5b8b5","tarball":"https://registry.npmjs.org/@ansonphong/360-viewer/-/360-viewer-6.0.4.tgz","fileCount":8,"integrity":"sha512-8NGVbzUPRJHrfQ/iFLCbIuyI20TBLDaDrmFPoARxt1oNNcw6YL4nPlJ41RC6rA69iRG/GBdAmkWgvAHUNvCGOA==","signatures":[{"sig":"MEYCIQDHSPvv1Uwrb0Wjp5rLR6p+amfZQc+sFX+lDjarP4fSPwIhAKtGZqjk18hEkxDIUgSdI0MWA+wxvWe7RLK717dCVcC0","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":205630},"main":"./dist/viewer.umd.js","module":"./dist/viewer.esm.js","exports":{".":{"import":"./dist/viewer.esm.js","require":"./dist/viewer.umd.js"},"./viewer.css":"./dist/viewer.css"},"gitHead":"69beaac76a4fc6c480c5a3e05e6529c7c5780eb8","scripts":{"build":"node build.mjs"},"_npmUser":{"name":"ansonphong","email":"phong@phong.com"},"repository":{"url":"git+https://github.com/ansonphong/360-VIEWER.git","type":"git"},"_npmVersion":"10.9.4","description":"Ultra-lightweight, headless 360 panorama renderer — Three.js, no DOM beyond canvas, 30KB core","directories":{},"_nodeVersion":"22.22.1","_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.25.0","typescript":"^5.7.0"},"peerDependencies":{"three":"^0.128.0"},"_npmOperationalInternal":{"tmp":"tmp/360-viewer_6.0.4_1779036660525_0.9011196179123102","host":"s3://npm-registry-packages-npm-production"}},"6.0.5":{"name":"@ansonphong/360-viewer","version":"6.0.5","description":"Ultra-lightweight, headless 360 panorama renderer — Three.js, no DOM beyond canvas, 30KB core","license":"MIT","author":{"name":"Phong","url":"https://phong.com"},"homepage":"https://github.com/ansonphong/360-VIEWER#readme","repository":{"type":"git","url":"git+https://github.com/ansonphong/360-VIEWER.git"},"bugs":{"url":"https://github.com/ansonphong/360-VIEWER/issues"},"keywords":["360","panorama","viewer","equirectangular","vr","threejs","three","webgl","immersive","photography","little-planet"],"main":"./dist/viewer.umd.js","module":"./dist/viewer.esm.js","exports":{".":{"import":"./dist/viewer.esm.js","require":"./dist/viewer.umd.js"},"./viewer.css":"./dist/viewer.css"},"peerDependencies":{"three":"^0.128.0"},"scripts":{"build":"node build.mjs"},"devDependencies":{"esbuild":"^0.25.0","typescript":"^5.7.0"},"_id":"@ansonphong/360-viewer@6.0.5","gitHead":"fa6015aa33b961a7068c74a24d1db9a56e802b09","_nodeVersion":"22.22.1","_npmVersion":"10.9.4","dist":{"integrity":"sha512-HPyoWqddL56SE7tGGGn78zHPBWUCniQkpx1IplKJE5avdsokm3HV5T6LdPCnetkpf7xqUIWMtM8tcUM/74uxvg==","shasum":"7552145d1718ebad90a3deac7c4a7a97cf24d45c","tarball":"https://registry.npmjs.org/@ansonphong/360-viewer/-/360-viewer-6.0.5.tgz","fileCount":8,"unpackedSize":206696,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCcx7tj07cTifOtibepOyvNdiSHp+UiJjQ55aLBGdm6OgIhALLVBdQTmvGqPV7F4jS0cfKD3/97cpIPbPP71amlD3Ax"}]},"_npmUser":{"name":"ansonphong","email":"phong@phong.com"},"directories":{},"maintainers":[{"name":"ansonphong","email":"phong@phong.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/360-viewer_6.0.5_1779850853211_0.8803888764377432"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-15T12:55:41.138Z","modified":"2026-05-27T03:00:53.478Z","6.0.0":"2026-05-15T12:55:41.530Z","6.0.1":"2026-05-15T13:51:46.285Z","6.0.2":"2026-05-15T13:53:54.180Z","6.0.3":"2026-05-15T14:27:16.182Z","6.0.4":"2026-05-17T16:51:00.669Z","6.0.5":"2026-05-27T03:00:53.374Z"},"bugs":{"url":"https://github.com/ansonphong/360-VIEWER/issues"},"author":{"name":"Phong","url":"https://phong.com"},"license":"MIT","homepage":"https://github.com/ansonphong/360-VIEWER#readme","keywords":["360","panorama","viewer","equirectangular","vr","threejs","three","webgl","immersive","photography","little-planet"],"repository":{"type":"git","url":"git+https://github.com/ansonphong/360-VIEWER.git"},"description":"Ultra-lightweight, headless 360 panorama renderer — Three.js, no DOM beyond canvas, 30KB core","maintainers":[{"name":"ansonphong","email":"phong@phong.com"}],"readme":"# @ansonphong/360-viewer\n\n**Ultra-lightweight, headless 360° panorama renderer.**\n\nCanvas-only Three.js viewer with no DOM beyond `<canvas>` — wraps the core renderer, multi-image switching, a typed event emitter, theme bridge, and library loader into a single public class.\n\n[![npm version](https://img.shields.io/npm/v/@ansonphong/360-viewer?color=blue)](https://www.npmjs.com/package/@ansonphong/360-viewer)\n[![npm downloads](https://img.shields.io/npm/dm/@ansonphong/360-viewer?color=blue)](https://www.npmjs.com/package/@ansonphong/360-viewer)\n[![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://github.com/ansonphong/360-VIEWER/blob/master/LICENSE)\n[![Three.js r128](https://img.shields.io/badge/three.js-r128-orange)](https://threejs.org/)\n[![Bundle size](https://img.shields.io/badge/core-30KB-brightgreen)](https://github.com/ansonphong/360-VIEWER)\n\n**[Live demo →](https://360.phong.com)** · **[Full docs →](https://github.com/ansonphong/360-VIEWER)** · **[Companion UI package →](https://www.npmjs.com/package/@ansonphong/360-viewer-library)**\n\n---\n\n## Why this viewer\n\n- **30KB core, no build step required** — drop in a `<script>` tag and you have mouse + touch + keyboard panning, pinch-zoom, projection switching, fullscreen, auto-rotation.\n- **Headless on purpose** — no sidebar, no toolbar, no opinion on layout. Pair with [`@ansonphong/360-viewer-library`](https://www.npmjs.com/package/@ansonphong/360-viewer-library) for batteries-included chrome, or wire it into your own UI.\n- **Adaptive resolution loading** — pick from 8K / 4K / 2K variants per image, swap at runtime, with smooth fade-through-black transitions.\n- **One Three.js instance** — peer-deps cleanly with whatever Three the host page already loads.\n- **Latest-wins concurrency** — calling `loadImage()` mid-transition cancels the in-flight load instead of locking up.\n\n---\n\n## Install\n\n```bash\nnpm install @ansonphong/360-viewer three\n```\n\nThree.js r128 is a peer dependency. The viewer expects it on `window.THREE` (UMD) or as an ESM import (ESM bundle).\n\n---\n\n## Quick start\n\n### Option A — Plain HTML + UMD (no build step)\n\n```html\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://unpkg.com/@ansonphong/360-viewer@6/dist/viewer.css\" />\n<script src=\"https://unpkg.com/@ansonphong/360-viewer@6/dist/viewer.umd.js\"></script>\n\n<div id=\"viewer\" style=\"width: 100%; height: 600px;\"></div>\n<script>\n  const viewer = new Phong360Viewer({\n    container: 'viewer',\n    autoRotate: true,\n    autoRotationRate: 1.5,\n  });\n  viewer.loadImage('/panoramas/sunset.jpg');\n</script>\n```\n\n### Option B — ESM (Vite / webpack / Rollup / Next.js)\n\n```js\nimport 'three';                                    // once into window.THREE\nimport { Phong360Viewer } from '@ansonphong/360-viewer';\nimport '@ansonphong/360-viewer/dist/viewer.css';\n\nconst viewer = new Phong360Viewer({\n  container: document.getElementById('viewer'),\n  autoRotate: true,\n});\nawait viewer.loadImage('/panoramas/sunset.jpg');\n```\n\n### Option C — Standalone UMD (no peer-dep coordination)\n\nIf you want one self-contained file that bundles its own Three.js reference resolution:\n\n```html\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js\"></script>\n<script src=\"https://unpkg.com/@ansonphong/360-viewer@6/dist/viewer.standalone.umd.js\"></script>\n```\n\nSame `window.Phong360Viewer` global. Internally uses a shim that resolves `three` to `window.THREE` at parse time — guarantees a single Three.js instance even on pages that already load Three.\n\n---\n\n## Public API\n\n### Constructor\n\n```js\nnew Phong360Viewer({\n  container,             // element or element id (required)\n  libraryUrl,            // optional: library.json manifest for multi-image\n  projection: 'equirect',// 'equirect' | 'little-planet'\n  resolution: 'auto',    // 'auto' | '2k' | '4k' | '8k'\n  theme: 'dark',         // 'dark' | 'light' | 'auto'\n  accent: '#e13e13',     // CSS color for UI accents\n  autoRotate: false,\n  autoRotationRate: 1.0,\n  fov: 75,\n  controls: {\n    enableZoom: true,    // false → mouse wheel scrolls the host page\n    enablePan: true,     // false → drag/keyboard pan disabled, pinch still zooms\n  },\n  loading: {\n    backgroundColor: '#000',\n    fadeInDuration: 500, // ms before swap\n    fadeOutDuration: 500,// ms after paint\n    showSpinner: true,\n  },\n  transition: { /* ... */ },\n  performance: {\n    maxPixelRatio: 2,    // DPR clamp for high-DPI GPUs\n    maxAnisotropy: 8,    // texture filtering ceiling\n    renderMode: 'on-demand', // 'continuous' | 'on-demand'\n  },\n})\n```\n\n### Methods\n\n```js\n// Image loading\nawait viewer.loadImage(url)            // latest-wins\nviewer.selectImage(id)                 // jump to image in library by id\nviewer.nextImage()\nviewer.prevImage()\nviewer.getCurrentImage()\n\n// Library\nviewer.setLibrary(manifest)            // pass a library.json object\nviewer.setSections(sections)\nviewer.getSections()\nviewer.getImages()\nviewer.getLibraryData()\n\n// Runtime controls\nviewer.setAutoRotate(true)\nviewer.getAutoRotate()\nviewer.setProjection('little-planet')\nviewer.setResolution('4k')\nviewer.getResolution()\nviewer.setTheme('light')\nviewer.setAccent('#6366f1')\nviewer.setPerformance({ maxPixelRatio: 1 })\n\n// Render lifecycle\nviewer.pause()\nviewer.resume()\nviewer.isPaused()\n\n// Three.js access (advanced)\nviewer.getContext()                    // { scene, camera, renderer, controls }\n\n// Cleanup\nviewer.destroy()\n```\n\n### Events\n\nSubscribe via `viewer.on(name, handler)` / `viewer.off(name, handler)`:\n\n| Event | Payload | When |\n|---|---|---|\n| `image:loading` | `{ url }` | New image fetch started |\n| `image:loaded` | `{ url, image }` | GPU upload + first paint complete |\n| `image:visible` | `{ url, image }` | Fade-out finished — fully visible to user |\n| `image:error` | `{ url, error }` | Load failed |\n| `library:loaded` | `{ manifest }` | `library.json` parsed |\n| `projection:change` | `{ projection }` | After `setProjection()` |\n| `resolution:change` | `{ resolution }` | After `setResolution()` or auto-pick |\n| `theme:change` | `{ theme }` | After `setTheme()` |\n\nThe container element also dispatches **bubbling CustomEvents** for outside listeners that don't have a viewer reference:\n\n- `phong-viewer-loaded` — `detail: { url }`, fires *after* fade-out (image fully visible)\n- `phong-viewer-paused` / `phong-viewer-resumed`\n- `phong-viewer-error` — `detail: { url, error }`\n\n---\n\n## Theming\n\nAll UI accents are driven by CSS custom properties on the container scope:\n\n```css\n.my-viewer {\n  --pv-accent: #e13e13;\n  --pv-bg: #000;\n  --pv-text: #fff;\n  --pv-surface: rgba(20, 20, 20, 0.85);\n}\n```\n\nOr switch built-in themes at runtime: `viewer.setTheme('dark' | 'light' | 'auto')`.\n\nEngine CSS (`viewer.css`) is canvas-relevant only — overlay, transitions, theme variables. All sidebar/toolbar/info-bar styles belong to [`@ansonphong/360-viewer-library`](https://www.npmjs.com/package/@ansonphong/360-viewer-library).\n\n---\n\n## Bundles in `dist/`\n\n| File | Purpose | Three.js |\n|---|---|---|\n| `viewer.esm.js` | ESM, modern bundlers | peer dep (external `three`) |\n| `viewer.umd.js` | UMD, plain HTML | reads `window.THREE` via shim |\n| `viewer.standalone.umd.js` | Self-contained UMD | reads `window.THREE` via shim |\n| `viewer.css` | Canvas-relevant styles | — |\n\nAll bundles expose the global `Phong360Viewer` (UMD) or named export `Phong360Viewer` (ESM).\n\n---\n\n## Multi-viewer pages\n\nEach viewer instance creates its own loading overlay scoped to its container — no shared global state. To pre-place an overlay (e.g. to prevent FOUC), drop a `<div id=\"loading-overlay\">` inside the viewer's container element and the engine will adopt it.\n\n`loadImage()` is latest-wins. A new call cancels the previous in-flight load; the prior Promise never resolves. Consumers tracking a specific call should `await` its Promise.\n\n---\n\n## Performance controls\n\n```js\nnew Phong360Viewer({\n  container: 'viewer',\n  performance: {\n    maxPixelRatio: 1.5,       // cap DPR on high-density mobile to cut fill cost\n    maxAnisotropy: 4,         // lower texture filtering to free VRAM\n    renderMode: 'on-demand',  // pause render loop when nothing changed\n  },\n});\n```\n\nThe engine also pauses rendering automatically when the canvas is off-screen (IntersectionObserver) and clamps post-resume delta to 100ms so long pauses don't produce camera jumps.\n\n---\n\n## Migration from 5.x → 6.x\n\nPure rename, no behavior changes:\n\n| 5.x | 6.x |\n|---|---|\n| `@ansonphong/360-engine` | `@ansonphong/360-viewer` |\n| `Phong360Engine` class | `Phong360Viewer` class |\n| `dist/engine.*` | `dist/viewer.*` |\n| `--p360-*` / `.p360-*` CSS | `--pv-*` / `.pv-*` |\n| `phong-360-loaded` event | `phong-viewer-loaded` |\n| `p360-help` event | `pv-help` |\n\nThe inner class `Phong360ViewerCore` is **unchanged** — still the core Three.js renderer.\n\n```bash\nnpm uninstall @ansonphong/360-engine\nnpm install @ansonphong/360-viewer\n```\n\n```diff\n- import { Phong360Engine } from '@ansonphong/360-engine';\n+ import { Phong360Viewer } from '@ansonphong/360-viewer';\n```\n\n```bash\n# Sweep CSS\nsed -i 's/--p360-/--pv-/g; s/\\.p360-/.pv-/g' your-styles.css\n```\n\nThe old package remains installable indefinitely with a deprecation notice — existing lockfiles do not break.\n\n---\n\n## Pair with the library UI\n\nNeed a full gallery experience — sidebar with sections, toolbar with controls, glassmorphic info bar with prev/next, deep-linking, theme toggle? Install the companion package:\n\n```bash\nnpm install @ansonphong/360-viewer @ansonphong/360-viewer-library three\n```\n\nSee [`@ansonphong/360-viewer-library`](https://www.npmjs.com/package/@ansonphong/360-viewer-library).\n\n---\n\n## Browser support\n\nModern evergreen browsers (Chrome, Firefox, Safari, Edge). Requires WebGL 1.0 and ES2017+. No IE support.\n\n---\n\n## Links\n\n- **GitHub:** [ansonphong/360-VIEWER](https://github.com/ansonphong/360-VIEWER) — full docs, examples, gallery template, deploy scripts\n- **Live demo:** [360.phong.com](https://360.phong.com)\n- **Companion UI package:** [`@ansonphong/360-viewer-library`](https://www.npmjs.com/package/@ansonphong/360-viewer-library)\n- **Author:** [Phong](https://phong.com)\n- **Issues:** [GitHub issues](https://github.com/ansonphong/360-VIEWER/issues)\n\n---\n\n## License\n\nMIT — see [LICENSE](https://github.com/ansonphong/360-VIEWER/blob/master/LICENSE).\n","readmeFilename":"README.md"}