3D-Gallery-Effect: The WebGL Gallery You Own, Not Install

StarKnightt turns a 3D image tunnel into a shadcn-style component, using shader math and scroll-driven motion to make a gallery feel alive without a physics engine.

8 min read • View on GitHub • More from StarKnightt

A wide editorial scene of a 3D tunnel made from floating image panels, each panel bending slightly as if caught in wind. The image explains the project's central idea: a premium-feeling gallery that gains depth from layout and shader motion, not from a physics engine.
The central idea is ownership plus motion: a premium-looking gallery that ships as source.

A beautiful and interactive 3D carousel gallery built with Next.js, featuring image and video support with an integrated music player.

StarKnightt, Project Creator and Contributor · StarKnightt/3D-Carousel
Key Takeaways

Most 3D galleries ask you to install a stack. This one asks you to copy a file. That difference sounds small until you notice what it changes: the motion lives beside your app code, the knobs live in props, and the result can be tuned like any other component in a design system.

A gallery you copy into your codebase

The GitHub repo is named 3D-Carousel, but the interesting part is the pattern it points to. The core lives in `src/components/ui/3d-gallery-photography.tsx`, which means the implementation sits where shadcn-style UI belongs, in your source tree. Instead of hiding the rendering behind a package boundary, it makes the whole thing something you are meant to read, edit, and ship.

A hedcut portrait of StarKnightt from a verified GitHub avatar, rendered in black ink on white. It gives a face to a project that otherwise reads like a systems sketch.

That ownership model matters because it changes the cost of ambition. If a gallery is part of your product surface, you want to change spacing, falloff, media mix, and motion rhythm without waiting on a dependency update.

The gallery is not a carousel. It is a moving field

The layout dodges the one thing that makes these interfaces feel cheap: a perfect ring. The images are spaced with a golden-angle pattern so the eye reads drift and depth instead of repetition. It looks more like a field than a track, which is why it feels organic rather than mechanical.

A medium view of image tiles placed along an irregular spiral path, with no obvious grid or orbit. The composition shows how golden-angle spacing avoids the stiff symmetry most 3D galleries fall into.
Golden-angle spacing keeps the scene from collapsing into a neat orbit.

That matters because the component is not trying to mimic a museum wall. It is trying to make a flat set of assets feel like they have inertia, spacing, and atmosphere.

How the illusion works under the hood

The engine is compact. React owns the component shell, `@react-three/fiber` owns the scene, and a custom `ShaderMaterial` does the heavy lifting. The vertex shader bends each panel like cloth under tension. The fragment shader softens the image with a local blur kernel, so the gallery feels cinematic without a separate post-processing chain.

A map of the path from input array to living 3D tunnel.

const GOLDEN_ANGLE = 2.618;

items.forEach((item, i) => {
  const theta = i * GOLDEN_ANGLE;
  item.position.x = Math.cos(theta) * radius;
  item.position.y = Math.sin(theta) * radius;
  item.position.z = -i * zSpacing;
});

useFrame((_, delta) => {
  uniforms.scrollForce.value += (targetScroll - uniforms.scrollForce.value) * 6 * delta;
});
A close-up of one image panel flexing like a sheet under tension, with its edges rippling and the surface softening at the margins. The image illustrates how shader deformation and blur make a flat tile feel physical.
A single panel can carry most of the illusion if the shader is doing the bending.

Wheel, keyboard, and touch all feed the same motion model, and idle time can let the scene recover into motion on its own. The point is not to simulate a real object. The point is to keep the eye convinced.

Why it stays fast

This is where the repo earns its keep. It avoids a physics engine, skips a heavy compositor stack, and keeps blur inside the material instead of applying it scene-wide. If the scene changes every frame, every avoided render matters. The component favors direct uniform updates because the GPU should do the moving, not React.

A split editorial scene contrasts a tall stack of heavy moving parts on one side with a compact, direct mechanism on the other. It explains why the gallery stays smooth when the math stays inside the shader and the frame loop.
The best performance win is often the system you never add.

The result is a deliberate trade-off. It is not physically exact, but it is visually sufficient. That is usually the right bar for interface motion.

What it gets right about the shadcn era

The broader lesson is not about 3D at all. It is about how frontend teams buy complexity now. They want source they can copy, inspect, and reshape. This repo fits that pattern: a premium interaction collapsed into a single component, with the implementation exposed rather than abstracted away.

Compared with other 3D gallery patterns

There are three common ways to do this job. Each solves a different problem, and each has a different cost when the design needs to evolve.

Three gallery patterns appear side by side: a rigid carousel, a dense shader-heavy depth stack, and the project's more organic tunnel. The image helps readers see the project's middle ground at a glance.
The project sits in the useful middle ground between simple carousels and heavyweight shader demos.
ApproachRendering modelAnimation strategyOwnership modelPerformance riskBest use case
CSS3 carousel galleryDOM transformsRotate and zoom with CSS and JavaScriptEasy to read, but styling can sprawlLow GPU cost, limited depthSimple media showcases
Complex Three.js demoWebGL scene graph plus shadersPhysics, post-processing, and a separate animation layerPowerful, but often dependency-heavyHigher tuning and maintenance costOne-off visual experiments
3D-Gallery-EffectR3F with a custom shader materialScroll-driven uniforms and frame-loop updatesCopy into the app and tune the propsFocused, because the math stays localPremium gallery components

The sweet spot is clear. CSS3 carousels are simple but limited. Heavy Three.js experiments can be dazzling but feel like a project of their own. `3D-Gallery-Effect` sits in the middle, which is exactly where a reusable interface component should live.

Who built it, and why that matters

StarKnightt is building in public, and this repo reads like a reusable idea factory rather than a one-off demo. That is what makes it interesting. It is not just a gallery that works. It is a compact proof that ambitious motion can still belong in the codebase instead of outside it.