How Pixel Hyderabad Was Made
A zoomable, animated, isometric pixel-art map of central Hyderabad, from Charminar to Hussain Sagar.

This project began as a tribute to Yadong Xie's Pixel Singapore. That project renders a real city in 3D, redraws it as pixel art, and serves the result as a gigantic deep-zoom image with little moving things on top. I wanted the same thing for Hyderabad. I also gave myself two constraints: use only open data, and make every pixel deterministic. There are no API keys and no image model.
The pipeline has the same five steps as Pixel Singapore. The tools inside each step are different.
- Model: build a 3D city from OpenStreetMap and an elevation model.
- Render: draw it with an isometric camera in a hand-written WebGL2 renderer.
- Pixelate: a post-process pass that makes it read as pixel art.
- Tile: cut a 260-megapixel image into a deep-zoom pyramid.
- Animate: traffic, metro trains, water, birds and kites, drawn live in the browser.
1 · The camera
Everything starts with the projection. Like Singapore, the camera is orthographic, rotated 15° west of north and tilted 45° down. The rotation lines up the Old City's main axes nicely and keeps Hussain Sagar from sitting dead-centre. At the full-resolution level, one image pixel is 0.5 m on the ground (2 px/m). Singapore used 0.25 m/px; I chose 0.5 m to cover more city on a laptop. The whole projection is one line:
screen = [ s·(x·R0 + y·R1), −s·((x·F0 + y·F1)·sin45° + z·cos45°) ]
The final image is 40,960 × 22,528 px (923 MP). It covers about 18 × 11 km, from the glass towers of HITEC City and the Financial District in the west, across Jubilee and Banjara Hills, to Hussain Sagar and down to Mecca Masjid in the Old City.
2 · Building the city from open data
All geometry comes from OpenStreetMap through Overpass. The terrain comes from the AWS Terrain Tiles DEM, resampled to a 10 m grid. Hyderabad sits on the gently rolling Deccan plateau, and hills like Naubat Pahad, under Birla Mandir, show up in the terrain.
| What | Count |
|---|---|
| Extruded buildings (with courtyards/holes) | 268,413 |
| Road segments | 61,675 |
| Low-poly trees | 931,406 |
| Metro viaduct ways (red / green / blue lines) | 62 |
| Hand-modelled landmarks | 9 |
Very few buildings in Hyderabad have height tags in OSM, so heights are a heuristic. Each building starts from its footprint area and type, then gets a deterministic random jitter from its id. Buildings south of the Musi are capped at four floors so the Old City stays low and dense. Roofs get water tanks and stair huts, since nearly every Hyderabad roof has a Sintex tank. Mosques get domes and minarets; temples get shikhara cones.
The nine landmarks are built procedurally in code: Charminar, Mecca Masjid, Chowmahalla Palace, Salar Jung Museum, Birla Mandir, Jubilee Hall, the domed new Telangana Secretariat, Prasads IMAX, and the Buddha statue on its rock in the lake. The metro runs on a viaduct 13 m up, on pillars with caps. Roads get kerbs, outlines and lane dashes, and flyovers get ramps and piers.
The mesh builder turns all of this into two binary groups, chunked on a 512 m grid:
| Group | Chunks | Vertices | Triangles |
|---|---|---|---|
| Flats (terrain, ground, water, roads, rail) | 2,171 | 18.91 M | 21.37 M |
| Solids (buildings, trees, landmarks, viaducts) | 1,377 | 49.83 M | 43.85 M |
That comes to about 2.4 GB of geometry and 65 million triangles, built in under ten seconds. The chunks are streamed to disk one at a time, so the build peaks at about 2 GB of RAM.
3 · Rendering
Pixel Singapore used photogrammetry tiles. I had only flat OSM polygons and a DEM, so I wrote a small raw WebGL2 renderer that runs in headless Chrome on the Mac's GPU through Metal. Node serves the binary chunks by byte range, and the page renders a 4096 px shot and posts the PNG back. It takes 60 shots of 4–7 seconds each, so the whole city renders in about five minutes.
Each shot goes through five passes:
- A shadow map from a late-afternoon sun (azimuth 235°, elevation 42°) for long, warm shadows.
- A terrain depth pass for the draped flat layers.
- The flat layers, ordered by a per-layer z value instead of geometry height. Roads always sit over parks, and parks over ground, without z-fighting, even where everything is draped on hills.
- The solids, which are lit in a few hard bands and shadowed. Windows are generated in the shader from wall height and distance along the facade, and glass towers get a cooler tint.
- A post pass that does the pixel-art work: outlines from depth and material-id edges, an ordered Bayer dither, and quantization of each channel to 28 levels.

Each shot is rendered with 64 px of padding and cropped when saved, so outlines and shadows match across shot boundaries. The stitched overview has no visible seams.
4 · Tiles
The 60 shots are cut into a standard Deep Zoom (DZI) pyramid: 17 levels of 512 px WebP tiles, 4,713 tiles and 366 MB in total. The top two levels are downsampled with nearest-neighbour so the pixels stay crisp when you zoom in. The lower levels use Lanczos so the zoomed-out city looks like a city rather than noise.

5 · Bringing it to life
The viewer is OpenSeadragon with image smoothing turned off. A second canvas sits on top and redraws every frame in image coordinates, so the animation stays registered at any zoom.
- Traffic: 35,283 drivable road paths, projected into image space and resampled every 12 m. Each one carries cars, two-wheelers, yellow-green autos and red or blue TSRTC buses. Density and speed depend on road class, and one-way roads loop.
- Metro: six-car trains in red, green and blue livery run up and down the viaduct at deck height.
- Water: glints twinkle across Hussain Sagar and the Musi.
- Sky: V-shaped bird flocks drift across the map, and kites fly over the Old City.
- Labels: landmarks, neighbourhoods and metro stations fade in and out by zoom level.
A CSS tilt-shift effect (a masked backdrop blur at the top and bottom of the screen) makes the view feel like a model. The blur gets stronger as you zoom in. There's also a minimap, a lat/long readout that inverts the projection, and shareable #x,y,zoom URLs.

Going west: HITEC City
The first version stopped at Banjara Hills. Most of Hyderabad's glass is further west, so the map now reaches HITEC City, Gachibowli and the Financial District. OSM rarely tags heights out there, so inside a few hand-drawn tech-zone boxes any large footprint (over 700 m²) without a height becomes a 6–28 floor tower. Most of those get the glass material and a blue-grey palette. The west is also much less green, so tree density on generic land is scaled down west of Banjara Hills.

What I'd do next
- Use real building heights. Footprints from Google Open Buildings or Microsoft data, combined with height estimates, would make the skyline less uniform.
- Push further west to Kokapet and Narsingi, and east to Uppal, once the tile budget allows.
- Add an optional image-model redraw pass, like the original, on top of the procedural render, using the mask to keep geometry fixed.
- Add a night mode, with streetlights along the road paths and a lit Charminar.
Map data © OpenStreetMap contributors (ODbL). Elevation from Terrain Tiles on AWS Open Data. The original idea and structure come from Yadong Xie's Pixel Singapore. Building heights are estimated; this map is not for navigation.
› explore the map