Skip to content

fix: Screenshot annotations only mark reachable controls as clickable#1465

Merged
hatayama merged 6 commits into
mainfrom
fix/screenshot-annotation
Jul 3, 2026
Merged

fix: Screenshot annotations only mark reachable controls as clickable#1465
hatayama merged 6 commits into
mainfrom
fix/screenshot-annotation

Conversation

@hatayama

@hatayama hatayama commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • Screenshot annotations now avoid labeling disabled, covered, or otherwise unreachable UI controls as clickable.

User Impact

  • Button-like UI that cannot receive clicks is no longer shown as an actionable target in annotated screenshots.
  • Annotation output now matches what UI click simulation can actually interact with.

Changes

  • Reused the existing UI raycast reachability check when collecting screenshot annotation targets.
  • Skipped disabled canvases and raycasters consistently across annotation and UI simulation paths.
  • Added EditMode and PlayMode coverage for disabled canvases, visible buttons, and covered controls.

Verification

  • uloop compile --wait-for-domain-reload true
  • uloop run-tests --test-mode EditMode --filter-type regex --filter-value "UIElementAnnotatorTests"
  • uloop run-tests --test-mode PlayMode --filter-type regex --filter-value "SimulateMouseUiTests"
  • git diff --check

Review in cubic

Summary

  • Updated screenshot annotation target collection to mark only UI controls that are actually raycast-reachable/clickable, reusing the same UiRaycastHelper reachability logic used by UI mouse click simulation.
  • Refactored UiRaycastHelper to centralize UI hit-testing in a frame-scoped RaycastContext that snapshots EventSystem pointer/Canvas+Graphic raycast inputs and selects the preferred hit using the existing priority rule.
  • Aligned canvas and raycaster handling with click simulation: disabled canvases/graphics are excluded, and covered/unreachable controls are not treated as actionable.
  • Improved annotation overlay rendering by switching to a two-pass approach (borders first, then labels) so label hierarchy remains visible when elements overlap.

Tests

  • EditMode (UIElementAnnotatorTests): added fixture setup/teardown cleanup and new coroutine coverage to verify CollectInteractiveElements() skips buttons under disabled canvases and includes buttons when visible; added coverage for overlay render ordering (labels above borders).
  • PlayMode (SimulateMouseUiTests): added regression tests to ensure clicks ignore disabled ScreenSpaceOverlay contents and to ensure interactables covered by a front UI graphic are excluded from collected interactive elements.

Use the same raycast reachability check for screenshot annotations as UI input simulation so disabled canvases and covered controls are not reported as clickable.
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@hatayama, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ea000747-a45b-4498-9c49-662da55c8b4b

📥 Commits

Reviewing files that changed from the base of the PR and between bb41522 and 607d568.

📒 Files selected for processing (1)
  • Assets/Tests/Editor/UIElementAnnotatorTests.cs
📝 Walkthrough

Walkthrough

Refactors UI raycast handling to reuse a cached RaycastContext, passes that context through interactive-element collection and reachability checks, splits annotation overlay rendering into separate border and label passes, and adds editor and playmode tests for disabled, covered, and multi-element UI scenarios.

Changes

Raycast reuse and annotation flow

Layer / File(s) Summary
Cached raycast context in UiRaycastHelper
Packages/src/Editor/Api/McpTools/SimulateMouseUi/UiRaycastHelper.cs
RaycastUI uses an internal RaycastContext with cached pointer data, results, and canvas raycast sources; canvas-space hit testing is moved into cached source collection and selection helpers.
Raycast context through UIElementAnnotator
Packages/src/Editor/Utils/UIElementAnnotator.cs
CollectInteractiveElements, CollectSelectables, CollectEventHandlers, and AddElementInfo now pass a shared raycast context through reachability checks, and IsRaycastReachable uses RaycastContext.Raycast.
Overlay rendering split into draw passes
Packages/src/Editor/Utils/UIElementAnnotator.cs
CreateAnnotationOverlay now precomputes AnnotationDrawInfo and renders borders and labels in separate passes using new helper methods and a private draw-info struct.
Editor and playmode UI tests
Assets/Tests/Editor/UIElementAnnotatorTests.cs, Assets/Tests/PlayMode/SimulateMouseUiTests.cs
Editor tests add fixture setup and teardown, overlay ordering coverage, coroutine checks for interactive element collection, and helper methods; playmode tests add disabled-canvas click coverage and blocked-button collection coverage.

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

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: screenshot annotations now only mark reachable UI controls as clickable.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/screenshot-annotation

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.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 4 files

