084

Threaded Image Slider

£5

A photographic slider with a fuller row of images and restrained threads that fan vertically at the edges, with touch dragging, momentum and centre snapping.

advanced
6 more details
webgl-shaderinfinite-loopdraggablemomentumsnapvelocity-reactive
Threaded Image Slider - GSAP animation effect preview

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

About this effect

A fuller row of photographs stays intact through the middle of the stage. At the outer edges, restrained image threads open into a gentle vertical fan.

Read the full effect overview

Drag or swipe to pull the strip, then release to settle on a photograph. Buttons and arrow keys follow the same continuous rail, with a readable image gallery whenever reduced motion, WebGL or JavaScript calls for it.

What's included

9 items
  • Restrained horizontal threads that fan vertically at the outer edges
  • Smaller desktop slides reveal more of the image collection
  • Complete, sharp central photograph with cover-fitted imagery
  • Infinite dragging with projected momentum and precise centre snapping
  • Previous and next buttons, arrow keys, Home and End navigation
  • Touch composition with a fully intact focal image
  • Gesture-led flutter that settles when movement ends
  • Optional automatic browsing with an explicit pause control
  • Semantic image fallback, live motion-preference handling and GPU cleanup

Perfect for

4 use cases
  • Photography portfolio sliders
  • Fashion and campaign lookbooks
  • Art direction project galleries
  • Visual collection highlights

How it works

1 section

Three.js renders each photograph as independent image bands, with position-based displacement opening them into threads at the stage edges. GSAP manages responsive motion preferences, navigation targets, frame scheduling and teardown. The continuous loop smooths travel and derives a gesture-speed envelope; semantic HTML supplies the images, captions, controls and fallback gallery.

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

Lighthouse, as measured

Google Lighthouse on this effect's demo, 15 September 2026. 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 Threaded Image Slider 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.

£5 Standard license, unlimited projects

Browse free effects

Documentation

Quick Start

Copy this folder and serve index.html over HTTP. The images are local; GSAP, three.js and the optional demo font load from CDNs.

For an existing page, copy the <main data-thread-slider> markup from index.html, the stylesheet, the inline head boot, and the dependency scripts. Keep the source list and all documented controls. The head boot probes WebGL before first paint and restores the image rail if a dependency fails or takes too long. It must precede the stylesheet:

Code snippet omitted: it ships with the download.

Place these scripts after the source markup:

Code snippet omitted: it ships with the download.

Already importing three.js? Set window.THREE to that module before loading assets/script.js, and omit the import-map shim. Avoid loading a second copy.

Using It With Your Own Design

The script uses data attributes, so decoration can change independently. Keep one [data-thread-slider] root, a [data-thread-stage], and a [data-thread-source] list. Each list item must contain an image and a figcaption. Keep [data-thread-count], [data-thread-caption], [data-thread-status], [data-thread-controls], and the native [data-thread-prev] / [data-thread-next] buttons. The status element should retain role="status" and aria-live="polite"; the root needs tabindex="0" for arrow navigation.

The demo font, caption styling, footer spacing and circular button treatment can be removed. Give the root a real height and preserve the stage's relative positioning, overflow clipping, touch-action: pan-y, the canvas positioning, and the source rail's native overflow / scroll snap. Preserve the html.gl and .is-live visibility gates and reduced-motion override. The source images are also the texture source, so do not remove them after startup.

The supplied page is a viewport demo. When embedding in a normal page, remove the demo's body { overflow: hidden } and set .thread-slider to the section height you want. Vertical touch gestures remain available to the surrounding page. This effect does not intercept the wheel.

The canvas uses a neutral #141414 clear colour. If changing the page ground, update renderer.setClearColor in the script to match --page in CSS. Texture colour itself is passed through without a grade; only displaced threads receive a small light variation.

Options

Set these attributes on [data-thread-slider] before initialization.

Attribute Default Purpose
data-enabled true false keeps the native image rail and navigation.
data-strength 1 Thread displacement multiplier, clamped to 0–1.8. Zero removes displacement but retains edge thinning.
data-threads 26 Horizontal bands per photograph, clamped to 8–60.
data-auto 0 1 advances every four seconds and inserts a play/pause button. Off by default and under reduced motion.

