121

Photo Sphere Gallery

£10 or the whole Vault, £99

A grid of photos folds into a spinning 3D sphere you can fling around, then flies into a cube, a heart or back into a grid at the press of a button. Click any photo to lift it out at full size.

advanced
16 more details
3d-transformsmorphingmomentumspring-physicsstaggerpointer-dragtouch-dragdepth-fallofflightboxshared-elementfocus-managementload-sequenceambientviewport-aware-tickerkeyboard-navigationprogressive-enhancement

This demo reads better at your own screen size than in the frame below:

Released

About this effect

A wall of photographs that does not stay flat. On load the grid peels apart and folds itself into a globe of cards, which then turns slowly on its own. Grab it and it stops dead like a globe under your hand; drag to turn it and tilt it, and let go mid-swipe to fling it, with the spin easing back down to its idle pace in the direction you threw it.

Read the full effect overview

The same cards rearrange on command. Cube packs them onto six faces, Heart fills a heart outline and puffs it forward so it still reads as an object when it sways, and Grid lays them flat again. Each card takes its own staggered flight to the slot nearest where it started, blooming outwards mid-flight so the cards clear each other, and the shape keeps turning while they travel. Cards on the far side fade into the background, so the depth reads even in a still frame.

Click a photo and the shape turns to bring it to the front, then the card lifts out of the shape and opens to fill the gallery, swapping in a larger file at the photo's own proportions. Close it and it flies back into its slot, and the spin picks up where it left off.

Photo Sphere Gallery - GSAP animation effect preview

What's included

13 items
  • Four shapes from one set of cards: sphere, cube, heart and grid, each rebuilt for the stage size
  • Drag or swipe to spin and tilt, with a fling that eases back to the idle spin in the direction you threw it
  • Catch-to-stop: pressing on a spinning shape halts it under the pointer
  • Staggered flights between shapes that bloom outwards mid-air, matched so cards travel to the nearest free slot
  • Facing shapes (heart and grid) turn under a drag and spring back with a slight overshoot
  • Click to enlarge: the shape turns the photo to the front, it lifts out to full size with a larger file and its real proportions, and flies back into place on close
  • Depth shading: cards behind the centre fade towards the background colour
  • Opening sequence folds the page's own photo grid into the sphere, so there is no jump when the script takes over
  • Works with any number of cards from about 20; every shape lays itself out for the count
  • Arrow keys spin and tilt, Enter enlarges the photo at the front and the arrows step through photos in the enlarged view; the shape buttons are native toggle buttons
  • Pauses its animation loop off screen and in background tabs
  • Reduced motion: no idle spin or fling, and shape changes cross-fade instead of flying
  • No JavaScript: the photos remain an ordinary responsive grid

Perfect for

4 use cases
  • Photographer and studio portfolios that want a memorable first screen built from their own work
  • Moodboards, reference libraries and archives where browsing a lot of images is the point
  • Event, festival and campaign pages showing a wall of attendee or community photos
  • Product and collection launches where a heart or cube shape can tie into the campaign

How it works

3 sections

Each photo is a card positioned in real CSS 3D space inside two nested layers: the outer one tilts, the inner one spins. Every shape is just a list of positions and orientations computed for the current stage size: latitude rings for the sphere, a 3 × 3 grid on each cube face, a filled heart outline with a domed depth, and a best-fit flat grid. When you choose a shape, each card is matched to the free slot nearest its place on the sphere, and GSAP tweens its position, rotation and scale there with a small per-card delay and a mid-flight bloom.

The spin, the fling and the spring back to facing are a small physics step on the GSAP ticker, which also writes every card's transform and its depth shade. The loop sleeps whenever nothing is moving, the stage is off screen or the tab is hidden. A change in motion preference rebuilds the gallery in place, and one teardown call returns the markup to the plain grid.

Enlarging tweens the spin so the chosen card faces the viewer, measures where it lands on screen, and hands over to a flat copy laid over the gallery, which GSAP grows to the largest box of the photo's proportions that fits. Closing measures the card again and flies the copy back to it.

Difficulty Advanced
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this effect's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Paid effect

Purchase to unlock the code.

Buying Photo Sphere Gallery opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£10 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £99, one payment.

Documentation

Quick Start

1. Add to your HTML <head>:

Code snippet omitted: it ships with the download.

2. Add the gallery to your <body>:

Code snippet omitted: it ships with the download.

3. Add before the closing </body> tag:

Code snippet omitted: it ships with the download.

The script finds every .photo-sphere on the page. It measures where each card sits in the plain grid, switches the gallery into 3D, and flies the cards from those cells into the starting shape.

