selected work

Çağkar Galeri

3D car showroom in the browser with adaptive, device-aware asset loading

class
3D showroom
state
live
access
cagkargaleri.emircancaglar.com
built with
JavaScript · three.js · glTF · KTX2

A walkable, lit 3D garage showing a small set of vehicle models as glTF, viewable entirely in the browser with no app to install. Loading and render quality both adapt to the device: what loads first, how many models load in parallel, and how often the scene re-renders when idle all change based on whether the device looks weak, mobile, or on a metered connection.

the problem

Car models are large — tens of megabytes of geometry and textures apiece — and a showroom needs several in one scene. Loading all of them naively means either a multi-minute wait or a crash on a phone; loading them one at a time in a fixed order leaves the garage looking empty for too long. Loading and rendering both needed their own explicit policy instead of "load everything, render every frame."

how it is built

  • Vehicle models loaded as glTF into a lit garage scene, in plain JavaScript and three.js, no framework.
  • KTX2 texture compression plus a separate mesh-optimization pass bring individual model sizes down substantially — the largest model in the set drops from roughly 43MB to about 16MB.
  • A two-tier loading plan: a lightweight preview asset loads first for every visible car, full high-quality models load in behind it, with the hero car prioritized first and the rest ordered to match the tour sequence.
  • Load concurrency adapts to the device: 2 concurrent preview loads and 1 high-quality load at a time on weak, mobile or save-data connections, versus 4 and 2 on a capable connection.
  • A bounded download queue supports promoting an item to the front, so selecting a car mid-load jumps its model ahead of ones already queued.
  • A runtime render policy throttles the render loop itself: full frame rate only while actively scrolling, interacting or moving the camera; a capped roughly-30fps ambient rate when idle but visible; fully paused when the tab is hidden. A separate high-quality render pass only runs after 600ms of true idle time.
  • Camera framing (field of view and orbit radius) is computed per model from its measured bounding-box dimensions and the viewport aspect ratio, rather than a fixed camera position per car.
  • Off-focus models dim to a fraction of their base opacity rather than disappearing, so the rest of the garage stays visible but clearly secondary.

the hard parts

  • The loading policy and the rendering policy had to be two separate systems: getting bytes down efficiently (tiered preview/hq loading, adaptive concurrency, a promotable queue) doesn't help if the renderer then spends every idle frame redrawing a static scene at full cost anyway. A second, independent policy decides when the renderer is even allowed to draw a frame, separate from what has already been downloaded.
  • Compressing textures without visibly degrading a showroom car's paint and reflections meant per-model tuning rather than one global setting — the repository still carries multiple separate model directories from different compression passes (an original set and at least one KTX2-compressed set), consistent with sizes having been checked and re-run rather than a single default preset applied once.

Need something like this built?

Backend systems, payment and API integrations, AI pipelines, and the interfaces in front of them. Freelance or contract, remote.

emircan@emircancaglar.com