Spin360 is a tiny web component that turns an image sequence into a smooth, draggable 360° product view. No framework, no dependencies, no build step.
Load the module, from a CDN or from your own copy, and add the tag:
<script type="module" src="https://cdn.jsdelivr.net/gh/ahmettasdemirusa/spin360@v1.0.0/spin360.js"></script>
<spin-360 src="/images/mug/{i}.webp" frames="36" pad="2" alt="Ceramic mug"></spin-360>
{i} is replaced by the frame number. pad="2" turns it into 00, 01 … 35. The viewer takes the aspect ratio of your images and the width of its container.
Put every frame in a single image, in a grid, and tell Spin360 how many columns it has. This one is a 6 × 6 grid of 36 frames, about 100 KB in total.
<spin-360 sprite="mug-sprite.webp"
frames="36" columns="6"></spin-360>
| Attribute | What it does |
|---|---|
src | URL pattern for the frames, with {i} for the frame number |
pad | Zero-pad the frame number to this many digits |
sprite · columns | Use a single sprite-sheet image instead of separate files |
frames | Number of frames (default 36) |
start | Frame to show first |
autoplay · speed | Turn on its own at speed frames per second (default 12). Stops on first interaction, and never starts for users who prefer reduced motion. |
drag-speed | Drag sensitivity multiplier (default 1: one full turn per viewer width) |
reverse | Invert the drag and arrow-key direction |
no-loop | Stop at the first and last frame instead of wrapping around |
no-inertia · no-hint | Turn off coasting after a flick, or the "Drag to rotate" hint |
eager | Load immediately instead of when the viewer scrolls near the viewport |
alt | Accessible label for screen readers |
const viewer = document.querySelector('spin-360');
viewer.goTo(9); // jump to a frame
viewer.next(); viewer.prev();
viewer.play(); viewer.pause();
viewer.frame; // current frame
viewer.addEventListener('spin360:change', (e) =>
console.log(e.detail.frame, e.detail.angle));
viewer.addEventListener('spin360:load', () => {});
// Switch colorway: the angle is kept
viewer.setAttribute('src', '/img/blue/{i}.webp');
The viewer is a focusable role="slider" that announces its angle, e.g. "90°".
| Key | Action |
|---|---|
| ← → ↑ ↓ | Rotate one frame |
| Page Up / Down | Rotate 45° |
| Home / End | First / last frame |
| Space | Play / pause |
Style it with CSS custom properties: --spin360-accent, --spin360-focus, --spin360-hint-bg, --spin360-hint-color, or with ::part(canvas|progress|hint).