Skip to content

fix(log-viewer): keep timeline text crisp when display scaling changes - #1065

Merged
lcottercertinia merged 3 commits into
certinia:mainfrom
lukecotter:bug-timeline-dpr-tracking
Sep 17, 2026
Merged

lcottercertinia merged 3 commits into
certinia:mainfrom
lukecotter:bug-timeline-dpr-tracking

Conversation

@lukecotter

@lukecotter lukecotter commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

📝 PR Overview

The flame chart, governor strip and minimap each read devicePixelRatio once, when their PIXI app is created. If the ratio changes afterwards — Windows display scaling moving between 125% and 150%, or the window moving to a monitor with a different scale factor — the canvases keep the resolution they were built at, so their text is upscaled and reads blurred until the log is reopened.

This makes the timeline follow the ratio instead of sampling it once.

🛠️ Changes made

  • Read devicePixelRatio once per FlameChart.resize and pass that one value to all three renderers, so they cannot land on different ratios.
  • Add the resolution to resize's skip guard. A ratio change leaves the box identical, so without this the existing "geometry unchanged" fast path returned before touching any renderer.
  • Watch for ratio changes in TimelineResizeHandler. No DOM event reports one, so a media query bound to the current ratio is re-made each time it stops matching.
  • Re-measure the container when the ratio changes rather than replaying the last size. A zoom step moves the ratio and the box together and the watcher runs before the resize observer, so replaying the old size painted a box the zoom had already left and then painted again.
  • Key the minimap's cached static texture on resolution as well as size. It is only rebuilt when width or height change, so the skyline, markers and axis would otherwise keep the old resolution even once the renderer had the new one.

🧩 Type of change (check all applicable)

  • 🐛 Bug fix - something not working as expected
  • ✨ New feature – adds new functionality
  • ♻️ Refactor - internal changes with no user impact
  • ⚡ Performance Improvement
  • 📝 Documentation - README or documentation site changes
  • 🔧 Chore - dev tooling, CI, config
  • 💥 Breaking change

🔗 Related Issues

None — found while checking the timeline's rendering on a scaling change.

✅ Tests added?

  • 👍 yes

Three behaviours, each checked to fail without its fix by breaking that fix on its own:

  • FlameChartResize.test.ts — a resize where only the ratio moved still applies.
  • TimelineResizeHandler.test.ts — the watcher binds to the ratio in force, and on a change re-renders the re-measured box and re-arms on the new ratio. A second test covers teardown.
  • MinimapStaticTexture.test.ts — the cached texture is rebuilt when only the ratio moved.

📚 Docs updated?

  • 🔖 README.md
  • 🔖 CHANGELOG.md
  • 📖 help site
  • 🧪 Marked any pre-release-only features (README 🧪 badge — see RELEASING.md)
  • 🙅 not needed

Anything else we need to know? [optional]

Verified in the extension development host: with the ratio change reproduced, devicePixelRatio and the canvas backing-store ratio now move together.

The legacy timeline (features/timeline/services/Timeline.ts) has the same bug and is not fixed here — its dpr is set once at module load and the dpr ??= … at line 491 can never re-fire. It is reachable through the timeline.legacy setting. Happy to follow up separately.

One remaining ceiling this does not own: the shared bitmap font is built at a fixed 2x (TextLabelRenderer.ts), so at ratio 3 labels still upscale from a 2x atlas.

The flame chart, governor strip and minimap read devicePixelRatio once at
load, so their text stayed at the old ratio after a scaling change or a move
to a monitor with a different scale factor, until the log was reopened.

Read the ratio on every resize and add it to the skip guard, so a resize that
changes only the resolution still applies. Watch for ratio changes, which
resize nothing and so never reach the resize observer, and re-measure there
rather than replaying a stale size. Key the minimap's cached static texture
on resolution too, or the skyline, markers and axis keep the old one.
Drop the zero guard in the ratio handler: FlameChart is the only IResizable
and already rejects a width or height of zero.

Cut the tests to the three that fail without a fix, and drop the comments
the code already says.
@lcottercertinia
lcottercertinia merged commit 61f2fd7 into certinia:main Sep 17, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants