惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
量子位
G
Google Developers Blog
J
Java Code Geeks
N
Netflix TechBlog - Medium
博客园 - 聂微东
宝玉的分享
宝玉的分享
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
月光博客
月光博客
The Cloudflare Blog
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
雷峰网
雷峰网
M
MIT News - Artificial intelligence
T
Tailwind CSS Blog
V
Visual Studio Blog
阮一峰的网络日志
阮一峰的网络日志
博客园 - 三生石上(FineUI控件)
Microsoft Azure Blog
Microsoft Azure Blog
aimingoo的专栏
aimingoo的专栏
Martin Fowler
Martin Fowler
有赞技术团队
有赞技术团队
T
The Blog of Author Tim Ferriss

Codrops

Drawing With Light: An Exploration of Lit GPU Tubes with TSL and WebGPU | Codrops Building a Real-Time 3D Face Mask with MediaPipe, Threlte and Three.js | Codrops Beyond the Luminance Ramp: A Shape-Aware ASCII Renderer in Three.js | Codrops From Rays to Meshes: Building Vercel’s Prism with vgpu | Codrops More Three.js Speakers, More Ideas from Paris | Codrops Breaking the Frame: Building a Real-Time Datamosh Effect with Three.js | Codrops Bend, Aim, Fling: Turning the Eiffel Tower into a Catapult with Three.js | Codrops Volatile Nexus: Tinkering with Glass, Caustics, Cubes and Sound in Three.js | Codrops Goodgrowth: Boot Sequences, Spinning Discs, and the Art of the Portfolio | Codrops Building a Mouse-Following Square Lens Effect with Three.js and GLSL | Codrops Blender to Three.js and Back: 10 Tips for a Better Workflow | Codrops Sixty Frames for the Record: A Three.js Game, Seven Fly-Throughs, and a Wall of CRTs | Codrops Run Rob Run: Building a Music-Reactive Goo with Three.js and WebGPU | Codrops Relighting Images with Depth Maps and Three.js | Codrops Building an Animated Testimonial Hero Using the GSAP Timeline and Dynamic CMS Data | Codrops Creativity at Enterprise-Scale, Without Compromise: The OFF+BRAND. Story | Codrops Inside HAOQI.DESIGN: Letting DOM and WebGL Share a Retro-Futurist Stage | Codrops From Motion to Meaning: Denis Avramenko’s Approach to Interactive Design | Codrops Creating an Interactive 3D Cluster with Three.js, TSL and Three Start | Codrops Exploring Procedural Geometry with Three.js and WebGPU | Codrops From Brand Systems to Cultural Worlds: Inside Antinomy and 27b | Codrops Designing a Flexible Digital Archive for Chems.Studio’s Creative Practice | Codrops The Department Is Open: Building the PX PUSH Website | Codrops Garden Anomaly: A Tiny WebGPU and TSL Experiment | Codrops A Canvas for Individuality: Creating Websites That Feel Unmistakably Human with Readymag | Codrops Building an Endless Interactive Glass Xylophone with Three.js | Codrops The Story Is in the Interaction: Bonhomme’s Digital Experiences for Luxury Brands | Codrops Building an Infinite GSAP Scroll Gallery with Parallax and Flip Transitions | Codrops Studio Freight: Moving Missions Forward | Codrops Between Print and Digital: The Making of MERSI’s Website | Codrops
Building an Infinite Loom: Unravelling Images into Thread...
By Clément Grellier · 2026-09-05 · via Codrops

An experimental Three.js demo that transforms images into flowing ribbons, weaving them together and unraveling them as they move across the screen.

marquee Three.js WebGL

Editor’s Note: Our Three.js Conference celebration takes a beautifully tactile turn today. Clément Grellier’s “Unwoven” transforms a simple image strip into something wonderfully alive, with photographs gently weaving themselves together and unraveling into threads as they move across the screen. A gorgeous example of how a little Three.js magic can make familiar UI feel completely unexpected.

🧵 Get woven into the action! The very first Three.js Conference is coming to Paris, bringing the community together for two days of talks, ideas, and connections. Use code CODROPS for 15% off and get your ticket →

Most image sliders move pictures around. This one takes them apart.

Unwoven is an endless horizontal strip of image cards, with each card made up of 26 horizontal ribbons rather than a single rectangle. In the middle of the screen, the ribbons sit flush and the card reads as an ordinary photograph. Near either edge of the viewport, they slide out of frame at different speeds, splay apart, flutter, and bleach into the white of the page. Cards arriving from the right weave themselves together, while cards leaving on the left come undone.

Three.js, GSAP, two shaders, one HTML file, no build step.

The mental model

Each of the 26 bands is a ribbon: an independent piece of geometry, two vertices tall and 21 wide, textured with its own horizontal slice of the image. Stacked with no gaps, they form a seamless picture.

Each ribbon then derives two random numbers from its index, which determine how fast it escapes, how far it drifts, and how much it flutters. That difference is the entire effect.

Step 1: Give every thread its own vertices

The obvious approach is to use one big plane with lots of horizontal subdivisions. Don’t. Neighbouring strips in a plane share vertices, and a shared vertex can only be in one place at a time. If strip 4 has slid 300px and strip 5 has slid 80px, the vertex between them has to pick one position, stretching the geometry to cover the difference. You get a rubbery membrane instead of a gap.

So, build the threads separately, each with its own vertices:

for (let t = 0; t < 26; t++) {
  for (let row = 0; row < 2; row++) {          // top and bottom edge
    const v = (t + row) / 26;
    for (let c = 0; c <= segments; c++) {
      const u = c / segments;
      position.push((u - 0.5) * width, (v - 0.5) * height, 0);
      uv.push(u, v);                           // still spans the whole card
      rim.push(row === 0 ? -1 : 1);            // which edge of the thread
      threadId.push(t);                        // used as a random seed
    }
  }
}

Step 2: Slide each thread at a random speed

First, one number telling the shader how close a card is to an edge. Call it tear: 0 in the middle of the screen, 1 at the edge.

float tear = max(
  1.0 - smoothstep(-halfWidth, -halfWidth + zone, x),
  smoothstep(halfWidth - zone, halfWidth, x)
);

Then slide:

float rnd = hash(threadId + seed);
world.x += direction * pow(tear, 1.4) * (60.0 + rnd * 420.0);

That’s the whole effect. rnd differs per thread, so they all travel different distances. Widen 60.0 + rnd * 420.0 and it reads as a comb; narrow it and it reads as motion blur.

Step 3: Open gaps and fade out

The threads are moving apart, but each is still a full-height rectangle, so they still tile with no gaps. Make the gaps by hiding each thread’s edges in the fragment shader:

float edge  = abs(rim);                  // 0 at the thread's middle, 1 at its edge
float width = mix(0.8, 0.2, tear);       // visible width: nearly all, then a core
float alpha = 1.0 - smoothstep(width, width + 0.06, edge);

alpha = mix(1.0, alpha, smoothstep(0.03, 0.30, tear));   // no gaps until they move

color = mix(color, vec3(1.0), smoothstep(0.55, 1.0, tear) * 0.8);   // whiten
alpha *= 1.0 - smoothstep(0.75, 1.0, tear) * 0.65;                  // then vanish

Two things there are worth knowing. The mix(1.0, alpha, ...) line forces alpha to exactly 1 while a card is mid-screen, so a woven card looks identical to a plain photo. And whitening before fading matters: fading alpha alone leaves see-through coloured lines, whereas whitening first means the threads have almost become the page before they disappear.

Things worth playing with

60.0 + rnd * 420.0: controls how staggered the threads are. This is the single biggest lever.

26 threads: around 8 looks like torn paper, while 60 looks like hair.

pow(tear, 1.4): raise the value to keep the photo together longer.

The size of the tear zone: controls how much of the screen unravels at once.

Clément Grellier

French front-end developer who cares about design. My focus is on precise integration and crafting innovative interactions.

Creative Spotlights

Inside the journeys and portfolios of today's most inspiring designers and developers.

Studio Stories

Discover how studios & agencies started, how they work, and what they've built.

Case Studies

Discover the ideas, design, and craft behind today’s most inspiring web experiences.