Why I Would Use Three.js and Pixi.js
CSS and GSAP animate the page. Three.js and Pixi.js draw a scene on the GPU. When a product needs thousands of sprites, a 3D configurator, or a canvas that must hold 60 fps, the DOM is the wrong tool. How I choose between them.
A browser page is a document: headings, buttons, forms, links a crawler can read. CSS, GSAP, and Framer Motion move that document. That is the right tool for almost every marketing site I ship. Three.js and Pixi.js exist for the other job: a scene the GPU paints, not a tree of divs. Teams reach for them when the DOM would drop frames, when the object is a 3D SKU, or when two thousand coins must stay on screen at 60 fps.
I already wrote when GSAP and Framer Motion earn their keep on a Figma-to-code handoff. This is not that article. This is when I would leave the DOM, what each library is actually for, and the bill you pay in Core Web Vitals, SEO, and accessibility if you put a WebGL canvas on a business URL.
1. The DOM is a document. A canvas is a drawing surface
Each DOM node carries layout, style, hit-testing, and a place in the accessibility tree. That cost is the point of the web: text selects, forms tab, Google indexes the heading. It is also why a thousand absolutely positioned divs will hitch on a mid-range phone. A canvas is a bitmap. You tell the GPU what to draw this frame. There is no layout for a sprite. There is also no heading for a crawler and no name for a screen reader unless you build that beside the canvas.
Raw WebGL (and now WebGPU) is cameras, buffers, shaders, and draw calls. You can write it. Most product teams should not. Three.js and Pixi.js wrap that surface into a scene graph, loaders, and a hiring pool. You pay with bundle weight and a black box in the middle of the page. The question is never “is GPU rendering cool.” The question is whether the product actually needs a scene.
2. Three.js: a 3D world in the tab
Three.js is a 3D engine for the browser. You get a scene, a camera, lights, meshes, materials, and textures. The library talks to WebGL; a WebGPU renderer exists for newer GPUs. People use it because a GLTF model of a sofa, a kitchen, or a turbine is cheaper to spin in the tab than to film every angle, and because a camera you can orbit is a better sales tool than a PNG carousel.
Typical work I see: product configurators (color, fabric, add-ons), architecture walkthroughs, scientific or financial data in space, WebXR booths, hero scenes on a brand site that must feel like a film still you can touch. Babylon.js is a real alternative with a stronger editor. Three.js won the examples, the Stack Overflow answers, and React Three Fiber - which is how I would wire a scene into a Next.js app that already thinks in components.
- Use Three.js when the object has depth: orbit, explode a part, swap a material, walk a room.
- Keep the GLTF lean. A 40 MB sofa kills mobile. LOD, compressed textures, and a poster image before the scene boots.
- Do not put the price, the CTA, or the checkout inside the canvas. HTML next to it. The scene sells the object; the document closes the deal.
3. Pixi.js: 2D at 60 fps, not a game engine
Pixi.js is a 2D renderer. Sprites, a display list, filters, particle systems, spine-style skeletal animation. It batches draw calls on the GPU so a slot reel, a kids’ learning board, or a map with a few thousand pins does not melt the main thread the way a DOM list would. People use it because Canvas 2D is too slow at that count, and because they already have a web app - they do not want to adopt a full game framework just to paint fast.
Phaser is a game framework: scenes, physics, input, audio. Pixi is the layer underneath when you already own React, routing, and auth. Interactive ads, branded minigames, dashboards that plot more points than SVG should, and casino-style UIs are the usual brief. If the product is a real game with levels and a physics world, start with a game engine. If the product is a Next.js app that needs a hot 2D stage in one route, Pixi is the library I would reach for.
- Use Pixi when the problem is count and smoothness in 2D: particles, sprite sheets, filters, a stage that redraws every frame.
- Atlas the sprites. Ten thousand loose PNGs will stall the load even if the GPU is happy later.
- Pause the ticker when the tab is hidden. A Pixi stage that keeps ticking in the background is a battery complaint waiting to happen.
4. How I choose: CSS, GSAP, Pixi, Three
The expensive mistake is using a 3D engine to fade a button. I already wrote that premium scroll storytelling belongs to GSAP and ScrollTrigger, and that React UI state belongs to Framer Motion. Those libraries animate nodes that stay in the document. Three and Pixi create a world that is not the document. Mixing them is fine. Replacing the wrong layer is how a landing page ships a 800 KB WebGL hero nobody asked to orbit.
- Hover, accordion, page transition, form feedback: CSS or Framer Motion. Stay in the DOM.
- Pinned sections, scrubbed timeline, cinematic scroll: GSAP. Still the document, just choreographed.
- Thousands of 2D objects, particles, a stage that must hold 60 fps: Pixi.js.
- Depth, camera, lights, a model you orbit: Three.js. Not a 2D slot reel.
5. The bill: vitals, SEO, a11y, cheap phones
A WebGL canvas is invisible to a crawler. Whatever the user must read - product name, price, legal, FAQ - lives in HTML around the stage, not painted into a texture. I already wrote how Core Web Vitals move revenue. An eager 3D hero on the homepage is a classic LCP and INP own-goal: the GLTF fights the first paint, then the render loop steals input. Lazy-load the scene after the document is useful. Show a static poster first. Destroy the renderer on unmount or you leak the GPU across client-side navigations.
Accessibility is a parallel UI, not a canvas attribute. Keyboard orbit, a text alternative for the model, reduced-motion that stops the loop. A cheap Android will thermal-throttle a busy fragment shader. Cap pixel ratio, offer a “2D photos” fallback, and do not make the only path to the SKU a WebGL context that failed to init.
6. Next.js: client island, not a server component
There is no WebGL on the server. The scene is a client component, loaded with next/dynamic and ssr: false, behind a poster or a skeleton. React Three Fiber if the rest of the app is React. @pixi/react if the stage must talk to the same state tree. I would not SSR a canvas “for SEO”: the crawler still sees an empty bitmap. Put the copy in the server-rendered HTML. Let the island boot when the user is ready to play with the object.
Conclusion: pick the surface that matches the object
Teams use Three.js because a 3D SKU sells better when the customer can orbit it. They use Pixi.js because two thousand sprites at 60 fps will not survive as divs. Neither library is a substitute for CSS, GSAP, or a fast document. If the brief is “make it feel premium,” I start with motion in the DOM. If the brief is “spin this kitchen” or “keep the coins on screen,” I leave the DOM on purpose, isolate the canvas, and keep the copy that Google and a screen reader need in HTML. I do this as a senior web engineer: Next.js islands, lazy WebGL, GSAP where the page is still a page. Write via the form with the object count, whether it is 2D or 3D, and whether the same URL must rank. We will not start by dropping a canvas on the homepage “to look modern.”
Need this built, not just explained?
Web app development: Next.js, React, PostgreSQL. Direct contractor.
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
Upwork
View ProfileTelegram
Contact meViber
Contact me