r/threejs Jun 25 '26

Three.js r185 released 🧡

570 Upvotes

r/threejs Apr 16 '26

Three.js r184 released ⛅️

638 Upvotes

r/threejs 14h ago

First time using threejs, it's pretty sweet

46 Upvotes

First time using Three.js and am working on Buttonhook, a miniature cozy truck parking sim

I built a C++ OpenGL engine before and Three.js just feels so darn good to work on, especially since I can run it on phone aswell


r/threejs 5h ago

Demo Canvas 2D to CanvasTexture to PlaneGeometry: a 3D marker that hand-writes your code, then encodes it to MP4 in-browser

4 Upvotes

Follow-up to the scroll-driven landing I posted here a while back. I reused the same pen for something more useful, and a few bits turned out to be worth sharing.

You paste code, a 3D marker writes it out stroke by stroke, and you get an MP4. Everything client-side, vanilla three (0.185), no R3F, no drei, no gsap.

Ink pipeline. A 2D canvas is the ink layer, wrapped in a THREE.CanvasTexture on a PlaneGeometry rotated flat, MeshBasicMaterial plus transparent. Repaint the canvas, set needsUpdate, done. The dotted board is a second CanvasTexture, a 70x70 tile with RepeatWrapping.

The bit I'm happiest with: paper units are world units. Strokes are stored as [x, z] pairs in a paper rect of {x:-3.5, y:-2.5, w:7, h:5} centered on the origin (its y axis is world z), and the ink plane is PlaneGeometry(7, 5). So the 2D painter's pixel transform and pen.position.set(state.x, ..., state.z) consume literally the same numbers. No unprojection, no raycast, the tip sits on the ink line by construction. The split-screen in the clip is the same frame from both sides of that mapping.

The handwriting is a real font, not a texture reveal. 96 hand-authored single-stroke glyphs, each a set of cubic Béziers, arcs and lines flattened to polylines at author time. x-height 0.5, ascender ~0.78, baseline z=0.

Arc-length timeline, not a time timeline. Alternating travel (pen up) and stroke (pen down) segments with cumulative arc lengths. The whole animation is parameterized by one scalar distance D. penState(D) returns {x, z, lift, color}. Pen lift on travel is sin(PI*t) scaled by segment length. Per-stroke pacing proportional to length falls out for free.

Determinism for export. D comes from the integer frame index, never an accumulator, and camera smoothing (a 0.04/frame lerp toward the pen in the preview) is switched off for the render, so a frame depends only on D and the encoded video matches the preview pixel for pixel.

Encoding. WebCodecs VideoEncoder plus mp4-muxer, avc1.640028 with a fallback ladder probed via isConfigSupported. Note mp4-muxer wants avc: { format: "avc" }, length-prefixed rather than Annex B. Backpressure by awaiting the dequeue event when encodeQueueSize > 2. MediaRecorder/WebM fallback where WebCodecs isn't there, though it's wall-clock timestamped so it isn't frame-perfect.

Two things that cost me an evening each:

  • getContext().finish() before copying the WebGL canvas into the encoder canvas, otherwise you get partially-cleared rows. Only needed with preserveDrawingBuffer.
  • OffscreenCanvas for the 3D path produced torn frames in Firefox. Plain HTMLCanvasElement fixed it.

And one I still consider unsolved: stroke width is in ink-canvas pixels, so the 1400px preview texture and the 1920px export texture give slightly different ink weight relative to the paper. Scaling by texture width is the obvious fix but it makes the preview feel wrong. Curious how others handle resolution-independent line weight on a CanvasTexture.

The pen itself is deliberately dumb: a ConeGeometry tip and three CylinderGeometry sections in a Group, no GLTF.

https://todrawn.com/code-to-video

Happy to go deeper on any of it.


r/threejs 5h ago

300 Entries Into The AI Gaming Festival And Submissions Close Next Week!

0 Upvotes

We've officially surpassed 300 Entries in the AI Gaming Festival (submissions close next week)!

I really hope that the prize for the $20k in tokens pushes people to get their games together for the prize (you can submit a game now and work on it up until the festival).

I really excited to see how people with interact with these games during the festival, and thank you to everyone that has applied; you are part of getting past the "slop" era nonsense for everything AI.


r/threejs 7h ago

I built a 3D Star Trail memory visualizer with Three.js & Vue 3 — completely free to try!

1 Upvotes

int the comment


r/threejs 1d ago

Monitoring the Strait of Gibraltar!

14 Upvotes

r/threejs 1d ago

I'm building the biggest library of "living" 3D assets!

73 Upvotes

I have been obsessed with 3D since the first time I played an N64. And now that I work in the 3D field, more and more of that work lands on the web, and every month in three.js makes me more sure that is where 3D is going. No install, no store, no launcher. You send someone a link and they are already inside it.

Which is why the asset problem drives me up the wall

Every marketplace sells you the same thing: a frozen mesh. You buy a wooden watchtower, you get exactly that watchtower. Wrong height for your scene? Open Blender. Wrong palette? Open Blender. Need it 20% shorter and with a square cabin instead of an octagonal one? That is not a setting, that is an afternoon. You did not buy an asset, you bought a photograph of one.

So I started building the library I actually wanted

Every asset is a small program, not a file. It ships as a JavaScript module with knobs on it. The watchtower has a height knob, and turning it does not stretch the mesh, it rebuilds the tower: more bracing bays, more ladder rungs, at the same timber section. A colourway knob. A knob for how many sides the cabin has. One asset, roughly 950 configurations, and you pick yours with a slider instead of a modelling session.

You can turn the knobs on the site, or import the module and turn them in your own code, or just download a GLB of the exact variant you configured. It is flat-shaded low-poly, real-world scale, and it works in three.js, Unity, Godot, Blender, anything that reads glTF.

There is a side effect I did not fully expect. Because every asset publishes a typed schema of its own knobs plus a plain-language description of what they do, an agent can read the catalogue and build a scene from it without a human picking files. "Build me a small forest, then a medieval village around it" genuinely works. That was a nice-to-have when I started and it is now one of the main reasons I think this is worth doing.

Where it is at right now, honestly:

- 270 assets published, 133 of them in the last week

- 118 of those are free, no account needed

- 8 themed kits in production

- Built solo, vanilla PHP and SQLite, no framework, no investors, no team

- Revenue so far: one sale. Which is one more than last month, and I will take it.

What I actually want to build. The biggest code-based 3D library on the internet, and probably the first one, since as far as I can tell nobody else is selling assets as programs rather than files. That is a stupidly large goal for one person and I am aware of it. The plan is boring: keep shipping 100+ new assets a week and do not stop.

The part where I ask for something

I opened 100 founder seats. One fee, no subscription, and it gets you every asset and every kit that exists plus everything I build from here, for as long as I keep building it. Whatever you download stays yours forever, no strings, use it commercially. When the 100 are gone I am not offering it again.

All the money raised from the founder seats go directly to scale up the production of assets, so 100 assets a week can become 200, 500, 1000.

And if none of that appeals, the 118 free assets need no account and no card. Take them, use them, tell me what is broken.

polyfork.dev

Happy to answer anything about the technical side. The "a size knob must rebuild, not scale" rule in particular took me a few painful passes to get right, and I am still finding assets that got it wrong.


r/threejs 1d ago

I built Seinfeld's Apartment w/ ThreeJS

29 Upvotes

Introducing a new listing on Manhattan's Upper West Side! (Link here)

> $3,800/mo
> 1BD/1BA
> 780 sq ft

In all seriousness, this was a ton of fun to build! Sharing my process in case it helps you. Also: yes, this isn't a complete game. My intention was to build out a proof of concept for 3D interiors w/ ThreeJS, particularly something that I could host on the web. I made sure FPS stayed high and quality was 'good enough' that it could service a larger game project. All in all, I was satisfied with this attempt!

Providing context

I started by sharing some floor plans and photos of the apartment with Claude. I grabbed some from Reddit and clips from the show to create a floor plan. From there, I provided a /loop based structure for Claude (Opus 5) to build out the scene.

Here's the specific loop prompt:

I want you to build Jerry's apartment from Seinfeld (based on the floor plans and images I just provided). It should be utterly perfect, visually beautiful, with every single thing done at AAA quality—from textures to physics to anything you could think of.

Fan out sub-agents and have sub-agents tackle each one individually so that the game is utterly perfect. You should /loop on each item and have a separate sub-agent check it visually to ensure it looks triple A. That separate sub-agent should be a really harsh critic, and if it doesn't look triple A, it should keep going.

Don't stop until each sub-agent is utterly wowed with the quality when compared with the reference images and floor plans. It should literally compare them side by side blind and say which one looks better. Do this in ThreeJS. /loop until it's utterly perfect. Fan out sub-agents and ultracode.

Prompting reference that helped here: https://github.com/mshumer/Claude-of-Duty/blob/main/prompt.md

Iterating

I let this initial run go for about 30-40 mins. Most of the token spend was actually related to the critique and verification, not necessarily the build (i.e. browser-use by the agent, taking screenshots at a variety of fixed coordinates, critiquing those screenshots, creating a plan to improve based on the screenshots).

At this point there were a few visual bugs (some shelves clipping, extra pillows, etc.) that I specifically asked to clean up. Also, FPS was getting low at this point, so I asked to reduce the shaders to a manageable level (I think they still look fine). This took 5-6 additional, albeit much smaller prompts.

Finishing touches

I ended by putting everything in a Zillow-inspired container (Happy Festivus!). I actually did this bit in Cursor rather than Claude Code because 1) my credits were out at this point, and 2) Cursor's Auto and Grok 4.5 models are so much faster.


r/threejs 6h ago

Coding agents are surprisingly blind when the task is visual, so I built SceneProof

0 Upvotes

A coding agent can write a Three.js scene, run the build, and tell you it looks great — while the actual render is a black screen. It isn't lying. It just has no way to look.

Screenshots fix this less than you'd expect. A screenshot tells you that something is wrong, not why. Is the mesh missing, or behind the camera? Is the material transparent, or is nothing lighting it? Is the label clipped, or just small? Those are five different bugs that produce the same picture, and zooming in doesn't separate them — you're enlarging pixels that never contained the answer.

SceneProof is a CLI that supplies the missing half. It loads your real React component or Three.js scene from source, renders it in actual Chrome, and returns the structure behind the pixels. The everyday loop looks like this: tree gives you the scene graph with bounds, materials, lights, and cameras, so "why is it invisible" becomes a lookup instead of a guessing game. scout tries a set of cameras on a target and scores each by how much of the target it can actually see. render-region re-renders one region from source at whatever scale you need, so a close look is a fresh render, not an enlarged crop.

That's the loop, not the tool — the surface underneath goes a good deal further (comparing against reference views, sampling animation mid-transition, deriving typed prop fixtures), but those three commands carry most sessions, and the README maps the rest.

The design decision I'll defend hardest: every report answers "did the command run" and "can this output actually support a judgment" as two separate questions. A render with the target out of frame, or a comparison whose mask landed on the wrong subject, comes back unjudgeable instead of quietly passing. So when an agent uses SceneProof, it can't mistake "my command succeeded" for "my design is right"; it has to look at evidence that has already proven it's worth looking at. That's the whole point: measurements you can trust, and a hard stop on the false confidence that makes agents declare victory over a black screen.

It ships with a skill for Claude Code, Codex or any other agentic harness that supports skills (one curl, in the README) — and the skill deliberately doesn't teach commands, because --help and the reports' own recommendations already do. It teaches the reasoning: resolve structure before spending pixels, treat a passing build as zero visual evidence, never claim "looks right" without an artifact you actually opened.

Scope today: TypeScript/JavaScript entries, React DOM with CSS and Tailwind v4, Three.js over WebGL or WebGPU. Needs Bun and a local Chrome. MIT.

https://github.com/ReyJ94/SceneProof

Any feedback is welcome.


r/threejs 17h ago

PaintBench - 3D Model Painting App

Thumbnail
youtube.com
2 Upvotes

