Skip to content

[Bug]: macOS themed cursor stays stuck on pointer/text after returning to arrow #557

Description

@chendashi1024

Search existing issues

  • I have searched the existing issues, including issues and PRs about cursor choreography, cursor positioning, and AI overwriting concurrent edits.

Describe the bug

On macOS, a themed cursor can remain stuck on its last semantic cursor type (pointer or text) after the real cursor has returned to the normal arrow state.

I reproduced this with the Hello Kitty & Watermelon theme in OpenScreen 1.10.0:

  • the normal arrow sprite is the watermelon;
  • the pointer sprite is Hello Kitty;
  • after the recorded cursor leaves a clickable element, the preview can keep rendering Hello Kitty instead of returning to the watermelon arrow;
  • once this happens, moving the playhead or reselecting the same theme does not reliably restore the arrow sprite.

The problem became visible immediately after an AI edit finished removing unused sections and adding zooms. However, inspecting the saved .openscreen project showed that the agent had not changed legacyEditor.cursorTheme; it remained hello-kitty-watermelon. The agent only added trims and zooms.

This is therefore different from #284: the theme was selected before the agent turn, no cursor-theme edit was made while the agent was running, and the saved theme value was not overwritten.

Expected behavior

When macOS reports that the current cursor is no longer a special semantic type, the compositor should return to the captured/default arrow bitmap. With this theme, leaving a clickable element should switch from Hello Kitty back to the watermelon arrow.

The theme picker should also make it clear when a theme uses different artwork for arrow and pointer, instead of previewing only the arrow sprite.

To Reproduce

  1. Record a macOS screen interaction where the cursor moves from a normal area onto a clickable element and then back to a normal area.
  2. Open the recording in OpenScreen 1.10.0.
  3. Select the Hello Kitty & Watermelon cursor theme.
  4. Ask the AI editor to remove unused sections and add local zooms.
  5. Wait for the agent turn to finish and preview the edited timeline.
  6. Observe that the cursor can change to the Hello Kitty pointer sprite and remain there after the recorded cursor has left the clickable element. The inspector still shows the same theme selected.

The lower-level failure does not appear to depend on the AI edit itself: any cursor telemetry sequence equivalent to null/arrow -> pointer -> null/arrow can expose it.

Screenshots

Not attached because the reproduction recording contains private application content. The state transition and source-level cause below are deterministic.

OS

macOS

OS Version

macOS 15.4.1 (24E263)

Browser

Not applicable — OpenScreen desktop app.

Device Type

Laptop (MacBook Air, Mac16,12)

Additional context

There appears to be a semantic mismatch between the macOS cursor helper and the Rust compositor:

  1. The macOS helper returns nil for cursor states other than I-beam and pointing hand, with the comment that the renderer should fall through to the captured/default cursor bitmap:
    https://github.com/getopenscreen/openscreen/blob/main/electron/native/screencapturekit/Sources/OpenScreenMacOSCursorHelper/main.swift#L224-L231

  2. The compositor's cursor type track ignores samples whose cursorType is absent. type_at(t) therefore returns the last explicit semantic type at or before t, allowing pointer or text to persist across later null samples:
    https://github.com/getopenscreen/openscreen/blob/main/crates/compositor/src/cursor.rs#L100-L140

In the real .cursor.json sidecar used for this reproduction, the raw transitions included sequences such as:

2136 ms: pointer
2173 ms: null
2214 ms: pointer
2494 ms: null

Applying the current type_at logic means the 2173 ms null sample does not reset the state; the effective type remains pointer.

The selected theme deliberately maps the semantic types to different sprites:
https://github.com/getopenscreen/openscreen/blob/main/src/lib/cursor/cursorThemes.ts#L89-L113

The renderer resolves the full sprite set per semantic cursor type:
https://github.com/getopenscreen/openscreen/blob/main/src/lib/cursor/cursorThemes.ts#L480-L510

The theme picker, however, previews only theme.assets.arrow (falling back to pointer), so users see the watermelon during selection but are not shown that the same theme uses Hello Kitty for pointer:
https://github.com/getopenscreen/openscreen/blob/main/src/components/ai-edition/RightPanes.tsx#L2324-L2340

Possible fix direction: represent the normal arrow/fallback as an explicit reset transition in the cursor type track, or make type_at treat a macOS null sample as a reset rather than filtering it out. A regression test for pointer -> null -> arrow fallback would cover the failure.

Related but different:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions