Skip to content

Blog Details

Home/Blog Details

SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
A compact 3D city rendered on a smartphone screen
three.js

A 3D city that fits in a phone browser's frame budget

Abdulbasit AbdulalimWritten by Abdulbasit Abdulalim
| 5 min Read

Two projects, one constraint

A property gallery and a street game. The first shows a house; the second shows a city you drive a scooter through. Very different products, one shared problem: both have to run in a browser, on a phone, on a connection that is not good.

The phone constraint is not a detail. A browser 3D scene that runs on a development machine and stutters on a mid-range Android phone is a demo, not a product. And the "mid-range Android phone" is the device most of the people who would use these things are holding.

The budget, stated first

Before any modelling, the frame budget was written down: 16.7 ms per frame at 60 fps, and the renderer has to fit inside that on a device that is not a development machine. Everything after that is a negotiation with that number.

Three things eat a frame budget in a browser scene, and they need different answers:

  • Draw calls. Every mesh, every material, every texture binding costs a call into the graphics driver. A thousand small objects is a thousand calls, and the driver - not your JavaScript - is the bottleneck.
  • Triangles. Geometry that does not need to be on screen is still transformed, still clipped, still rasterised.
  • Fill rate. Every pixel covered by a transparent, blended or overlapping surface is expensive. Shadows, effects and overdraw live here.

The answers

Chunk the world. The city is not one scene; it is a grid of chunks, and only the chunks near the player exist. Chunks load ahead of the player and are released behind them. This is not an optimisation so much as a requirement: a full city has to be divided into pieces before it can be delivered, streamed and freed at all.

Use level of detail, and use it honestly. Each object has a detailed version and a simple version, and the switch is by distance. The switch has to be invisible, which is the hard part - a building that pops from a box to a detailed model right in front of the player is worse than a building that was always a box. The practical rules that came out of it: switch in the direction of travel, switch behind the player rather than in front, and never switch something the player is close enough to be studying.

Merge the static geometry. Roads, pavements, kerbs and building shells do not move and do not need individual materials. Merging them into a handful of large meshes turns thousands of draw calls into tens. The city can then afford detail where detail is visible.

Do not render what the camera cannot see. Frustum culling, distance culling, and - for the interiors - not modelling the inside of buildings nobody can enter. Some of this is trivial and some of it is genuinely free performance, because the work you never ask for is the work you never pay for.

Load the heavy parts after the first frame. The first frame is what the user is waiting for. Textures, environment maps and detail geometry can arrive after the scene is already on screen and stable, and the user sees a scene rather than a loading bar.

The property gallery, which is a different problem

A gallery does not need a city. It needs a room - and a room is much harder than it sounds, because a room is exactly where the user looks.

The approach that worked: build the room as a set of surfaces, light it with baked lighting rather than real-time shadows, and make the camera movement constrained and deliberate. A constrained camera is a design decision as much as a performance one - it means the scene only ever has to look good from a few angles, and that is a far smaller job than making every angle good.

The loading behaviour is the part that decides whether it feels expensive or cheap: the first view is available almost immediately, and detail fades in behind it.

The failure modes

The frame budget is spent before the scene is visible. A skybox at high resolution, a full-screen post-processing chain and a large environment map can each eat a millisecond or two before a single building is drawn.

Shadows are the classic mistake. A shadow map is a second render of the scene. On a phone, that doubles the cost of the thing you were already struggling to afford. Baked shadows and blob shadows under objects cost nothing and look nearly as good.

The device is not the one you tested on. The real constraint is the low end, and the low end is always worse than the device you have. The scene has to be profiled on the slowest supported device, not the fastest.

Textures are memory, and memory is failure. A phone that runs out of memory does not degrade gracefully - it kills the tab. Texture budgets and disposal are not a nicety.

What I would keep

  • Write the budget down first. "16.7 ms" turns an open-ended argument about quality into a concrete trade.
  • Reduce draw calls before triangles. The driver is usually the bottleneck, and merging geometry is cheap to do.
  • Decide what the user can see, then only build that. Most scenes contain geometry that exists because it was easy to model.
  • Test on the slowest supported device, not the fastest one you own.

The city in Streetverse and the gallery in Atrium are different products with the same discipline underneath: the phone is the target, the budget is written down, and everything that is not worth its milliseconds is not in the scene.

Contact Me

Let's Talk for Your
Next Projects

0 / 4000

Or email olaleke2004@gmail.com

Where

Based in Lagos, Nigeria
Working with clients worldwide

Contact

Email : olaleke2004@gmail.com

Time

within 24 hours

Stay Connected

SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers