Skip to content

Let users dim or hide the background dots - #245

Merged
SunkenInTime merged 6 commits into
mainfrom
t3code/background-dot-opacity
Oct 4, 2026
Merged

SunkenInTime merged 6 commits into
mainfrom
t3code/background-dot-opacity

Conversation

@SunkenInTime

@SunkenInTime SunkenInTime commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

A user asked for a way to turn off the dot grid behind the map (THINKII's feedback post, Sept 28). Settings → Map layers now has a Background dots slider. 100% is today's look and 0% hides the grid.

Editor background at 100%, 40% and 0%, zoomed 3x

The dots are faint even at 100%, so the crop above is zoomed 3×. At normal size the difference is subtle: the canvas goes from lightly textured to flat.

The new slider under Workspace map visibility

What follows the setting

  • The editor canvas, the loading skeleton, and the map theme and folder editor previews (everything that draws DotGrid).
  • The library background (HoverDotGrid). The cursor glow scales too, so 0% leaves no dots under the mouse either.
  • Screenshots and video exports (page_screenshot.dart, VideoExporter). Their offscreen container doesn't read Hive, so the value is passed in explicitly, the same way spawn barriers and region names already are.

Library background at 100%, 40% and 0%, zoomed 3x

Reproduction

On main, Settings has no control for the dots. They always draw at a fixed alpha of 0.7 on the border color.

Data

AppPreferences gets backgroundDotOpacity at Hive index 19 (generated, nextIndex 20), defaulting to 1.0. Preferences written by older builds have no field 19, so they read as 1.0 and the app looks unchanged. A test writes a record the way a pre-change build did and reads it back.

Library backups (from #234) already carry the other Map-layers toggles, so they now carry backgroundDotOpacity too, as an optional key in globals.appPreferences. A backup without the key, meaning every backup made before this PR, keeps the current value on import. The library-backup round-trip test checks both cases. .ica files don't hold preferences, so they don't change.

Verification

  • Captured the real editor, library and settings dialog with a throwaway widget-test harness, all on this build with only the slider value changed (100 / 40 / 0).
  • flutter analyze lib test: no new issues.
  • flutter test after merging main: 1581 passed. New tests cover old preferences loading at full opacity, persistence and clamping, the grid painting nothing at 0%, a hidden library grid not animating on mouse movement, and screenshots honoring the value they're given.

No migration, on purpose. This field is additive and the adapter default (1.0) is the old look, so no stored value needs rewriting, the same as fields 17 and 18. AGENTS.md now says this directly: a migration is needed when old data would not load correctly, and an additive field with an old-behavior default needs a test instead.

Full editor at 100% and 0%

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a “Background dots” setting to control dot visibility from fully hidden to fully visible.
    • The setting applies to workspace maps, screenshots, and exported videos, and is saved with preferences and library backups.
  • Bug Fixes
    • Older saved preferences and backups continue to load; backups without this setting preserve the current preference.

RetriggerConfidence Score: 5/5

The confirmed test reliability issue is non-blocking; no outstanding finding makes the product change unsafe to merge.

Findings

  1. P2 Wait for the painted grid ▶
  2. P2 Hidden grid retains hover ▶

Summary

The PR adds a persisted Background dots setting across the editor, library, screenshots, video exports, and backups. The new glow regression test can fail on slower runners when its fixed wait ends before the shader loads.

Reviews (7) · Last reviewed commit: "Test that hidden dots come back without ..."

A "Background dots" slider under Map layers sets how strongly the dot grid
draws behind the map, the library, and exported screenshots and videos.
100% is today's look; 0% hides the grid. The value is a new AppPreferences
field (index 19) that defaults to 1.0, so preferences saved by older builds
load unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 39 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c959d393-124d-43a7-944d-e3b4fd8cf9f1
📥 Commits

Reviewing files that changed from the base of the PR and between 9cf98bd and 093d33b.

📒 Files selected for processing (2)
  • lib/widgets/hover_dot_grid.dart
  • test/hover_dot_grid_glow_test.dart

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b04c15d7-1f26-488b-8028-b34eb27f383a
📥 Commits

Reviewing files that changed from the base of the PR and between 4a5ff45 and 9cf98bd.

📒 Files selected for processing (18)
  • AGENTS.md
  • lib/hive/hive_adapters.g.dart
  • lib/hive/hive_adapters.g.yaml
  • lib/screenshot/page_screenshot.dart
  • lib/screenshot/screenshot_view.dart
  • lib/services/archive_manifest.dart
  • lib/services/video_export/video_exporter.dart
  • lib/strategy/strategy_import_export.dart
  • lib/widgets/dialogs/export_video_dialog.dart
  • lib/widgets/dot_painter.dart
  • lib/widgets/hover_dot_grid.dart
  • lib/widgets/settings_tab.dart
  • test/background_dot_opacity_test.dart
  • test/interactive_map_canonical_center_test.dart
  • test/screenshot_view_test.dart
  • test/strategy_folder_import_test.dart
  • test/video_export_navigation_failure_test.dart
  • test/video_exporter_sink_test.dart

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

App preferences now include a persisted background dot opacity setting. Map and screenshot dot grids use the setting, video exports pass it to screenshots, and library backups serialize and restore it.

Changes

Background Dot Opacity

Layer / File(s) Summary
Persist and edit opacity
lib/providers/user_preferences_provider.dart, lib/hive/hive_adapters.g.dart, lib/hive/hive_adapters.g.yaml, lib/widgets/settings_tab.dart, AGENTS.md, test/background_dot_opacity_test.dart, test/interactive_map_canonical_center_test.dart, test/strategy_view_skeleton_test.dart
App preferences add backgroundDotOpacity, defaulting to 1.0; the setter clamps values to 0.0–1.0. Hive reads older records with a default of 1.0. The settings tab adds a slider, and tests cover persistence, backward compatibility, and provider setup.
Apply opacity to map and export dot grids
lib/widgets/dot_painter.dart, lib/widgets/hover_dot_grid.dart, lib/screenshot/page_screenshot.dart, lib/screenshot/screenshot_view.dart, lib/services/video_export/video_exporter.dart, lib/widgets/dialogs/export_video_dialog.dart, test/background_dot_opacity_test.dart, test/screenshot_view_test.dart, test/video_export_navigation_failure_test.dart, test/video_exporter_sink_test.dart
DotGrid and HoverDotGrid scale their rendering by the preference and skip rendering at nonpositive opacity. Screenshot capture and video export pass the opacity to ScreenshotView. Tests cover dot rendering, hover behavior, and exporter setup.
Include opacity in library backups
lib/services/archive_manifest.dart, lib/strategy/strategy_import_export.dart, test/strategy_folder_import_test.dart
Library backup manifests include the opacity value. Imports clamp a supplied value to 0.0–1.0 and retain the current preference when the key is absent. Tests cover round-trip and legacy backups.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant ExportVideoDialog
  participant AppPreferencesProvider
  participant VideoExporter
  participant ScreenshotView
  participant DotGrid
  ExportVideoDialog->>AppPreferencesProvider: Read backgroundDotOpacity
  ExportVideoDialog->>VideoExporter: Pass backgroundDotOpacity
  VideoExporter->>ScreenshotView: Pass backgroundDotOpacity
  ScreenshotView->>DotGrid: Pass opacity
Loading

Merge Risk: ⚪ Minimal · up to 9cf98

No merge-blocking issue is identified; the change is ready to merge after normal checks.

Security Architecture Review

Security architecture risk: ⚪ Minimal · up to 9cf98

The new setting controls cosmetic background dots. The reviewed changes preserve older saved preferences, validate imported values and do not introduce new access permissions or sensitive-data exposure. No material security risk was identified in this change.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — An archive author can influence this added setting when the archive is imported. Its traced effects extend across the local application's dot backgrounds and exported dot appearance, not to tenant identity, service privileges or resource selection.

Trust Boundaries and Controls

  • observed — The archive reader accepts numbers or parseable numeric strings, preserves missing/null as unspecified and throws FormatException for other values. Import clamps the resulting value to 0.0–1.0 before writing the existing preferences singleton; the settings setter also clamps its input.

Resilience and Maintainability Implications

  • observed — Library globals are committed before subsequent archive content, so a later import failure can leave the cosmetic preference applied. This non-atomic ordering predates the PR; adding opacity does not introduce a new privileged transition. Normal preference updates use the existing serialized write queue, which permits later writes after a failed write.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: users can dim or hide the background dots.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread lib/providers/user_preferences_provider.dart
Comment thread lib/widgets/hover_dot_grid.dart
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@SunkenInTime

Copy link
Copy Markdown
Owner Author

@greptileai review

Comment thread lib/widgets/hover_dot_grid.dart Outdated
void _handleGlobalPointer(PointerEvent event) {
if (event.kind != PointerDeviceKind.mouse) return;
// A hidden grid has no glow to animate.
if (ref.read(appPreferencesProvider).backgroundDotOpacity <= 0) return;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Hidden grid retains hover

If the pointer leaves the library grid while Background dots is at 0%, this return skips the exit handling. The grid stays mounted, so restoring the dots shows a glow at the pointer’s old position until another pointer event updates it. Clear the hover when hiding the grid, or continue handling exits while it is hidden.

Artifacts

Authored Flutter widget reproduction test

  • The test mounts each grid implementation, changes opacity around a real mouse exit, and inspects the restored painter’s hover and position.

Parent-commit grid implementation

  • This source was extracted from `HEAD^` and supplies the pre-change widget for the comparison run.

Baseline widget-test output without the guard

  • The Flutter test ran the parent-commit widget and observed restored hover 0.0 after the mouse exited while hidden.

Current widget-test output with the guard

  • The Flutter test ran the PR widget and observed restored hover 1.0 at the stale (80,80) position after the mouse exited while hidden.

Combined Flutter test execution record

  • The captured command, working directory, exit code, and output show both comparison tests passing with different restored hover values.

View artifacts

T-Rex Ran code and verified through T-Rex

@SunkenInTime SunkenInTime Oct 3, 2026 •

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 01f8056. While the opacity is 0, pointer events now reset the glow and its target to 0 instead of returning early, so turning the dots back on starts with no glow. test/hover_dot_grid_glow_test.dart covers it: hover until the glow is up, hide the dots, leave the grid, show them again, and expect a glow of 0. Without the fix it reads 1.0. (Correction to my first reply: the shader does load in flutter_tester.)

@SunkenInTime SunkenInTime reopened this Oct 3, 2026
SunkenInTime and others added 3 commits October 3, 2026 14:32
Main restructured screenshot and video capture (page_screenshot.dart) and
brought library-backup globals. The dot opacity now reaches the new capture
paths explicitly, and library backups carry it next to the other map-layer
toggles; backups without the key keep the current value.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An additive field whose default reproduces the old behavior loads from old
records without one, as AppPreferences fields 17-19 do. The rule now asks
for a migration only when old data would not load correctly, and for a test
that proves the additive case.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Moving the mouse off a hidden grid used to leave the glow target set, so
turning the dots back on showed a glow at the old pointer spot until the
next move.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@SunkenInTime

Copy link
Copy Markdown
Owner Author

@greptileai review

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Comment on lines +56 to +60
for (var i = 0; i < 10; i++) {
await tester.runAsync(
() => Future<void>.delayed(const Duration(milliseconds: 50)));
await tester.pump();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Wait for the painted grid

If the shader takes more than 500 ms to load on a slower runner, these ten delays finish before the grid creates its CustomPaint. The subsequent glow() lookup throws, failing the regression test even when the hover behavior is correct. Wait for the painted grid to appear before checking its glow. This is a non-blocking test reliability issue.

Artifacts

Shader-wait reproduction command

  • This executed script temporarily delays shader loading, runs the widget test in each condition, and restores the tracked sources.

Unmodified glow test passes

  • The original widget test ran without an injected delay and exited successfully.

Fixed wait fails with a delayed shader

  • The original widget test ran with a 750 ms shader delay and exited with `Bad state: No element` at `glow()`.

▶ Chromium capture of the fixed-wait test failure

  • Chromium displayed the captured failing widget-test output, emphasizing the missing `CustomPaint` lookup.

Poster showing the fixed-wait failure

  • A frame from the Chromium output capture shows the original test's failure under delayed shader loading.

Readiness-wait test passes with the same delay

  • The widget test ran with the same 750 ms shader delay and a bounded `CustomPaint` readiness wait, then exited successfully.

▶ Chromium capture of the readiness-wait test passing

  • Chromium displayed the captured passing widget-test output under the same delayed-load condition.

Poster showing the readiness-wait pass

  • A frame from the Chromium output capture shows the test passing after waiting for `CustomPaint`.

Chromium evidence-capture script

  • This executed Playwright script rendered the actual test logs in Chromium and recorded the paired videos and posters.

View artifacts

T-Rex Ran code and verified through T-Rex

@SunkenInTime
SunkenInTime merged commit 72afed8 into main Oct 4, 2026
14 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.

1 participant