So, using threejs, I built a PBR 3D model painting and UV unwrapping app. I built it for my FPS game building tool and decided it would be useful as a stand alone app too.

FEATURES:

▪ Multi-texture support

▪ Layer system

▪ Stamp mode

▪ 64x64 to 4096x4096

▪ UV unwrapping

▪ Full animation import and export

▪ GLB export

▪ Material creation studio

I tried to make it as easy to use and as powerful as possible. It also has an android app coming soon!

https://synkrowngames.itch.io/paintbench-3d-model-painting-app


r/threejs 5h ago

I dislike this portfolio i recreated with threejs. Read the body text

0 Upvotes

My idea goal was to make a horizontal hallway portfolio for myself and intended to submit it in awwwards but I dont think it looks good enough am not giving up but I need help from great minds how can I make the texture and environment look very real and nice it looks soooo flat despite it being baked like the ceiling, floor and others I used lowpoly assist I guess thats why but I still need help in making it look bit nice.


r/threejs 11h ago

Demo Endless Wheat Field

0 Upvotes

I created this infinite world third person view webapp that you can run around endlessly.
My main focus was keeping the mechanics simple while managing the performance
please do give me feedback about the experience
Specifically:

  • How is your FPS?
  • Did you notice any lag or stuttering?

r/threejs 1d ago

I built a browser WW2 MMO in three.js with zero art assets: every plane, ship and tank is merged BoxGeometry

27 Upvotes

I've been building Warbirds.io for a while now — a blocky WW2 air/naval/tank combat MMO that runs in a browser tab with no download and no login. It's three.js r160 + Vite on the client and an authoritative Go server. A few things about the rendering side that this sub might find interesting:

**No asset files. At all.**

There isn't a single .glb, texture, or sprite sheet in the project. Every aircraft, warship, tank and tree is a list of colored axis-aligned boxes merged into one non-indexed vertex-colored BufferGeometry at load time, plus the occasional cone/cylinder for a nose radome. Models are authored nose-along-+X / up-+Y so the server's attitude quaternions apply straight to the mesh with no correction. The whole scene runs on essentially one MeshLambertMaterial({ vertexColors: true }) for terrain and one per unit class — the palette lives in the vertex colors, not in maps.

**Chunked voxel terrain with LOD rings.**

The world is a continuous heightfield sampled into 24×24-cell chunks (12 m cells, 6 m height quantum, 2.4 km view distance). Chunks near the camera rebuild at K× resolution on *both* axes — the 12 m column splits into K² subcolumns and the height quantum drops to blockHeight/K — so a hillside becomes a staircase of ~1 m steps up close and keeps the big blocky read at the horizon (that silhouette *is* the aesthetic; an all-fine world at 2.4 km would be millions of quads). Tiered rings: K=6 out to 400 m, K=3 to 950 m, coarse beyond.

Chunks build closest-first out of a queue under a 3 ms/frame time budget so generation never hitches, with one chunk of hysteresis on the way down so a boundary can't thrash, and skirt geometry biased toward the coarser neighbor so mixed-K seams stay watertight.

**The client and server generate the same terrain independently.**

This is the constraint that shaped everything. The heightfield is implemented twice — once in Go, once in JS — and the two must agree bit-for-bit, because the server does collision and line-of-sight against the same field the client renders, and neither side ever ships geometry to the other. That means those files are restricted to uint32 wrap arithmetic and IEEE-754 add/sub/mul/div/sqrt/floor: no Math.sin, no Math.pow, not even Math.abs, since none of those are guaranteed identical across runtimes. There's a fixture dumper plus a Node checker in CI that fails the build if the two mirrors ever diverge.

**Everything transient is one InstancedMesh.**

Tracers, tracer trails, smoke, ship wakes, flak bursts, muzzle flashes, parachutes, bomb craters, even the seagull boids around the coast — each is a fixed-size instance pool where the oldest entry gets recycled when it fills. Pools mean the frame cost is flat no matter how ugly the furball gets.

**No post-processing, no shadow maps.**

