REFERENCE
- Gallery page: https://magpui.com/en/i/city-footage-on-a-shattered-sphere-d15a7e
- First frame (image): https://dnioievkvxejjbxgwvko.supabase.co/storage/v1/object/public/media/city-footage-on-a-shattered-sphere-d15a7e/shot.jpg
- Clip (mp4): https://dnioievkvxejjbxgwvko.supabase.co/storage/v1/object/public/media/city-footage-on-a-shattered-sphere-d15a7e/clip.mp4
- Original post: https://x.com/TONASY99/status/2117575043530236181 by @TONASY99
Before building, download the first frame and look at it. If ffmpeg is available, download the clip and extract frames (ffmpeg -i clip.mp4 -vf fps=2 frame-%02d.png), then study the motion frame by frame. Match what you see; the text below describes it, the frames are the truth.
BUILD
A dark, cinematic 3D index of seven cities. In the center of a portrait viewport floats a sphere broken into large curved shards with thin dark gaps between them; each shard shows the same city video, so the sphere reads like a cracked glass ball with footage inside. Scrolling rotates the sphere to the next city: the shards loosen, spin and reassemble while the footage cross-fades. Clicking the sphere opens the city: the shards burst outward, then fly back and lay flat as a honeycomb-like mosaic that fills the whole page, the gaps close, and the video becomes a full-bleed background behind an editorial city profile. A back link returns to the sphere. It should feel heavy, glassy and calm, like a museum installation.
DESIGN SYSTEM
- Canvas: near-black #121010 with a faint warm vignette; portrait-first layout (about 1080x1350 reference) that also works in landscape.
- Header: top-left project title 15px medium off-white #EDEAE6 with a second line '040 - 2026.11' 11px at 55% opacity; top-right 'Seven Cities' 15px and 'One landmark in each' 11px at 55%. 24px page padding.
- Index caption (bottom-left, 24px inset): counter '01 / 07' 11px, then country + local time ('France 04:02') 13px at 70%, then the city name in a tall condensed grotesque, uppercase, about 56-64px, tight tracking, off-white; under it a hint 'Scroll to turn, click to open' 11px at 60%.
- Sphere: radius about 32% of the viewport width, 30-40 shards from a Voronoi split of the sphere surface, gaps 6-10px rendered as dark seams, each shard slightly thick (2-3px bevel) with a soft fresnel rim highlight rgba(255,255,255,0.25) and a faint reflection, giving a glass look.
- City page: video full-bleed, darkened by a gradient from transparent at the top to rgba(10,8,8,0.85) at the bottom; country label 13px, city name 64px condensed uppercase, a 3-4 line intro paragraph 15px/1.5 at 85% opacity, max width 560px; then a two-column fact table (label 12px at 55% left, value 13px right, 6px row gap): Local time, Best time, Getting there, then a gap, Pictured, Footage. Footer row: '<- All cities' link left, 'Next city <name>' right, both 13px with an underline on hover.
- One transition frame is light: during the burst the background briefly flashes to a pale grey #DADADA and the footage desaturates, then darkens again.
MOTION
- Idle: sphere rotates slowly on Y (about 6 deg/s) with a gentle float (translateY +-6px, 4s sine). Shards breathe outward 2-4px on a slow noise.
- Scroll to next city (wheel, swipe or arrow keys, one step per gesture): shards push out 15-25% of the radius with random spin, the sphere rotates 120-180 deg, the video texture cross-fades over 400ms, shards return; total 1100ms, cubic-bezier(0.65,0,0.35,1), stagger 0-120ms by shard index. Caption: old name slides up 24px and fades out (250ms), new name slides in from 24px below (350ms, cubic-bezier(0.22,1,0.36,1), 120ms delay); time ticks live.
- Open (click): phase 1 burst, shards fly outward 1.5-2.5x radius with random rotation, 500ms cubic-bezier(0.22,1,0.36,1); phase 2 flatten, each shard flies to its slot in a full-screen 2D hexagon-ish Voronoi mosaic facing the camera, 900ms cubic-bezier(0.65,0,0.35,1), stagger 0-250ms from the center outward; phase 3 the seams shrink from 8px to 0 over 400ms and the shards merge into one continuous video. Text of the city page fades up 16px with a 60ms stagger per line after the mosaic lands.
- Close ('All cities'): exact reverse, seams open, shards curl back onto the sphere, 1200ms.
SECTIONS
Parts: header, sphere of shards, index caption with counter and hint, city page (hero video, title, intro, fact table, footer nav). States: idle, hover (sphere scales 1.03 and shards part 4px, cursor pointer), turning, opening, city page open, closing.
IMPLEMENTATION
- Three.js with TypeScript. Build the shards once: generate a spherical Voronoi (Fibonacci-sphere seed points + nearest-point cells), triangulate each cell, inset its edges for the seam and extrude it slightly. Give each shard two target transforms: its place on the sphere and its place in a flat 2D Voronoi mosaic that covers the viewport plane (compute the 2D cells from the same seed order so each shard has a partner).
- One VideoTexture per city (muted, loop, playsInline), shared by all shards. In a custom ShaderMaterial blend the sphere projection (equirectangular UV from the shard's world normal) with the screen-space UV of the flat mosaic using a uniform uFlatten 0 to 1, so the footage lines up as one image when flat. Add fresnel rim and a subtle refraction offset, and a uCrossfade uniform between two videos.
- Drive every phase with GSAP timelines (or a small tween engine) on per-shard progress values; keep the DOM text in HTML over the canvas.
- prefers-reduced-motion: no burst or spin; cities cross-fade on a static sphere and opening is a 300ms fade to the city page.
- Keyboard: arrow keys or PageUp/PageDown change city, Enter opens, Escape or Backspace returns; the sphere has an accessible button role with the city name as label; visible focus ring.
- Performance: under 60k triangles total, only the current and next video playing, pause videos when the tab is hidden, cap devicePixelRatio at 2, fall back to a poster image on low-power devices.
ADAPT TO THE PROJECT
Reuse the project's existing design tokens, components and fonts where possible and map the colors above to the closest existing tokens. Never copy the original's name, footage, photos or copy: use your own licensed or placeholder city videos and placeholder text.
SUCCESS CHECK
- Scrolling one step rotates the shattered sphere to the next city, cross-fades the footage and updates the counter, name and live local time.
- Clicking bursts the shards and lands them as a flat full-page mosaic whose seams close into one continuous video behind the city profile, and 'All cities' reverses it.
- With reduced motion the cities still change and open with simple fades and every control works from the keyboard.