For example, a coarser, more restrained treatment:

Code snippet omitted: it ships with the download.

Choosing Your Images

Horizontal threads reveal vertical structures especially well: silhouettes, garment seams, a face against a clear background, or strongly shaped architecture. Give the subject breathing room and choose visibly different neighbouring photographs. Fine horizontal lines alone can disappear into the bands. Test every image both centred and at the edge, including the phone crop.

Images are cover-fitted, preserving their proportions. The demo uses 3:4 frames. Landscape originals work, but their outer sides will crop. Keep essential subjects near the centre. Five photographs ship with this example; keep at least five for a dense infinite rail at normal desktop widths. The repeated rail keeps wide stages populated. Desktop photographs are capped at 400px high so more images share the stage.

Replace assets/img/*.webp, update image dimensions and descriptive alt text, and change the captions. For the repository asset pipeline, edit assets/img-manifest.json and run bun scripts/build-template-assets.ts threaded-image-slider from the GSAP Vault repository. The download already contains the baked assets and does not need that pipeline.

Public Controls and Cleanup

Each root exposes its own API:

Code snippet omitted: it ships with the download.

position and target use photograph pitches, while index is wrapped into the source list. Input can interrupt an active settle. For deterministic captures, window.__thumbnail() selects the second photograph and freezes the renderer using the same shaders; root.threadSlider.freeze(false) resumes it. render() draws synchronously for a pixel probe.

Before removing the demo or changing routes, call:

Code snippet omitted: it ships with the download.

This reverts the owned media contexts, kills owned navigation tweens, removes listeners and observers, releases pointer capture, disposes textures/geometry/materials, and releases the WebGL context. It also restores the source rail and caption state. Use revert(), not kill(). Live motion-preference changes destroy or rebuild the scene automatically. Multiple roots share this page-level cleanup handle while keeping separate navigation state.

Accessibility

Native buttons and a focusable root support keyboard browsing, including arrow keys, Home and End. The selected caption is announced after navigation. The central photograph is fully intact at rest on phones, and horizontal touch drag coexists with vertical page gestures.

Reduced motion uses the ordinary image rail with instant navigation. No JavaScript, WebGL2 unavailable, disabled effects, failed image decoding and blocked dependencies all retain the same semantic image source. Without JavaScript the browser's native horizontal rail remains usable. Automatic browsing is optional and includes an explicit pause control.

Dependencies

Dependency Version Responsibility
GSAP core 3.15.0 Media contexts, navigation target tweens, frame scheduling and cleanup.
three.js 0.180.0 BufferGeometry, texture handling and shader rendering through WebGL2.

No GSAP plugins and no Lenis. The continuous loop owns frame-rate-independent position chase and the gesture-speed envelope; the shaders deform and thin the image bands.

Browser Support

The animated view needs WebGL2 and ES module/import-map support. The head and runtime probes check WebGL before constructing a renderer. Unsupported or blocked environments receive the source rail. A lost GPU context temporarily restores that rail; when restored, the selected image returns to the canvas.

Performance

The demo repeats five source photographs across fifteen meshes, sharing textures and geometry; offscreen meshes are culled. Each pixel takes one photograph sample. Rendering pauses outside the viewport and while the document is hidden; no ambient thread drift runs at rest. Pixel ratio is capped at 2 on fine pointers and 1.5 on coarse pointers.

On constrained devices, first lower the renderer's pixel-ratio cap, then reduce data-threads or the geometry segment count. Resize is observed on the stage so an iframe or parent layout change updates the canvas. All textures and the GPU context are disposed on teardown.

Image Credits

The bundled WebP files are portrait crops of the sources below, recorded in assets/img-manifest.json. Replace the demo photographs for your production project. Source photography is supplied under the respective Unsplash or Pexels licence; the effect's code licence does not transfer ownership of stock photography.

Interaction inspiration: Unwoven by Clément Grellier. This effect uses an independent implementation and independently sourced imagery.

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

Your cart

Your cart is empty

The Vault £99

The Vault library, plus future additions to the library.