Trail Collector

ProShowcase & Mediapowered by @vectorvesper/motion

Images peel off the cursor as it moves and fly into empty frames scattered around the page, filling them one by one before fading to make room. The whole arrangement measures its container and scales to fit, so the frames hold together in a panel as well as full bleed. A pointer trail that leaves something behind rather than dissolving.

Trail Collector

Included with membership

Members install Trail Collector with one command and get the full source, the usage code and the Framer remix, licensed for client work. One membership covers the whole library and the CLI.

When to use it

A landing page or an archive where you want the visitor's movement to assemble something — a lookbook that builds itself, a gallery that fills as you explore. It wants a generous stage and a set of frame positions to aim at. It measures its container and scales to fit, so it holds together in a panel as well as full bleed, but it is still a section rather than something you drop into a column.

  • Place frames as percentages and keep them off the centre — the trail spawns under the cursor, and a frame beneath it is hit before it can fly anywhere.
  • Give it more images than frames. Images cycle, so a short list repeats visibly once every frame is full.
  • Vary rotation a little per frame. Identical angles read as a grid rather than as pinned prints.
  • Raise spawnDistance if the trail feels too dense — it is the pointer travel between spawns, so it thins the stream without touching the flight.

Avoid:

  • Do not put frames where your own content sits. The settled images are opaque and stay for several seconds.
  • Do not raise maxActiveFlights far past the default expecting a thicker trail — that is the ceiling on images in the air at once, and every one is animated.
  • Do not use full-resolution photographs. Each image is drawn twice over, small, and many are on screen at once.
  • Do not give two frames the same id; slots are keyed by it and duplicates collect into the same place.

Props

A pointer trail that puts things away. As the cursor moves, images peel off it, hang for a moment, then fly to an empty frame somewhere on the page and settle into it. Frames fill in turn and their contents fade after a while, so the page keeps rearranging itself as long as someone keeps moving.

<TrailCollector />

The trail, the frames and the flight between them. Fills its container and paints its own background from the theme.

PropTypeDefaultDescription
images*TrailImageItem[]—The pictures the trail cycles through. Required — nothing spawns without it.
containers*TargetContainer[]—The frames images fly into, positioned as percentages. Required.
theme"light" | "dark""light"Background and frame colours together. Light is an off-white studio; dark is near-black.
spawnDistancenumber75How far the pointer travels between spawns, in pixels. This is the density control — larger thins the trail without changing how anything moves.
spawnWidthnumber46Width of the small borderless image that leaves the cursor.
spawnHeightnumber62Height of that image at the cursor.
cardWidthnumber135Frame width at full size, used for any container that does not set its own. Scaled down with the stage — see the note on responsiveness — so this is the size on a large screen rather than a fixed one.
cardHeightnumber185Frame height at full size. The aspect ratio it forms with cardWidth is preserved as the stage shrinks, so frames never distort.
collectionDelaynumber320Milliseconds an image hangs at the cursor before it sets off for a frame.
flightDurationnumber1050Milliseconds the flight itself takes.
settleStayDurationnumber4000Milliseconds an image stays fully visible in its frame before it starts to fade.
fadeDurationnumber1600Milliseconds the fade takes. Together with settleStayDuration this decides how quickly frames free up.
maxActiveFlightsnumber8Ceiling on how many images are in the air at once. Raising it thickens the stream and costs proportionally.
titlestring"Trail Collector"Heading rendered over the field.
subtitlestring—Supporting line under the heading — a good place to tell people to move the cursor.
onImageCollected(item: TrailImageItem, targetSlot: TargetContainer) => void—Fires when an image lands and docks in a frame, with both the picture and the slot it filled.
classNamestring""Applied to the wrapper.
styleReact.CSSProperties—Inline styles merged onto the wrapper.
mount"auto" | "eager""auto"When to start collecting. The default waits until the page has frame headroom to spare. Set "eager" to respond to the pointer immediately. Note this defaults the opposite way from the components that build a 3D scene: those start eagerly and take "auto" to defer. Both mean the same thing by "auto" — let the runtime pick the moment — the default just matches what each component already did. Neither setting takes it off the shared frame loop or overrides the reduced-motion preference.

<TrailImageItem />

type

One picture in the rotation.

PropTypeDefaultDescription
id*string—Stable key.
src*string—The picture.
title*string—Caption shown once it settles.
tagstring—Optional secondary label.

<TargetContainer />

type

One frame for images to fly into. Positioned by percentage rather than pixels, so the arrangement holds at any size.

PropTypeDefaultDescription
id*string—Stable key for the slot.
label*string—Badge on the frame, such as FRAME 01.
xPercent*number—Horizontal position, 0 to 100, as a percentage of the container.
yPercent*number—Vertical position, same scale.
categorystring—Optional collection tag shown on the frame.
widthnumbercardWidthOverrides the default frame width.
heightnumbercardHeightOverrides the default frame height.
rotationnumber0Tilt in degrees. Vary it across the set so the frames read as pinned rather than laid out.
It reads the visitor's reduced-motion preference and does not run at all when it is set — no images spawn and the pointer is not tracked. The frames and the heading still render, so the page keeps its structure without anything flying across it.
It measures its own container and scales the whole arrangement to fit, so all ten frames survive on a small stage instead of overflowing it. Frames, spawned thumbnails and flight targets share one scale factor, which runs from full size down to roughly half and never distorts the frame aspect. The heading shrinks below about 850 by 520. Nothing needs configuring — cardWidth and cardHeight describe the large-screen size and everything follows from there.
Cost follows how many images are in flight, which maxActiveFlights caps. The trail spawns by pointer distance rather than by frame, so moving faster does not create more work — it spreads the same spawns further apart.
Client component. It measures its own box to place the frames and reads the pointer, so it has to run in the browser.
Back to all components