Re-trigger cubic

hatayama added 4 commits July 3, 2026 17:11
Avoid repeated Canvas and Graphic scans while collecting screenshot annotations so reachability filtering stays aligned with UI input behavior without adding per-element scene-wide work.
Render all annotation borders before creating labels so label tabs remain visible when they overlap another element's outline.
Drop unused raycast helper entry points and keep annotation draw values shared between border and label passes so the overlay code stays narrow after the review cleanup.
Clarify that RaycastContext snapshots Canvas and Graphic state so future callers keep it scoped to one frame instead of caching stale UI state.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
Assets/Tests/PlayMode/SimulateMouseUiTests.cs (1)

341-356: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Missing explanatory comment for the regression scenario.

Every other non-trivial regression test in this file (e.g. lines 115-117, 171-173, 235-237) has a comment explaining the specific gotcha being tested. Consider adding one here noting that a front Graphic blocks raycast reachability so covered controls are correctly excluded from annotation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Assets/Tests/PlayMode/SimulateMouseUiTests.cs` around lines 341 - 356, Add a
short explanatory comment in
CollectInteractiveElements_Should_SkipButtonCoveredByFrontGraphic to describe
the regression being covered: a front Graphic intercepts raycasts, so the
covered control should be excluded from
UIElementAnnotator.CollectInteractiveElements. Place it near the blocker
setup/assertion so the intent matches the other regression tests in
SimulateMouseUiTests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Assets/Tests/Editor/UIElementAnnotatorTests.cs`:
- Around line 15-21: The SetUp fixture in UIElementAnnotatorTests relies on
AddComponent<EventSystem>() to become current, which can leave
UIElementAnnotator.CollectInteractiveElements() using a stale EventSystem.
Update SetUp to explicitly assign EventSystem.current to the newly created
EventSystem on UIElementAnnotatorTestsEventSystem, and clear or replace any
existing current system before running the test so the raycast context is always
the fixture’s own.

---

Nitpick comments:
In `@Assets/Tests/PlayMode/SimulateMouseUiTests.cs`:
- Around line 341-356: Add a short explanatory comment in
CollectInteractiveElements_Should_SkipButtonCoveredByFrontGraphic to describe
the regression being covered: a front Graphic intercepts raycasts, so the
covered control should be excluded from
UIElementAnnotator.CollectInteractiveElements. Place it near the blocker
setup/assertion so the intent matches the other regression tests in
SimulateMouseUiTests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 26196f51-58b2-4d08-b530-a1765e7baafd

📥 Commits

Reviewing files that changed from the base of the PR and between 2cea66f and 0562d45.

📒 Files selected for processing (4)
  • Assets/Tests/Editor/UIElementAnnotatorTests.cs
  • Assets/Tests/PlayMode/SimulateMouseUiTests.cs
  • Packages/src/Editor/Api/McpTools/SimulateMouseUi/UiRaycastHelper.cs
  • Packages/src/Editor/Utils/UIElementAnnotator.cs

Comment thread Assets/Tests/Editor/UIElementAnnotatorTests.cs
Disable and restore any pre-existing EventSystem during UIElementAnnotatorTests so annotation collection does not raycast through stale editor scene state.
@hatayama hatayama merged commit 90e7483 into main Jul 3, 2026
9 checks passed
@hatayama hatayama deleted the fix/screenshot-annotation branch July 3, 2026 09:21
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