mapbox / mapbox/mapbox-gl-js

Dynamically restyle map based on framerate

Open
#10,330 2 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

cross-platform :tv: feature :green_apple: needs discussion :speech_balloon:
Dominant language
TypeScript
Stars
12.4k
Forks
2.4k
PR merge metrics
No merged PRs in 30d

Description

## Motivation

Achieving a stable framerate can be a challenge, especially on lower end devices. One of the best ways you can do this is within the style. Reducing layer complexity, label collisions, aggressively filtering, so on and so forth.

This presents a nasty tradeoff: simplify a style and get a stable framerate on lower end devices, compromising the experience on better devices; or design the ideal style, which could make your map tremendously difficult to use for those folks on lower end devices.

## Design

I propose including a map state lookup expression like `["zoom"]` which returns the time to render the previous frame, or the maximum time to render a frame in this session. Something like `["frametime"]`. A map designer could use `["frametime"]` within a case expression to filter more and more features out of a layer in order to dynamically simplify a style and boost framerates on weaker devices, while preserving the style on higher end devices.

This design puts control in the hands of map designers, and allows them to shape a graceful, progressively "dehanced" style for lower end devices, while designing with an ideal style in mind.

If we determine that `["frametime']` leads to the style "flapping" (e.g. frame time is high => simplify style => frame time improves => complexify style => frame time is high => ) we could instead report the maximum frame time since the map began rendering, or the maximum frame time in the last ~240 frames or something like that.

### Mock-Up

Example of how we could simplify a layer by adjusting its filter dynamically based on the frame time.

```js
{
"id": "my-road-network",
"filter": [
"case",
// worse than 60fps remove tertiary roads
[["frametime"], ">", 16.666]
[
"match",
["get", "class"],
["primary", "secondary"],
true,
false
],
// worse than 30fps remove tertiary & secondary roads
[["frametime"], ">", 33.333]
[
"match",
["get", "class"],
["primary"],
true,
false
],
// 60fps or better show all roads
[
"match",
["get", "class"],
["primary", "secondary", "tertiary"],
true,
false
]
]
}
```

### Concepts

If we embrace this design, I think we'd need to figure out whether frame time or framerate makes sense. Frame time (e.g. 16.666ms) is a bit more flexible, framerate (e.g. 60fps) is more well-known outside of graphics programming circles.

We'd need documentation and recommendations around how to best use this expression as well.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue names no files or tests. Start by reviewing the expression evaluation and frame-rendering paths, then resolve whether frame time or framerate should be exposed and how to avoid the proposed style flapping. Done means an agreed implementation design, with documentation and recommendations for using the new expression.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
frontend, performance, web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.