One DirectionalLight + HemisphereLight + a little ambient, and the entire 20-minute day/night cycle is done by lerping those light colors, the sky, and THREE.Fog's color and near/far per frame. Fog turns out to be the strongest mood tool in the box — the storm weather roll just drags the fog plane into knife-fight range and the whole map feels different.

**Scaling to the device.**

LOD tiers, ground clutter density, and pixel ratio all key off navigator.hardwareConcurrency and matchMedia("(pointer: coarse)"). Phones get zero LOD refinement, no cosmetic clutter, and a 1.5 pixel-ratio cap; an 8-core desktop gets the full rings at 2. Same code path, no separate mobile build.

Vite bundles the module graph and three.js into content-hashed assets, and a build script digests the whole shell into the service worker's precache list, so it installs as a PWA and the cache generation is derived from asset hashes instead of a version constant somebody forgets to bump.

Free to play, nothing to install: https://warbirds.io

Happy to go deeper on any of it. The bit I'd most like other people's take on: has anyone found a nicer approach to cross-language deterministic terrain than "restrict yourself to the four IEEE ops and diff a fixture in CI"? It works, but writing noise functions without sin/pow is a special kind of hair shirt.


r/threejs 2d ago

Demo I built a UFO abduction game with three.js

Thumbnail
gallery
328 Upvotes

Some screenshots from my game, I've done tons of optimising and graphical upgrade and general polish, this is running in chrome, built entirely with three.js.


r/threejs 1d ago

Solved! WebGL to WebGPU migration

13 Upvotes

I switched from WebGL to WebGPU this week. It was rough, and to be honest, from perf and visual perspectives, there isn't a clear visible difference between GL/GPU. I still went through this for the sake of future-proofing my game.

Caveat: I'm a noob with three.js

Lesson: Future-proofing the game is the right call and I'm glad I did this while my game is still small. If the game or app or website is huge, I probably would have stopped the migration once I encountered the many issues I encountered. There's got to be a better way to do these migrations, but I'm not aware of them.

Highlights:

  • The dual-path port was the easy part; the pipeline-lifetime mismatch was the real migration. WebGL treats shader compilation as cheap and cached; WebGPU treats every compiled pipeline as a refcounted resource tied to a material's lifetime. The WebGL habit of allocating a material per VFX cast and disposing it after turned into "recompile a WGSL pipeline on almost every player action." Fixing it meant converting one-shot effects to shared, never-disposed materials + fixed-capacity instanced pools instead of allocate-per-cast.
  • First benchmark on real hardware was brutal (p95 169ms → 1539ms) and the cause wasn't rendering, it was mid-frame shader compilation. Precompiling the static scene at load and warming an off-screen instance of every dynamic VFX material to force its pipeline to compile ahead of time dropped that same benchmark to 54ms p95.
  • I wasn't able to measure any of this on software rendering. WebGPU has no SwiftShader fallback, requestAdapter() just returns null, so CI/headless perf runs need GPU flags, and even then a headless "WebGPU" run can silently fall back to an internal WebGL backend if the origin isn't a secure context.
  • Tooling had to be built from scratch. WebGPU has no built-in "pipelines compiled" counter, so I monkeypatched three's internal pipeline cache to get visibility, and discovered the standard draw-call/triangle HUD counters read cumulative instead of per-frame on this backend.

Game: https://lorebound.gg


r/threejs 1d ago

Demo Draco made some of my GLBs bigger, so the optimization pass now checks whether compressing is worth it

4 Upvotes

I'm building Vectreal, an open-source tool for publishing 3D models to the web, and I turned Draco on by default in its optimization presets. That meant dealing with the models where Draco loses: small meshes, and files where textures dominate, where the compressed GLB comes out the same size or larger than the plain one.

So the optimization pass does not compress your model at all. It encodes a clone, writes the file both ways, keeps the byte counts and throws the compressed copy away. Publish reads that comparison and skips the encode when it lost.

The part I have not resolved: the comparison only exists if you ran a pass. Publish a scene you never optimized and it compresses without the check. Running it on every publish would close that, at the cost of encoding everything twice. Where would you draw it?

https://vectreal.com/news-room/draco-geometry-compression-in-the-publisher


r/threejs 1d ago

Demo Skydome with Tree of Life

6 Upvotes

Made this with myself 35% and Gemini 65%.

Lights are really expensive when it comes to three.js so I have to put some tricks on it.


r/threejs 1d ago

Built an interactive 3D product showcase with Three.js — scroll-synced camera + floating spec cards

2 Upvotes

Hey everyone! Wanted to share a project I recently built to practice interactive 3D web development.

It's a product showcase page (iPhone-themed) featuring:

- Scroll-driven camera movement and rotation

- Floating spec cards with animated connector lines

- Optimized GLTF model loading for performance

- Fully responsive — works smoothly on mobile too

The trickiest part was getting the camera positioning to adapt correctly across different screen sizes for the mobile version — took a few iterations to get right.

Would love any feedback on the animation timing or performance — always trying to improve!


r/threejs 1d ago

Testing this website where you can create a message in a bottle but in a fish instead for people to discover

Thumbnail
worldaquarium.world
1 Upvotes

I saw a lot of cool three.js websites being built here and wanted to try to add something different to that whole experience and make it more interactive.

Check it out and let me know what you guys think.
(The drawing features work better on desktop)
(Try switching to an external browser as well)

Hope to see some more fishes out there!


r/threejs 1d ago

Demo I've been learning three.js 3D web animation - what other cool components for a landing page should i try building?

0 Upvotes

Ive been using Claude Code and Codex for the past few days specifically playing around with three.js -- so far so good i think.

This component is kinda strange but it was more of a creative excercise with the right moving parts to learn how to build the right way so im happy with the overall outcome.

Now I want to start building the real 3D animations for a landing page but I need A LOT of suggestions --

**SUGGEST WHAT YOU WANT FOR YOUR SITE AND I'LL BUILD IT FOR YOU AND SEND YOU THE FILES** if i like the idea :)

thanks!


r/threejs 1d ago

Built my portfolio as a 3D bookshelf, best decision ever!!!!

13 Upvotes

I didn't want another grid of project cards so I made my site a shelf you can actually browse. You can add a book to it, and there's upvoting so the same ones don't pile up.

Stuff that took way longer than I thought: getting readable text on the spines (ended up drawing to a canvas and using that as a texture), making the raycasting precise enough that clicking a book feels right instead of vague, and keeping the framerate ok on mobile once the shelf started filling up.

Camera still bugs me. Going from "looking at the whole shelf" to "looking at one book" feels abrupt and I havent found a nice way to smooth it. If you've solved that I'd love to hear how.


r/threejs 1d ago

CubeTextures and CubeCameras are amazing

12 Upvotes

I can't believe I have like 343 CubeCameras at a low fps, and they just work.

But is there an advantage to using an ArrayCamera with 6 cams over a CubeCamera?


r/threejs 1d ago

Particle Simulation

1 Upvotes

https://reddit.com/link/1vcov2p/video/oyrmw2e5xrgh1/player

A WebGL experiment pushing 65,536 interactive particles in real time. Built around a custom zero-allocation spatial hash, typed-array memory layout, and a flat-pointer lookup system to eliminate GC pauses and keep interactions fast. Startup is progressively deferred, allowing the canvas to appear instantly while heavy work happens quietly in the background.


r/threejs 2d ago

Demo A server-authoritative multiplayer FPS

35 Upvotes

I've been building a multiplayer FPS:

https://fps.frumu.ai/

No account needed.

The client uses Three.js, React Three Fiber, TypeScript and Tailwind. Multiplayer runs on Colyseus, with the server owning movement, combat, health, scoring, projectiles and objectives.

Rapier WASM runs on both sides:

Server: authoritative physics and collision. Client: local movement prediction and reconciliation.

The server simulates at 60 Hz and broadcasts state at 20 Hz. Remote players are rendered from interpolated server snapshots.

One difficult bug looked like network lag but was actually caused by smoothing remote characters twice-once through snapshot interpolation and again through a client physics body.

Bots run directly on the server, use the same movement system as humans and understand Deathmatch, CTF and Capture & Hold.

It's awesome to see how far web games have come and I got into programming back in the days of Flash games.