Can CeylanVienna-based, globally curious.
Learn/Frontend

Do not build masks from translucent polygons

A map overlay looked like fog-of-war in theory, but overlapping transparent buffers created ugly rings. The fix was to treat it as one composited mask, not many semi-transparent shapes.

2026-05-30·2 min read·intermediate

What happened

A map needed a fog-of-war effect: areas with data should feel visible, and areas without data should stay dark.

The first implementation used circular buffer polygons around every data point. Each buffer had soft transition rings with different opacities. In isolation, one buffer looked reasonable.

But once multiple data points were close together, the map turned into a mess of dark circular bands. The visual effect looked like stacked shadows instead of explored territory.

Root cause

The mistake was using many translucent polygons for a masking problem.

Map renderers blend every semi-transparent shape independently. If three rings overlap, their opacity stacks. If ten rings overlap, the area becomes much darker than intended.

The system was technically doing the right thing. The model was wrong.

A fog effect should answer one question:

How visible should this pixel be?

The polygon approach answered a different question:

How many semi-transparent shapes happen to cover this pixel?

Those are not equivalent.

Why it was non-obvious

The bug hides because the first few test cases look fine.

One circle creates a nice transition. Two circles still seem acceptable. Then real data arrives, nearby buffers overlap, and the renderer starts accumulating darkness in unpredictable-looking bands.

This is especially easy to miss in AI-assisted UI work because the proposed solution sounds geospatially correct: "create buffer zones around covered areas." But the desired output was not a geographic fact. It was a visual effect.

The fix

Use a single composited mask.

The corrected implementation used a canvas layer above the map:

  1. Draw one dark rectangle over the whole viewport.
  2. For each covered area, subtract a soft radial gradient from that dark layer.
  3. Redraw the canvas when the map moves, zooms, resizes, or receives new data.

Now overlaps reveal more of the map instead of adding more darkness.

The important change was not canvas itself. It was changing the mental model:

One mask, many cutouts.

Not:

Many transparent overlays.

Reusable rule

Use map polygons for geographic facts.

Use canvas, WebGL, or another compositing layer for visual masks.

Good uses for polygons:

  • boundaries
  • regions
  • hex cells
  • selected areas
  • measured buffers that represent real spatial meaning

Bad use for overlapping translucent polygons:

  • fog-of-war
  • spotlight effects
  • progressive reveal
  • darkness/lightness masks
  • any effect where opacity should not depend on shape count

If the overlay is supposed to behave like a mask, build a mask. Do not approximate it with many semi-transparent geometries.

Practical test

Before shipping a visual map overlay, test it with clustered data.

Sparse points can hide blending bugs. Dense points reveal whether the effect is truly composited or just stacked.

If adding more data makes the overlay darker, louder, or ring-shaped, the rendering model is wrong.

More like this, straight to your inbox.

I write about Frontend and a handful of other things I actually care about. No schedule, no filler. Just when I have something worth saying.

More on Frontend

Building a web app for future native migration: constraints from day one

If you're planning to wrap your web app in a native shell later, the constraints aren't optional from day one. Web-only APIs baked into your components will block the migration.

The no-build frontend: when you don't need React

Most internal tools and personal dashboards don't need a JavaScript framework. Here's the case for plain HTML and when the complexity earns its keep.

If this raised a question, I'd be happy to talk about it.

Find me →
← Back to Learn