← Back to Blog
·7 min read·

A Three.js Object You Can Orbit

The last article was when I would leave the DOM. This one is the object. Drag it. Switch glass to chrome. The GPU paints the SKU; the copy around it stays HTML. How I wire that island in Next.js — and why it still does not live on the homepage.

Three.jsWebGLNext.jsFrontendAnimationProduct

Live scene — drag to orbit

Shape
Finish

I already wrote when I would pick Three.js over Pixi.js, and why a canvas on a business URL is a bill, not a decoration. That piece was a decision. This one is the object. The scene above this paragraph is the same pattern I would ship for a product page: an island, lazy, disposable, with the sentence you are reading still in the document.

Drag to orbit. Switch the knot for a crystal or a ring. Glass, chrome, ember. That is the commercial job: a SKU the customer can hold, not a PNG carousel of the same three angles. No GLTF download. No 40 MB sofa. Procedural geometry, a physical material, an environment map, bloom on a budget, particles that stop when you leave the viewport.

1. What you are actually looking at

A torus knot, an icosahedron, a torus. Three.js draws them as meshes. The glass finish is MeshPhysicalMaterial: transmission, thickness, IOR, iridescence. Chrome is metalness 1 and a tight roughness. Ember is emissive, the cheap way to make a night-mode SKU feel hot without another light. Around it, a point cloud on a ShaderMaterial — not DOM dots, not a particle library. One draw call.

Glass without an environment is a grey blob. RoomEnvironment plus PMREM gives the mesh something to refract so the transmission reads as volume, not as a bug. Bloom is UnrealBloomPass on a composer, weaker in light theme, weaker on a phone. I cap devicePixelRatio. I drop particle count when hardwareConcurrency is low. That is the difference between a demo that survives a recruiter’s laptop and one that cooks a mid-range Android in the subway.

2. The island, not the homepage

There is no WebGL on the server. This page is a static export. The article HTML is in the first paint. The scene is a client island: IntersectionObserver with a root margin, then a dynamic import of three, then a renderer. If you never scroll here, you never download the engine. If you leave, the loop yields. On unmount I dispose geometries, materials, the composer, the PMREM, the renderer. Navigate away in this app and the GPU context does not leak into the next article.

I did not put this on the homepage. An eager 3D hero fights LCP and then steals INP. Recruiters can wait one scroll. Customers on a product URL can wait for the object they came to touch. They cannot wait for a canvas that blocked the heading. Reduced motion stops the auto-rotate and the particle drift; drag still works, because that is a choice, not an animation.

  • Copy and heading in server HTML. Canvas is not a crawler surface.
  • Boot on intersection, not on route load.
  • Dispose on unmount. Pause off-screen. Honour prefers-reduced-motion.

3. Raw Three.js here. React Three Fiber in a product app

I wired the engine myself on this page so the island stays one chunk and the loop is obvious: create, tick, dispose. In a Next.js app where the scene must talk to cart state, a colour picker, and a stock flag, I would use React Three Fiber. Same GPU, a scene graph that lives in the React tree, fewer footguns around unmount. The mistake is adopting R3F to spin a cube, or avoiding it when ten meshes must stay in sync with Redux. Pick the wrapper when the product already thinks in components.

4. When I would ship this for a client

A jewellery SKU. A bottle. A device whose colourways are the sale. Architecture that must be walked, not photographed from four JPEGs. Not a marketing homepage that needed “to feel premium” — that brief is still CSS and GSAP. Not a slot reel: that is Pixi. If the object is a GLTF from the factory, I keep it lean, add LOD, and put a poster up while it boots. If WebGL fails to init, the page still has photos and a price. The canvas is the best path to the SKU, never the only one.

Conclusion: show the object, keep the document

Teams hire Three.js when a customer converts by orbiting, not by reading. They should still hire a document: title, price, legal, a fallback image. I ship that split as a senior web engineer — Next.js islands, a capped GPU budget, GSAP where the page is still a page. If your brief is a SKU that must be held in the tab, write via the form with the object, the device mix, and whether the same URL must rank. We will not start by dropping a canvas on the homepage “so the portfolio pops.”

Need this built, not just explained?

Web app development: Next.js, React, PostgreSQL. Direct contractor.

Web app development

Ready to discuss your project?

I'm a senior web engineer specializing in React and Next.js - available for freelance projects worldwide.

Location

Kyiv, Ukraine

Telegram

Contact me

WhatsApp

Contact me