Using It With Your Own Design

What the effect needs from your markup: the four nested hooks .photo-sphere > .photo-sphere__stage > .photo-sphere__world > .photo-sphere__cards, with one .photo-sphere__card per photo. The stage is the drag surface and holds the perspective; the world layer tilts and the cards layer spins, so keep them nested in that order. Shape buttons are any element with data-formation-to inside .photo-sphere; the script keeps their aria-pressed in step. A card can hold anything square-ish: an <img>, a <picture>, or an <a> wrapping an image (a drag that ends on a link does not follow it).

Enlarging: a click on a card that is not a drag enlarges its <img>. Give each image a data-full with a larger file (the demo uses 1100px wide); it starts loading on the click and is shown at its own proportions, so a square card can open into a landscape or portrait photo. Without data-full the card's own file is shown, at no more than twice its size. A card holding a link stays a link and never enlarges. The script builds the enlarged view (.photo-sphere__viewer, holding .photo-sphere__backdrop, .photo-sphere__photo and .photo-sphere__close) inside .photo-sphere, so it covers the gallery rather than the whole page. Style those four classes however you like; .photo-sphere needs position: relative for the view to sit over it.

What is only the demo's styling: the dark ground and its soft radial glow, Mona Sans, the pill-shaped control bar and the cue line. Card corner radius is --psg-radius. Restyle or replace all of it. The script never reads a class from the control bar or the cue.

CSS the effect depends on:

  • .photo-sphere.is-3d rules: the world and cards layers are position: absolute at the stage centre with transform-style: preserve-3d, and each card is position: absolute and sized by --psg-card. Don't put overflow, opacity, filter or clip-path on the world or cards layers: each one flattens the 3D.
  • .photo-sphere.is-3d .photo-sphere__stage uses perspective: var(--psg-perspective). The script sets both custom properties from the stage size.
  • .has-js .photo-sphere gives the gallery a fixed height (100svh in the demo). Size it however you like, but give the stage a real height: every shape is fitted to it.
  • touch-action: pan-y on the stage lets horizontal swipes spin the shape while vertical swipes still scroll the page.
  • .photo-sphere__card::after is the depth shade. It reads --psg-shade and paints --psg-shade-colour, which should match whatever is behind the stage.
  • Without the is-3d class, .photo-sphere__cards is a CSS grid. That is the no-JavaScript layout and the opening frame.

Options

Attribute Values Default Description
data-formation sphere, cube, heart, grid sphere The shape the cards fly into first
data-auto-rotate true, false true Idle spin for the sphere and cube, gentle sway for the heart
data-spin-speed degrees per second 9 Idle spin speed
data-intro true, false true Fold out of the grid on load. false starts in the shape
data-enlarge true, false true Click a photo to enlarge it. false leaves the cards inert

On each card's <img>, data-full is the larger file shown when it is enlarged.

The shape buttons take a data-formation-to with one of the four shape names.

Custom property Set by Description
--psg-shade-colour you Colour the far side fades towards (the demo uses the page ground)
--psg-radius you Card corner radius
--psg-card script Base card size for the current stage
--psg-perspective script Stage perspective for the current stage

Accessibility

  • Keyboard: the stage is focusable. Left and Right arrows spin the shape (each press adds a nudge), Up and Down tilt it. While the stage has keyboard focus the idle spin waits and the photo nearest the front is ringed (.is-front); Enter or Space enlarges it. The enlarged view is a modal dialog labelled with the photo's alt text: focus sits on its close button, Left and Right step through the described photos while the shape turns each one to the front behind it, Escape or any click closes it, and focus returns to the stage. The photos are not individual buttons, because cards seen edge-on at the side of a sphere are too thin to be usable touch targets. The shape buttons are native <button> toggles with aria-pressed.
  • Reduced motion: there is no idle spin or fling, and dragging moves the shape directly without inertia. Shape changes cross-fade in place instead of flying, the enlarged photo fades in and out instead of lifting, and the opening sequence is skipped. If the preference changes while the page is open, the gallery rebuilds itself.
  • No JavaScript: the cards stay an ordinary responsive grid and the shape buttons are hidden, since they would do nothing.
  • Alt text: give each distinct photo a description. If you repeat photos to fill the shape, mark the repeats alt="" so screen readers don't read them twice; they still enlarge on click, and the arrow keys in the enlarged view skip them.
  • The animation loop stops while the gallery is off screen, while the tab is hidden, and whenever nothing is moving.

Dependencies

Required:

  • GSAP 3.12+ (the demo is built against 3.15.0)

No GSAP plugins and no Lenis: it is a pointer effect and never scrolls the page.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.