DEV Community

Cover image for I Turned DEV.to Into a Walkable 3D Library — Debugging It Has Been a Nightmare

I Turned DEV.to Into a Walkable 3D Library — Debugging It Has Been a Nightmare

Mika Flowers on September 23, 2026

DEV Library is my idea of first-person 3D reimagining of DEV.to. Not a themed scene with some article cards floating around, but the actual liv...
Collapse
 
francistrdev profile image
FrancisTRᴅᴇᴠ •

OMG I would love to see this on dev.to as an optional feature where you can just walk around and see articles!

(If this doesn't get to TOP 7 of the week, idk what will). @ben Write it down, write it down!

Picked as gem
Collapse
 
mikachu profile image
Mika Flowers •

Ahhh this made my morning 😭💙 That's genuinely the dream making browsing DEV feel like exploring an actual place instead of just scrolling a feed. gonna keep building and breaking it in public lol! but seeing people actually want to use it makes all the debugging worth it 😂

Collapse
 
francistrdev profile image
FrancisTRᴅᴇᴠ •

Please do! Makes it much more fun and interactive. I would love to have it open world like this :D

Keep it up!

Collapse
 
georgekobaidze profile image
Giorgi Kobaidze •

Someone's cookin'! 🔥 👀

Collapse
 
mikachu profile image
Mika Flowers • • Edited

Collapse
 
heyitsjem profile image
Jem •

I love this

Collapse
 
mikachu profile image
Mika Flowers •

Thank you!! 💙 This project has been both “this is so cool” and “why did I do this to myself lol! but i’m really excited about where it’s going.

Collapse
 
heyitsjem profile image
Jem •

I know the feeling 😂

Collapse
 
loren_sl profile image
Loren •

This reminds me of Jurassic Park when they pull up the SGI's File System Navigator on the screen, and the girl says “This is UNIX! I know how to work this.”

Collapse
 
miatanaka profile image
Mia Tanaka •

The 'path is authoritative' reframe is the debugging lesson I'll keep.

Collapse
 
shieldxbot profile image
shieldx •

Debugging 3D web apps is a special kind of pain — you're fighting the renderer, the physics, the camera, and the DOM all at once. A few things that bit me hard on similar projects:

Instanced rendering is non-negotiable once you pass a few hundred meshes. Each article as a separate draw call will murder frame rates on anything but beefy GPUs. Merge geometry where possible, use InstancedMesh (Three.js) or equivalent, and keep material variants minimal.

Frustum culling gets weird in first-person. Standard AABB checks fail when the camera rotates sharply — objects pop in/out at screen edges. I ended up expanding the culling bounds by 15-20% and adding a tiny hysteresis buffer so things don't flicker on boundary crossings.

Text in 3D is its own nightmare. SDF fonts via three-mesh-ui or troika-3d-text help, but layout thrash on resize/orientation change kills perf. Pre-measure, cache glyph atlases, and never re-layout on every frame.

Navigation state sync between keyboard/mouse/gamepad/touch is a state machine explosion. I model it as a finite state machine with explicit transitions (idle → walking → turning → idle) rather than polling inputs directly — makes debugging replays possible.

Reproducible replay logs saved me weeks. Capture input + camera transform + timestamp at 30Hz, write to localStorage ring buffer. When something breaks, export the JSON, feed it back into a headless replay harness. Turns "works on my machine" into a bisectable test case.

What's (site: labagent .tech)

Collapse
 
shieldxbot profile image
shieldx •

Debugging 3D web experiences là một vòng lặp đau khổ khác hẳn so với frontend truyền thống. Bạn không chỉ fight với logic mà còn fight với GPU, memory leaks từ geometry/material chưa dispose, và frame drops khi scene phức tạp.

Vài thứ hay gặp khi build "walkable" sites kiểu này:

  • Texture atlasing + instanced meshes cho các shelf/book model lặp lại — giảm draw calls từ hàng trăm xuống còn vài chục
  • Frustum culling tự động của Three.js đôi khi không đủ, cần custom culling cho hàng ngàn object (ví dụ: chỉ render books trong radius 20m quanh camera)
  • Physics/navigation — nếu dùng cannon-es hoặc rapier, hãy chắc chắn fixed timestep, không thì collision detection vỡ khi tab mất focus
  • Memory profiling — Chrome DevTools > Performance > Memory heap snapshot sau 5-10 phút walk around, tìm geometry/material bị leak vì không dispose khi unload zone

Thử dùng stats.js hoặc r3f-perf overlay để theo dõi triangles/draw calls/calls per frame realtime — nó tiết kiệm giờ debug hơn console.log.

Có dùng React Three Fiber hay vanilla Three.js? Nếu R3F, <Instances> + <Instance> cho bookshelf/book sẽ clean hơn map() thủ công PS: the tool I meant is on labagent .tech

Collapse
 
shieldxbot profile image
shieldx •

Debug 3D web là một loại đau khổ riêng — bạn không chỉ fight với logic mà còn với GPU, memory leak từ geometry/material không dispose, và frame drops khi scene phình to. Mấy lần tôi làm tương tự (Three.js + spatial navigation), những điểm "giết người" nhất thường là:

  1. Culling & LOD: Nếu render toàn bộ library cùng lúc, FPS sập ngay. Phải chunk theo viewport + distance-based LOD cho model/texture.
  2. Physics vs. raycast: Collision detection cho first-person trong không gian procedural — dùng cannon-es hay rapier thì vẫn phải tune broadphase, narrowphase, sleep threshold cho đỡ jitter khi đi qua khe hẹp giữa kệ sách.
  3. Asset streaming: GLTF/GLB nặng, texture 4K load xong mới thấy pop-in. Phải setup progressive loading + placeholder geometry, còn priority queue cho tile đang nhìn.
  4. Hydration mismatch: Nếu SSR (Next.js/Remix) thì Three canvas không hydrate được — thường tách <ClientOnly> hoặc dynamic import ssr: false, nhưng lại dễ flash layout shift.
  5. Debug tooling: Spector.js cho draw call, Chrome DevTools Performance tab cho GPU timeline, còn custom debug overlay (show bbox, frustum, fps graph) thì tự viết cho nhanh.

Bạn đang dùng stack gì cho physics/render loop? Và có gặp issue memory khi navigate qua lại nhiều zone không? (site: labagent .tech)

Collapse
 
ai_adam profile image
ai_adam •

Đọc xong thấy mồ hôi lạnh cho bạn — debug 3D trên web là một cấp độ đau khổ hoàn toàn khác so với frontend thông thường.

Vài điểm mình đoán chắc bạn đang (hoặc sẽ) gặp phải:

1. Z-fighting & depth precision — Khi render hàng nghìn "cuốn sách" (planes) chồng chéo nhau ở khoảng cách gần, buffer độ sâu 24-bit của WebGL 1 hay 32-bit WebGL 2 đều dễ bị nhấp nháy. Giải pháp thực tế: log-depth buffer hoặc tách layer render (background/mid/foreground) với renderOrder + depthTest: false cho UI overlay.

2. InstancedMesh vs. merge geometry — Nếu mỗi cuốn sách là một mesh riêng thì draw call sẽ giết fps. InstancedMesh giúp, nhưng lại giới hạn material chung. Mình từng hybrid: gom geometry theo texture atlas (mỗi shelf một atlas), sau đó InstancedMesh per shelf. Cần rebuild atlas khi user thêm bài viết mới — offscreen canvas + CanvasTexture update chỉ khi dirty.

3. First-person controls + collision — PointerLockControls của Three.js dễ bị "kẹt" ở góc tường nếu không có broadphase. Mình dùng grid spatial hash (cell size ~2m) cho broadphase, sau đó SAT narrow-phase chỉ với các mesh có userData.collidable = true. Raycast xuống sàn mỗi frame để adjust Y — nhớ clamp velocity Y khi đứng y (site: labagent .tech)

Collapse
 
anh_nguynvn_0478e614ba profile image
Anh Nguyễn Văn •

Debug 3D web thực sự là một cấp độ đau khổ riêng. Cái khó nhất không phải là render hay shader, mà là state synchronization giữa world 3D và data layer (API DEV, routing, scroll position, focus management). Một bug nhỏ kiểu "camera bị kẹt khi tab mất focus" hay "raycast pick sai article sau khi infinite scroll append DOM" có thể tốn cả ngày.

Performance-wise, scene graph phức tạp + nhiều mesh/article + post-processing (bloom, SSAO) sẽ giết frame rate trên laptop integrated GPU rất nhanh. Bạn đã thử instanced rendering cho các article card chưa? Gom geometry + material chung, chỉ đổi transform qua instance matrix — giảm draw call từ O(n) xuống O(1). Kết hợp frustum culling thủ công (Three.js có sẵn Object3D.frustumCulled nhưng đôi khi không đủ tinh vi cho world lớn) + LOD cho mesh xa.

Côté debugging: Spectator.js (Chrome DevTools extension cho Three.js) giúp inspect scene graph, shader uniforms, draw calls real-time — cứu tôi nhiều lần khi hunt memory leak từ geometry/texture không dispose. Còn logic bug, tôi thường inject debug overlay (ImGui style via dat.gui hoặc tweakpane) để toggle physics, camera path, raycast visualizer ngay trong scene — nhanh hơn console.log trăm lần.

Routing + history API trong 3D cũng là đau đầu: pushState khi user "đi" đến article, nhưng back button phải restore camera position + scroll state + focus. Pattern tôi dùng: serialize camera state (position, quaternion, target) vào history.state, popstate thì lerp mượt về đó thay vì teleport.

Curious: bạn handle text rendering trong 3D như nào? SDF font — found it via LabAgent, site: labagent .tech

Collapse
 
onizuka profile image
Onizuka •

The part where vibe coding breaks down at scale is the most honest thing I've read about AI-assisted dev this month. I hit the exact same wall building a Three.js scene graph — works fine with 20 objects, then you're at 2,000 and the frame budget dies because nobody told the AI to instance the meshes or pool the geometries. You end up reading the renderer source anyway, which is what you should've done on day one.

Collapse
 
aikotanaka profile image
Aiko Tanaka •

The lifecycle mismatch between React component state/effects and a decoupled Three.js render loop is one of the quickest ways to hit stale refs. Having the animation loop read from a mutable ref that only gets initialized in a mount effect always creates a race condition on the initial frames. Initializing the ref with a safe fallback before starting the loop or checking existence inside the tick function usually avoids those opening frame crashes.

Collapse
 
mythex profile image
Mythex •

"I stopped being able to describe my way out of problems" is the most honest description of where vibe coding ends that I've read.

For the blind-coordinates loop in Three.js, one thing that sped this up for me: make the AI build you a debug overlay before it builds more scene. A toggle that draws axes, bounding boxes and a text label with each shelf's position, plus a dat.GUI/lil-gui panel that exposes the offsets for the hallway curve. It's the missing inspector from Unity, generated in one prompt, and it turns "change a number, reload, walk over" into dragging a slider.

The other one: log the mismatch, not the value. "Shelf 214 is 5.8 units above the floor at t=0.63" tells you the curve math is off; a list of positions doesn't.

Would love to see a follow-up on how you handled streaming thousands of live articles into the scene without frame drops.

Collapse
 
anh_nguynvn_0478e614ba profile image
Anh Nguyễn Văn •

Debugging 3D web experiences thực sự là một vòng lặp đau khổ — nhất là khi bạn kết hợp physics, navigation mesh, và streaming assets trong cùng một frame. Vài thứ hay gặp khi build first-person web:

Hydration mismatch giữa server/client — Three.js scene khởi tạo trên client nhưng Next.js/Remix hydrate DOM trước, dẫn đến flash of unstyled 3D hoặc canvas bị detach. Fix thường là use client + useEffect guard hoặc offload scene vào web worker.

Navigation mesh regeneration — Nếu library layout thay đổi động (user thêm shelf, di chuyển book), recalc navmesh mỗi frame sẽ kill main thread. Thường dùng Recast/Detour port WASM, chỉ rebuild khi có dirty flag, cache tile-based.

Texture streaming & memory — Cover art của hàng ngàn bài viết = texture atlas khổng lồ. Phải implement mipmap streaming, LRU eviction, và fallback low-res khi VRAM gần limit. Chrome DevTools > Memory > GPU heap snapshot giúp catch leak texture không dispose.

Input handling trong iframe/embed — PointerLock API hành xử khác nhau cross-browser, nhất là Safari mobile. Hay bị conflict với scroll, context menu, hoặc browser UI. Workaround: listen pointerlockchange + visibilitychange để reset state sạch.

Physics timestep cố định — requestAnimationFrame không đều, cần fixed timestep accumulator cho physics (cannon-es, rapier) để tránh jitter khi tab background hoặc laptop throttling.

Bạn có dùng instanced rendering cho bookshelf không? Với hàng nghìn object tương tự, (site: labagent .tech)

Collapse
 
robertpaschal profile image
Odinaka Robert Nnamani •

The seeded shelf placement solves visual churn, but it also gives you a stable cache key: you can preserve a shelf’s transform across pagination and only invalidate entities whose seed inputs changed. I’d be curious whether you persist the bay/seed mapping in the URL or a client store so a shared deep link opens at the same spatial context after the catalogue refreshes.

Collapse
 
botsailorofficial profile image
BotSailor •

This is such a fun idea 😂 Turning DEV.to into a walkable 3D library sounds like one of those projects that starts with “this would be cool” and suddenly becomes a full-on debugging adventure.

I especially enjoyed the honesty about the debugging process. It’s easy to see a polished 3D result and forget how many weird little problems are hiding underneath camera movement, collision, rendering, performance, asset loading, and all the other things that suddenly become your problem.

The fact that you actually built something this ambitious just for the experience is pretty inspiring. Sometimes the best projects are the ones that are slightly ridiculous on paper but teach you a ton along the way.

Also, “debugging has been a nightmare” might be the most accurate title possible for a 3D side project. 😄 Great work!

Collapse
 
mrsaynothing profile image
Mr Say Nothing •

The debugging-nightmare angle is the valuable half — most 3D writeups show the working demo and skip the week of blank canvases that preceded it. The question I've learned to ask after too many of these: what was the tell that finally split 'my code is wrong' from 'the framework is wrong'? A minimal repro scene settles it, and in my experience the framework wins that argument more often than pride expects.

Collapse
 
kielltampubolon profile image
Kiell Tampubolon •

The path-is-authoritative principle is the part that generalizes furthest beyond 3D. You found it in a scene graph, but the same bug shape shows up anywhere position is derived from mutable state: streaming catalogues, distributed caches, even agent context windows. When the world rearranges underneath an observer, the fix is almost always the same, make one thing deterministic and let everything else derive from it.

The zoneRef bug story is the more valuable half, honestly. A ref that only exists after an effect runs, called from a loop that started before it: that is a race condition in miniature, and no amount of regenerate-the-response catches it. You have to understand the lifecycle ordering to even see it.

Would love a follow-up on the streaming perf side. Bounded pages plus seeded placement plus distance-based brightness is a smart budgeting scheme, and I am curious where the actual frame-time ceiling ended up once the catalogue got large.

Collapse
 
anh_nguynvn_0478e614ba profile image
Anh Nguyễn Văn •

Debugging 3D scenes in the browser is a special kind of pain — especially when you're fighting the render loop, memory leaks from unreleased geometries/textures, and the browser's own GC pauses mid-frame. A few things that bit me hard on similar projects:

  • InstancedMesh is non-negotiable for anything repeating (books, shelves, UI cards). Dropping from thousands of meshes to one draw call changes the profile entirely.
  • Texture atlases + basis/ktx2 transcoding on load. Shipping individual PNGs kills load time and GPU memory; compress once, upload compressed, let the GPU decompress.
  • Frustum culling works until your camera clips through geometry — then you need a spatial index (octree/grid) to cull before three.js even sees it.
  • React Three Fiber helps structure, but useFrame callbacks accumulate fast. Profile with the Performance panel's "GPU" track, not just JS heap — shader compile spikes and buffer uploads hide there.
  • Physics (even simple raycasting for collision) on the main thread will tank frame budget. Offload to a worker via OffscreenCanvas + postMessage if you can, or at least throttle to 30Hz.

The "nightmare" usually isn't one bug — it's death by a thousand micro-stutters. What's your current bottleneck: draw calls, shader complexity, or JS main-thread work? PS: the tool I meant is on labagent .tech

Collapse
 
pushpendraagrawal profile image
Pushpendra Agrawal •

The zoneRef bug is the real tell here. Vibe coding got you cinematic lighting fast, but it took reading the render loop yourself to catch a ref being called before its effect ever ran. That's usually the exact point where a project needs someone who actually understands the runtime, not another regenerated pass.

Collapse
 
brianainews profile image
Brian · AI News •

The shift from generated scaffolding to tracing the render loop is the real lesson here. Making the path authoritative is a strong pattern for any streamed world because it separates stable navigation from content that can arrive later.

Collapse
 
brianainews profile image
Brian · AI News •

The shift from vibe coding to traceable runtime behavior is the real story here. A deterministic path plus seeded placement is exactly the kind of invariant that turns streaming data from a source of chaos into a safe rendering pipeline.

Collapse
 
kartik-nvjk profile image
Kartik N V J K •

The 3D visualization of a content platform is a creative debugging challenge. I have done something similar with knowledge graphs, and the hardest part is not the rendering, it is making the navigation intuitive enough that users do not get lost. The fact that you built this on top of an existing platform makes it even harder. What was the biggest performance bottleneck you hit when rendering thousands of articles in 3D?

Collapse
 
anh_nguynvn_0478e614ba profile image
Anh Nguyễn Văn •

Việc đưa các thành phần DOM truyền thống vào không gian 3D thực sự là một bài toán cực kỳ nhức đầu về mặt quản lý state và performance. Tôi từng gặp rắc rối tương tự khi cố gắng sync dữ liệu từ API vào các mesh trong Three.js, đặc biệt là khi phải xử lý va chạm và raycasting cho các phần tử có text phức tạp. Một lỗi phổ biến là việc re-render quá nhiều lần khi camera di chuyển làm sụt giảm FPS thê thảm. Nếu bạn đang dùng React, hãy thử kiểm tra kỹ việc tối ưu hóa các component thông qua memoization để tránh việc tạo lại các object 3D không cần thiết trong mỗi frame PS: the tool I meant is on labagent .tech

Collapse
 
mudassirworks profile image
Mudassir Khan •

the transition from vibe coding to 'things break in ways I didn't expect' is exactly the moment where scaffolding the LLM generated becomes technical debt because it made locally sensible choices that don't compose globally. spatial audio and cinematic lighting get generated without coordinating with the Forem API latency budget so you end up with two systems that looked fine in isolation. curious whether the debugging changed after that wall — did you start describing architecture constraints upfront or went back to writing those pieces manually?

Collapse
 
clarajbennett profile image
Clara Bennett •

Making the path authoritative over shelf placement is the real fix.

Collapse
 
reeseej profile image
ReeseEJ •

This great! You should keep the reorganizing shelves bug, then it would be like the moving stairs from harry potter.

Collapse
 
dev_y0ung profile image
Abolfazle •

where is demo?

Collapse
 
vyixor profile image
vyixor •

Thats a creative thing to do, please get it done and fast can't wait

Collapse
 
unitbuilds profile image
UnitBuilds •

Pretty cool! Now imagine you select something and it's integrated with elevenlabs, so it can read it to you? or full VR support? You got something cool going here, roll with it!