Skip to content

Commit fb5ee2c

Browse files
jkuriclaude
andcommitted
fix(editor): improve cursor overlay smoothness in preview playback
Cache cursor bitmap image and only re-render when style or size changes, avoiding expensive CGContext drawing on every frame. Increase time observer frequency from 30fps to 60fps for smoother cursor position updates. Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent a2f409e commit fb5ee2c

File tree

2 files changed

+18
-9
lines changed

2 files changed

+18
-9
lines changed

Reframed/Editor/CursorOverlayLayer.swift

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ final class CursorOverlayLayer: CALayer {
99
private var cursorVisible = true
1010
private var clickColor: CGColor?
1111
private var clickSize: CGFloat = 36
12+
private var cachedImage: CGImage?
13+
private var cachedImageStyle: CursorStyle = .defaultArrow
14+
private var cachedImageSize: CGFloat = 0
1215

1316
override init() {
1417
super.init()
@@ -75,14 +78,20 @@ final class CursorOverlayLayer: CALayer {
7578
}
7679
cursorLayer.frame = cursorRect
7780

78-
let scale = NSScreen.main?.backingScaleFactor ?? 2.0
79-
cursorLayer.contentsScale = scale
80-
let imgW = Int(cursorRect.width * scale)
81-
let imgH = Int(cursorRect.height * scale)
82-
let padPx = pad * scale
83-
84-
if let cgImage = renderCursorImage(style: style, size: size * scale, padPx: padPx, width: imgW, height: imgH) {
85-
cursorLayer.contents = cgImage
81+
let needsImageUpdate = style != cachedImageStyle || abs(size - cachedImageSize) > 0.01
82+
if needsImageUpdate {
83+
let scale = NSScreen.main?.backingScaleFactor ?? 2.0
84+
cursorLayer.contentsScale = scale
85+
let imgW = Int(cursorRect.width * scale)
86+
let imgH = Int(cursorRect.height * scale)
87+
let padPx = pad * scale
88+
89+
if let cgImage = renderCursorImage(style: style, size: size * scale, padPx: padPx, width: imgW, height: imgH) {
90+
cursorLayer.contents = cgImage
91+
cachedImage = cgImage
92+
cachedImageStyle = style
93+
cachedImageSize = size
94+
}
8695
}
8796

8897
updateClickLayers(clicks: clicks, containerSize: containerSize)

Reframed/Editor/SyncedPlayerController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ final class SyncedPlayerController {
102102
}
103103

104104
func setupTimeObserver() {
105-
let interval = CMTime(value: 1, timescale: 30)
105+
let interval = CMTime(value: 1, timescale: 60)
106106
timeObserver = screenPlayer.addPeriodicTimeObserver(forInterval: interval, queue: .main) {
107107
[weak self] time in
108108
MainActor.assumeIsolated {

0 commit comments

Comments
 (0)