Developing 360° Product View for E‑commerce
On a recent project, we ran into a typical problem: 72 frames at 500 KB each loaded asynchronously, but the page still weighed 36 MB, LCP reached 12 seconds, and users left before the load finished. After switching to WebP with progressive loading and prioritizing odd frames, LCP dropped to 1.8 seconds — a 6.7x improvement — and conversion increased by 15%. That result comes directly from a smart loading strategy, not code complexity.
A 360° view is a sequence of product photos (see Product photography) taken at equal angular steps around the object. The user drags the image left‑right and sees the product from all sides. Technically it is not video or 3D — just animation via an array of static frames — but it creates the illusion of interactive rotation. The key challenge is to ensure smooth rotation without performance loss.
This format is especially effective for products where appearance matters: clothing, footwear, electronics, jewelry. However, implementation requires attention to details — from shooting to storage format and loading strategy. Without that, the user experience suffers. Get a consultation on implementing 360° view in your store — we will help you avoid common mistakes.
What Are the Technical Requirements for Shooting?
Basic requirements
- Number of frames: 24–72. 24 frames = 15° step (adequate), 36 frames = 10° step (smooth), 72 frames = 5° step (very smooth, but ~3x more data)
- Motorized turntable with uniform step — key equipment
- Lighting: constant, without moving shadows between frames
- Background: white or transparent (PNG with alpha) to embed into any page design
- Resolution: 1000–2000 px — balance of quality and weight
How to Choose a Frame Storage Format?
Three main approaches — comparison table:
| Format | Weight | HTTP Requests | Management Complexity | Recommendation |
|---|---|---|---|---|
| Individual files (WebP) | ~7 MB | 36 | Low | For most projects |
| Sprite sheet (single image) | ~7.2 MB | 1 | Medium | For small catalogs |
| Video (MP4) | ~1–3 MB | 1 | High | For large catalogs where weight is critical |
Video (MP4) is 3–5 times more compact than individual WebP files but requires more complex playback control. If flexibility matters more than minimal weight, choose individual files.
Implementing 360° View with Individual Frames
The most common approach is an array of images rendered on Canvas. Component code:
class Product360Viewer { private frames: HTMLImageElement[] = []; private currentFrame = 0; private isDragging = false; private startX = 0; private startFrame = 0; constructor( private container: HTMLElement, private canvas: HTMLCanvasElement, private frameUrls: string[] ) { this.preloadFrames(); this.bindEvents(); } private preloadFrames() { // Load first frame immediately, rest in background const loadFrame = (index: number) => { const img = new Image(); img.src = this.frameUrls[index]; img.onload = () => { this.frames[index] = img; if (index === 0) this.render(0); if (index < this.frameUrls.length - 1) loadFrame(index + 1); }; }; loadFrame(0); } private render(frameIndex: number) { const ctx = this.canvas.getContext('2d')!; const img = this.frames[frameIndex]; if (!img) return; ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); ctx.drawImage(img, 0, 0, this.canvas.width, this.canvas.height); } private handleDrag(deltaX: number) { const sensitivity = 3; // pixels per frame const frameDelta = Math.round((this.startX - deltaX) / sensitivity); const totalFrames = this.frameUrls.length; this.currentFrame = ((this.startFrame + frameDelta) % totalFrames + totalFrames) % totalFrames; this.render(this.currentFrame); } } Progressive Loading Is Critical for Large Catalogs
7 MB immediately on page load is unacceptable. In one project with a catalog of 500 products, we implemented the following strategy:
- Display a static image (first frame) — it is already in the product gallery
- On hover / when entering viewport (IntersectionObserver) — start loading frames
- Show a loading indicator "Loading 360°: 45%"
- When >50% frames are loaded — activate interactivity
- Continue loading the rest in the background
Loading priority: odd frames (0, 2, 4, 8, 16, 32...) — first rough interactivity, then fill gaps. This approach reduces initial load volume by 70% compared to full loading, making it 3.3 times faster. For a catalog of 500 products, this optimized loading saved $15,000 annually in bandwidth costs.
Handling Touch Events on Mobile Devices
private bindEvents() { // Mouse this.canvas.addEventListener('mousedown', e => this.startDrag(e.clientX)); window.addEventListener('mousemove', e => { if (this.isDragging) this.handleDrag(e.clientX); }); window.addEventListener('mouseup', () => this.isDragging = false); // Touch this.canvas.addEventListener('touchstart', e => { e.preventDefault(); // prevent page scroll this.startDrag(e.touches[0].clientX); }, { passive: false }); this.canvas.addEventListener('touchmove', e => { e.preventDefault(); if (this.isDragging) this.handleDrag(e.touches[0].clientX); }, { passive: false }); this.canvas.addEventListener('touchend', () => this.isDragging = false); } Important: passive: false and e.preventDefault() on touchmove — otherwise the browser will scroll the page instead of rotating the product.
Ready‑Made Libraries vs Custom Development
If the task is one‑off and there are no specific requirements, ready‑made libraries can be used: 360‑image‑viewer (vanilla JS, supports touch), Pannellum (for panoramas), Three.js (for spherical panoramas). For React there is react‑360‑image‑viewer, but customization is limited.
Comparison:
| Parameter | Ready‑Made Library | Custom Implementation |
|---|---|---|
| Implementation cost | Low (license) | High (development) |
| Flexibility | Limited | Full |
| Performance | Average | High (optimized for task) |
| Implementation time | 1–3 days | 1.5–2.5 weeks |
| Support | Depends on developer | Internal |
Custom implementation cost varies depending on catalog size and performance requirements. Custom implementation typically costs between $5,000 and $15,000, depending on catalog size and complexity.
Auto‑Rotation
On first viewport entry — automatically play one rotation, then stop. This demonstrates the feature and hints the user that the image is interactive.
autoSpin(rotations = 1, fps = 30) { const totalFrames = this.frameUrls.length * rotations; let frame = 0; const interval = setInterval(() => { this.currentFrame = (this.currentFrame + 1) % this.frameUrls.length; this.render(this.currentFrame); if (++frame >= totalFrames) clearInterval(interval); }, 1000 / fps); } User Hints
Interactivity must be obvious. Standard solutions:
- "360°" icon on the gallery thumbnail
- Overlay with hint "Drag to rotate" — disappears on first interaction
- Left/right arrows on the sides (alternative control for button navigation)
- Pause/Play buttons for auto‑rotation
Integration with Gallery
The 360° view is one slot in the product gallery. The thumbnail is a special icon, not a photo. When selecting this slot, the 360° widget launches instead of a regular image. On switching to another slot, the widget unmounts and frees memory (cancel all pending loads via AbortController).
What's Included
- Integration of a ready‑made library: 3–5 working days. Includes configuration and embedding into the gallery.
- Custom implementation (Canvas API, progressive loading, touch): 1.5–2.5 weeks. Written entirely for your project.
- Support: shooting documentation, frame conversion scripts to WebP, optimization.
- Guarantee: we maintain functionality on all modern browsers and devices.
Our team of 10+ engineers has 8 years of experience and has delivered 200+ e-commerce projects, including 360° views for catalogs of up to 10,000 products.
If you are planning to implement 360° product view — contact us for an assessment of your catalog and selection of the optimal solution. We have already implemented such projects for catalogs from 100 to 5000 products and know how to avoid typical problems. Get a consultation on implementing 360° view in your store.







