REFERENCE
- Gallery page: https://magpui.com/en/i/cursor-gravity-image-trail-20badb
- First frame (image): https://dnioievkvxejjbxgwvko.supabase.co/storage/v1/object/public/media/cursor-gravity-image-trail-20badb/shot.jpg
- Clip (mp4): https://dnioievkvxejjbxgwvko.supabase.co/storage/v1/object/public/media/cursor-gravity-image-trail-20badb/clip.mp4
- Original post: https://ui.aceternity.com/interactions/gravity-trail by Manu Arora (@mannupaaji)
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.
ASSETS
This needs real artwork, not shapes drawn in code. Use the files the user gives you (ask where they are). If you have an image generation tool, generate them with these prompts; otherwise leave clearly marked placeholders.
- trail-photo-pack: Set of 8 vertical lifestyle photos for a UI trail demo: coastal aerial, mountain road, ceramic cup on table, green forest path, night city bokeh, desert dune, fresh citrus on marble, abstract fabric fold. Photoreal, varied color, no text, no logos, 3:4 aspect, plain neutral backgrounds where possible.
BUILD: Build a self-contained preview box (about 720×420) with a light background and centered hint text "Move your cursor". As the pointer moves inside the box, small rectangular photo cards spawn at the cursor, get flung with the pointer's recent velocity, then fall under gravity and leave the box forever—no floor, no walls, no bounce. Cards may slightly rotate from the fling. Idle hint fades while trailing. It should feel like tossing Polaroids into open air.
DESIGN SYSTEM: Box: white #ffffff, 1px border #e8e8e8, radius 16–20px, overflow hidden. Hint: Inter/Geist 14–16px, #111 at ~55% opacity, with a tiny cursor glyph in a pill. Cards: 72×96 to 96×128px (portrait), radius 8px, soft shadow 0 8px 24px rgba(0,0,0,0.12), containing colorful placeholder photos (nature, travel, product—generic stock, not branded). Spawn rate tied to pointer speed; cap ~24 live cards.
MOTION: Track pointer positions over ~80–120ms to estimate velocity. On each spawn (throttle ~40–60ms while moving faster than ~40px/s): create card at cursor with vx, vy = velocity * 0.35–0.55 plus tiny random jitter; angular velocity from horizontal speed. Each frame: vy += gravity (1400–1800 px/s²), position += velocity * dt, rotate += ω * dt; remove when fully outside the box bounds (+margin). Hint opacity 1→0 in 200ms after first spawn, back to 1 after 1.2s idle. prefers-reduced-motion: do not spawn a physics trail; show 3 static tilted cards in a gentle arc and a short opacity pulse on the hint instead.
SECTIONS: (1) Preview frame. (2) Hint label centered. (3) Ephemeral photo cards as the only interactive layer.
IMPLEMENTATION: React + requestAnimationFrame (or Motion/Popmotion) with plain DOM/absolute images or a canvas; CSS transforms for position/rotation. No WebGL required. Keyboard focus: box is focusable; arrow keys can nudge a single demo card for a11y. Performance: recycle DOM nodes from a pool; pause RAF when offscreen.
ADAPT TO THE PROJECT: Use the project's card radius, shadow and type tokens. Replace demo photos with the project's own image set or neutral unsplash-style placeholders. Never copy logos or brand photography from the reference.
SUCCESS CHECK:
- Moving the cursor inside the box spawns photo cards that continue with the fling and fall out the bottom/sides.
- Cards never bounce or collide with walls.
- prefers-reduced-motion disables the physics trail and keeps a calm static alternative.