~/case/ring-builder← /work
$cat README.md
/01

Ring Builder

A real-time 3D diamond-ring configurator in the browser — customise metal, diamonds, and lighting against a photoreal preview, then export marketing stills and 360° MP4s with no render server.

year
2025
role
Frontend Developer
duration
4 months
live
> stack
  next.js · three.js · react three fiber · typescript · glsl
$cat summary.md

A browser-based configurator for fine jewellery. Load a GLB ring model and customise it live — metal shade, diamond colour and refraction, HDR lighting, camera angle — against a photoreal preview, then export marketing assets: high-resolution stills and 360° rotation videos encoded to MP4 entirely client-side. The hard part isn't the panel of controls; it's making a diamond actually read as a diamond at interactive frame rates, and getting video out of WebGL with no render backend.

$ls features/
  • 01GLB model import with automatic material detection (metal, diamond, engraving)
  • 02Live material editing — metal shades, diamond tints, and index of refraction
  • 03Photoreal viewport with a custom ray-traced diamond shader and swappable HDR environments
  • 04High-resolution still export up to 1920² with ACES tone mapping and bloom
  • 05360° product video exported to MP4 in-browser via FFmpeg.wasm
  • 06Save and load configurations, plus batch-render multiple presets in one pass
$cat challenges.md
#01Making a diamond look like a diamond

Three.js's physical material can't fake gemstone optics — no internal bounces, total internal reflection, or dispersion. A standard PBR diamond just looks like grey glass, which is unsellable for jewellery.

#02Instant edits across a 40-property scene

Metal shade, diamond colour, IOR, HDR map, light angles, camera — every control had to update the GPU immediately, without re-walking and rebuilding the whole model hierarchy on each change.

#03Exporting video from WebGL, in the browser

A six-second 360° clip is ~180 frames; holding them all at export resolution runs to hundreds of megabytes, and there was no server to do the encoding.

$cat approach.md
01Custom GLSL diamond shader with BVH ray-tracing

A fragment shader traces rays through the diamond geometry — up to eight internal bounces with Fresnel reflect/refract, IOR-based colour shift, and chromatic aberration. A three-mesh-bvh acceleration structure culls non-intersecting triangles so it stays real-time instead of testing every face per ray.

02Framework-free state with an observer pattern

Scene state lives in a plain TypeScript configurator class that notifies subscribers on change; a thin React hook binds it to the UI. Setters batch and push only the changed material via typed-array writes with colour caching — no Redux, no full re-render.

03Streaming frames straight into FFmpeg.wasm

Frames render in batches of thirty, write directly into FFmpeg's virtual filesystem, then clear — never accumulating in JS. Peak memory fell roughly 76%, with parallelised temp-file cleanup trimming encode time.

$git log --oneline
  • a1f0c93chore: Next.js + React Three Fiber scaffold
  • 5d8b2e4feat: 3D scene, HDR lighting, orbit controls
  • c3e7a19feat: custom diamond shader + BVH ray-tracing
  • 7f2d6b0feat: configurator state + live material edits
  • b9c4e85feat: GLB import + material auto-detect
  • 2e6a1f7feat: image + 360° MP4 export via FFmpeg.wasm
  • perfperf: stream frames, cache colours, cut memory 76%
$cat outcomes.md
  • Real-time, photoreal diamond rendering at interactive frame rates
  • Stills and 360° MP4 export running entirely client-side — no render backend
  • ≈76% lower peak export memory after the streaming-and-caching optimisation pass
$ls ../
pritesh@portfolio: ~/case/ring-builder$
© 2026 Pritesh Mendapara · Frontend Developer · built in surat