@jian-ai/remote-control 0.8.2 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@
3
3
  Jian Remote Control — Linux computer-use helper (X11).
4
4
 
5
5
  Newline-delimited JSON on stdin → JSON lines on stdout (same cmds as macOS helper).
6
- Overlay: override-redirect window with geometric white pointer + soft blue glow.
6
+ Overlay: override-redirect window with white pointer + #2880F8 stroke/glow (parity with macOS sprite).
7
7
  Input: xdotool when available (save/restore cursor around clicks so the user's
8
8
  pointer is not left at the Jian position). Wayland: best-effort; overlay may be
9
9
  unavailable — input still works when ydotool/wtype/xdotool can reach the session.
@@ -279,13 +279,14 @@ class Overlay:
279
279
  cmap = X11.XDefaultColormap(self.dpy, self.screen)
280
280
  white = XColor()
281
281
  exact = XColor()
282
- if X11.XAllocNamedColor(self.dpy, cmap, b"#FAFAF8", byref(white), byref(exact)):
282
+ if X11.XAllocNamedColor(self.dpy, cmap, b"#FFFFFF", byref(white), byref(exact)):
283
283
  X11.XSetForeground(self.dpy, self.gc, white.pixel)
284
284
  glow = XColor()
285
- if X11.XAllocNamedColor(self.dpy, cmap, b"#3A7AD6", byref(glow), byref(exact)):
285
+ # Match macOS ship sprite stroke #2880F8 (geometric stand-in; bitmap is macOS-only).
286
+ if X11.XAllocNamedColor(self.dpy, cmap, b"#2880F8", byref(glow), byref(exact)):
286
287
  X11.XSetForeground(self.dpy, self.gc_glow, glow.pixel)
287
288
  ink = XColor()
288
- if X11.XAllocNamedColor(self.dpy, cmap, b"#171716", byref(ink), byref(exact)):
289
+ if X11.XAllocNamedColor(self.dpy, cmap, b"#2880F8", byref(ink), byref(exact)):
289
290
  X11.XSetForeground(self.dpy, self.gc_ink, ink.pixel)
290
291
  self.available = True
291
292
  return True
Binary file
@@ -5,8 +5,9 @@
5
5
  Protocol: newline-delimited JSON on stdin → newline-delimited JSON on stdout (flush each).
6
6
  Errors go to stderr in English only.
7
7
 
8
- Pointer UX (Lucas / v0.8.2 polish):
9
- - Geometric white arrow (anathema-white style) with a soft brand-blue glow underneath.
8
+ Pointer UX (Lucas / v0.8.3):
9
+ - Bitmap sprite: white fill + thick #2880F8 stroke + soft blue glow (embedded PNG).
10
+ Prefer sprite over live CGPath so AA/glow match the approved preview.
10
11
  - Agent actions save the user’s cursor, hide it briefly, drive HID at the target, then
11
12
  restore — so clicks do not leave the physical mouse stranded at the Jian position.
12
13
  - Overlay tip animates (ease-out) between positions; system cursor is not the visible UX.
@@ -79,18 +80,225 @@ private func intValue(_ object: [String: Any], _ key: String) -> Int? {
79
80
  return nil
80
81
  }
81
82
 
82
- // MARK: - Colors (Jian + geometric white pointer)
83
+ // MARK: - Pointer sprite (embedded PNG)
83
84
 
84
- private let jianInk = NSColor(srgbRed: 0x17 / 255, green: 0x17 / 255, blue: 0x16 / 255, alpha: 1)
85
- /// Soft brand blue under the pointer — visible, not neon.
86
- private let jianGlow = NSColor(srgbRed: 0x3A / 255, green: 0x7A / 255, blue: 0xD6 / 255, alpha: 1)
87
- private let pointerWhite = NSColor(srgbRed: 0xFA / 255, green: 0xFA / 255, blue: 0xF8 / 255, alpha: 1)
85
+ /// Soft click-ripple blue (matches ship stroke #2880F8).
86
+ private let jianGlow = NSColor(srgbRed: 0x28 / 255, green: 0x80 / 255, blue: 0xF8 / 255, alpha: 1)
88
87
 
89
88
  private let sessionAlpha: CGFloat = 0.94
90
89
  private let idleAlpha: CGFloat = 0.18
91
- private let pointerSize: CGFloat = 36
92
- /// Tip of the geometric arrow (hotspot) near the view's top-left.
93
- private let hotspot = CGPoint(x: 2, y: 2)
90
+ /// Padded sprite canvas (40 pt blade + 10 pt glow pad each side).
91
+ private let pointerSize: CGFloat = 60
92
+ /// Tip hotspot in the padded 60 pt view (content tip was (2,2) in the 40 pt box).
93
+ private let hotspot = CGPoint(x: 12, y: 12)
94
+
95
+ /// Ship asset `macos/jian-pointer.png` (@3x master) as base64 — single-file helper stays
96
+ /// reliable when only the binary is copied into Application Support (no sidecar PNG).
97
+ private let jianPointerPngBase64 = """
98
+ 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
291
+ """
292
+
293
+ private let jianPointerImage: NSImage? = {
294
+ guard let data = Data(base64Encoded: jianPointerPngBase64, options: .ignoreUnknownCharacters)
295
+ else {
296
+ fputs("computer-helper: embedded pointer PNG base64 decode failed\n", stderr)
297
+ fflush(stderr)
298
+ return nil
299
+ }
300
+ return NSImage(data: data)
301
+ }()
94
302
 
95
303
  // MARK: - Overlay view
96
304
 
@@ -106,7 +314,7 @@ private final class JianPointerView: NSView {
106
314
  guard let ctx = NSGraphicsContext.current?.cgContext else { return }
107
315
 
108
316
  if rippleVisible {
109
- let maxRadius = pointerSize * 0.9
317
+ let maxRadius = pointerSize * 0.55
110
318
  let radius = 3 + maxRadius * rippleProgress
111
319
  let alpha = max(0, 1 - rippleProgress)
112
320
  ctx.saveGState()
@@ -121,52 +329,25 @@ private final class JianPointerView: NSView {
121
329
  ctx.restoreGState()
122
330
  }
123
331
 
124
- let path = Self.arrowPath(in: bounds)
125
-
126
- // Soft blue glow under the white blade (brand cue without neon spam).
127
- ctx.saveGState()
128
- ctx.setShadow(
129
- offset: CGSize(width: 0, height: 2),
130
- blur: 10,
131
- color: jianGlow.withAlphaComponent(0.55).cgColor
132
- )
133
- jianGlow.withAlphaComponent(0.35).setFill()
134
- path.fill()
135
- ctx.restoreGState()
136
-
137
- ctx.saveGState()
138
- ctx.setShadow(
139
- offset: CGSize(width: 0.5, height: 1.2),
140
- blur: 2.5,
141
- color: NSColor.black.withAlphaComponent(0.22).cgColor
142
- )
143
- let fillAlpha = 1 - fillPulse * 0.28
144
- pointerWhite.withAlphaComponent(fillAlpha).setFill()
145
- path.fill()
146
- ctx.restoreGState()
147
-
148
- jianInk.withAlphaComponent(0.85).setStroke()
149
- path.lineWidth = 1.15
150
- path.lineJoinStyle = .miter
151
- path.lineCapStyle = .butt
152
- path.miterLimit = 8
153
- path.stroke()
154
- }
155
-
156
- /// Sharp geometric pointer (anathema-white style): tip → shaft → barb.
157
- private static func arrowPath(in bounds: NSRect) -> NSBezierPath {
158
- let s = min(bounds.width, bounds.height)
159
- let path = NSBezierPath()
160
- // Coordinates in view space (flipped Y): tip near top-left hotspot.
161
- path.move(to: CGPoint(x: s * 0.06, y: s * 0.06))
162
- path.line(to: CGPoint(x: s * 0.06, y: s * 0.72))
163
- path.line(to: CGPoint(x: s * 0.28, y: s * 0.55))
164
- path.line(to: CGPoint(x: s * 0.42, y: s * 0.88))
165
- path.line(to: CGPoint(x: s * 0.55, y: s * 0.82))
166
- path.line(to: CGPoint(x: s * 0.36, y: s * 0.48))
167
- path.line(to: CGPoint(x: s * 0.62, y: s * 0.48))
168
- path.close()
169
- return path
332
+ // Bitmap blade (white + #2880F8 stroke + baked glow). Pulse alpha on click flash.
333
+ let alpha = 1 - fillPulse * 0.28
334
+ if let image = jianPointerImage {
335
+ image.draw(
336
+ in: bounds,
337
+ from: .zero,
338
+ operation: .sourceOver,
339
+ fraction: alpha,
340
+ respectFlipped: true,
341
+ hints: nil
342
+ )
343
+ } else {
344
+ // Last-resort fallback if decode failed — still a visible tip, not ink/cream geometry.
345
+ jianGlow.withAlphaComponent(0.9 * alpha).setFill()
346
+ let tip = NSBezierPath(
347
+ ovalIn: CGRect(x: hotspot.x - 3, y: hotspot.y - 3, width: 6, height: 6)
348
+ )
349
+ tip.fill()
350
+ }
170
351
  }
171
352
 
172
353
  func flashClick(duration: TimeInterval = 0.16) {
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jian-ai/remote-control",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "description": "Jian Remote Control worker — connect a computer to a Jian gateway over HTTPS",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  # Jian Remote Control — Windows computer-use helper
2
2
  # JSON lines on stdin → JSON lines on stdout (same cmds as macOS/Linux helpers).
3
- # Overlay: topmost transparent WinForms pointer (geometric white + blue glow).
3
+ # Overlay: topmost transparent WinForms pointer (white + #2880F8 stroke/glow; macOS uses bitmap).
4
4
  # Input: SendInput with save/restore so agent clicks do not strand the user cursor.
5
5
  # English-only errors.
6
6
 
@@ -123,7 +123,8 @@ function Ensure-Overlay {
123
123
  (New-Object System.Drawing.Point(13, 17)),
124
124
  (New-Object System.Drawing.Point(22, 17))
125
125
  )
126
- $glowBrush = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(140, 58, 122, 214))
126
+ # Parity with macOS ship sprite: white fill + #2880F8 stroke/glow (geometric stand-in).
127
+ $glowBrush = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(140, 40, 128, 248))
127
128
  $glowPts = @(
128
129
  (New-Object System.Drawing.Point(3, 4)),
129
130
  (New-Object System.Drawing.Point(3, 28)),
@@ -134,9 +135,9 @@ function Ensure-Overlay {
134
135
  (New-Object System.Drawing.Point(23, 19))
135
136
  )
136
137
  $g.FillPolygon($glowBrush, $glowPts)
137
- $fill = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(255, 250, 250, 248))
138
+ $fill = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(255, 255, 255, 255))
138
139
  $g.FillPolygon($fill, $pts)
139
- $pen = New-Object System.Drawing.Pen ([System.Drawing.Color]::FromArgb(220, 23, 23, 22), 1.1)
140
+ $pen = New-Object System.Drawing.Pen ([System.Drawing.Color]::FromArgb(255, 40, 128, 248), 2.4)
140
141
  $g.DrawPolygon($pen, $pts)
141
142
  $glowBrush.Dispose(); $fill.Dispose(); $pen.Dispose()
142
143
  })