node-mac-recorder 1.14.1 → 1.15.0

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.
package/CLAUDE.md CHANGED
@@ -73,10 +73,22 @@ The package handles complex multi-display coordinate transformations:
73
73
  - `checkPermissions()` - Verify macOS recording permissions
74
74
 
75
75
  ### Cursor Tracking
76
- - `startCursorCapture(filepath)` - Begin real-time cursor tracking to JSON
76
+ - `startCursorCapture(filepath, options)` - Begin real-time cursor tracking to JSON
77
+ - `options.windowInfo` - Window information for window-relative coordinates
78
+ - `options.windowRelative` - Set to true for window-relative coordinates
77
79
  - `stopCursorCapture()` - Stop tracking and close output file
78
80
  - `getCursorPosition()` - Get current cursor position and state
79
81
 
82
+ ### Events
83
+ The MacRecorder class emits the following events:
84
+ - `recordingStarted` - Emitted immediately when recording starts with recording details
85
+ - `started` - Emitted when recording is confirmed started (legacy event)
86
+ - `stopped` - Emitted when recording stops
87
+ - `completed` - Emitted when recording file is finalized
88
+ - `timeUpdate` - Emitted every second with elapsed time
89
+ - `cursorCaptureStarted` - Emitted when cursor capture begins
90
+ - `cursorCaptureStopped` - Emitted when cursor capture ends
91
+
80
92
  ### Thumbnails
81
93
  - `getWindowThumbnail(windowId, options)` - Capture window preview image
82
94
  - `getDisplayThumbnail(displayId, options)` - Capture display preview image
@@ -90,9 +102,14 @@ The package handles complex multi-display coordinate transformations:
90
102
 
91
103
  ### Common Development Patterns
92
104
  - All recording operations are Promise-based
93
- - Event emission for recording state changes (`started`, `stopped`, `completed`)
105
+ - Event emission for recording state changes (`recordingStarted`, `started`, `stopped`, `completed`)
106
+ - `recordingStarted` event provides immediate notification with recording details
94
107
  - Automatic permission checking before operations
95
108
  - Error handling with descriptive messages for permission issues
109
+ - Cursor tracking supports multiple coordinate systems:
110
+ - Global coordinates (default)
111
+ - Display-relative coordinates (when recording)
112
+ - Window-relative coordinates (with windowInfo parameter)
96
113
 
97
114
  ### Platform Requirements
98
115
  - macOS only (enforced in install.js)
@@ -102,6 +119,13 @@ The package handles complex multi-display coordinate transformations:
102
119
  ### File Outputs
103
120
  - Video recordings: `.mov` format (H.264/AAC)
104
121
  - Cursor data: JSON format with timestamped events
122
+ - `x`, `y`: Cursor coordinates (coordinate system dependent)
123
+ - `timestamp`: Time from capture start (ms)
124
+ - `unixTimeMs`: Unix timestamp
125
+ - `cursorType`: macOS cursor type
126
+ - `type`: Event type (move, click, etc.)
127
+ - `coordinateSystem`: "global", "display-relative", or "window-relative"
128
+ - `windowInfo`: Window metadata (when using window-relative coordinates)
105
129
  - Thumbnails: Base64-encoded PNG data URIs
106
130
 
107
131
  ## Troubleshooting
package/index.js CHANGED
@@ -302,6 +302,13 @@ class MacRecorder extends EventEmitter {
302
302
  this.emit("timeUpdate", elapsed);
303
303
  }, 1000);
304
304
 
305
+ // Kayıt tam başladığı anda event emit et
306
+ this.emit("recordingStarted", {
307
+ outputPath: this.outputPath,
308
+ timestamp: this.recordingStartTime,
309
+ options: this.options
310
+ });
311
+
305
312
  this.emit("started", this.outputPath);
306
313
  resolve(this.outputPath);
307
314
  } else {
@@ -506,9 +513,12 @@ class MacRecorder extends EventEmitter {
506
513
  /**
507
514
  * Cursor capture başlatır - otomatik olarak dosyaya yazmaya başlar
508
515
  * Recording başlatılmışsa otomatik olarak display-relative koordinatlar kullanır
509
- * @param {string} filepath - Cursor data JSON dosya yolu
516
+ * @param {string|number} intervalOrFilepath - Cursor data JSON dosya yolu veya interval
517
+ * @param {Object} options - Cursor capture seçenekleri
518
+ * @param {Object} options.windowInfo - Pencere bilgileri (window-relative koordinatlar için)
519
+ * @param {boolean} options.windowRelative - Koordinatları pencereye göre relative yap
510
520
  */
511
- async startCursorCapture(intervalOrFilepath = 100) {
521
+ async startCursorCapture(intervalOrFilepath = 100, options = {}) {
512
522
  let filepath;
513
523
  let interval = 20; // Default 50 FPS
514
524
 
@@ -528,8 +538,20 @@ class MacRecorder extends EventEmitter {
528
538
  throw new Error("Cursor capture is already running");
529
539
  }
530
540
 
531
- // Recording başlatılmışsa o display'i kullan, yoksa main display kullan
532
- if (this.recordingDisplayInfo) {
541
+ // Koordinat sistemi belirle: window-relative, display-relative veya global
542
+ if (options.windowRelative && options.windowInfo) {
543
+ // Window-relative koordinatlar için pencere bilgilerini kullan
544
+ this.cursorDisplayInfo = {
545
+ displayId: options.windowInfo.displayId || null,
546
+ x: options.windowInfo.x || 0,
547
+ y: options.windowInfo.y || 0,
548
+ width: options.windowInfo.width,
549
+ height: options.windowInfo.height,
550
+ windowRelative: true,
551
+ windowInfo: options.windowInfo
552
+ };
553
+ } else if (this.recordingDisplayInfo) {
554
+ // Recording başlatılmışsa o display'i kullan
533
555
  this.cursorDisplayInfo = this.recordingDisplayInfo;
534
556
  } else {
535
557
  // Main display bilgisini al (her zaman relative koordinatlar için)
@@ -568,23 +590,42 @@ class MacRecorder extends EventEmitter {
568
590
  const position = nativeBinding.getCursorPosition();
569
591
  const timestamp = Date.now() - this.cursorCaptureStartTime;
570
592
 
571
- // Global koordinatları display-relative'e çevir
593
+ // Global koordinatları relative koordinatlara çevir
572
594
  let x = position.x;
573
595
  let y = position.y;
596
+ let coordinateSystem = "global";
574
597
 
575
598
  if (this.cursorDisplayInfo) {
576
- // Display offset'lerini çıkar
599
+ // Offset'leri çıkar (display veya window)
577
600
  x = position.x - this.cursorDisplayInfo.x;
578
601
  y = position.y - this.cursorDisplayInfo.y;
579
602
 
580
- // Display bounds kontrolü - cursor display dışındaysa kaydetme
581
- if (
582
- x < 0 ||
583
- y < 0 ||
584
- x >= this.cursorDisplayInfo.width ||
585
- y >= this.cursorDisplayInfo.height
586
- ) {
587
- return; // Bu frame'i skip et
603
+ if (this.cursorDisplayInfo.windowRelative) {
604
+ // Window-relative koordinatlar
605
+ coordinateSystem = "window-relative";
606
+
607
+ // Window bounds kontrolü - cursor window dışındaysa kaydetme
608
+ if (
609
+ x < 0 ||
610
+ y < 0 ||
611
+ x >= this.cursorDisplayInfo.width ||
612
+ y >= this.cursorDisplayInfo.height
613
+ ) {
614
+ return; // Bu frame'i skip et - cursor pencere dışında
615
+ }
616
+ } else {
617
+ // Display-relative koordinatlar
618
+ coordinateSystem = "display-relative";
619
+
620
+ // Display bounds kontrolü
621
+ if (
622
+ x < 0 ||
623
+ y < 0 ||
624
+ x >= this.cursorDisplayInfo.width ||
625
+ y >= this.cursorDisplayInfo.height
626
+ ) {
627
+ return; // Bu frame'i skip et - cursor display dışında
628
+ }
588
629
  }
589
630
  }
590
631
 
@@ -595,6 +636,14 @@ class MacRecorder extends EventEmitter {
595
636
  unixTimeMs: Date.now(),
596
637
  cursorType: position.cursorType,
597
638
  type: position.eventType || "move",
639
+ coordinateSystem: coordinateSystem,
640
+ ...(this.cursorDisplayInfo?.windowRelative && {
641
+ windowInfo: {
642
+ width: this.cursorDisplayInfo.width,
643
+ height: this.cursorDisplayInfo.height,
644
+ originalWindow: this.cursorDisplayInfo.windowInfo
645
+ }
646
+ })
598
647
  };
599
648
 
600
649
  // Sadece eventType değiştiğinde veya pozisyon değiştiğinde kaydet
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "1.14.1",
3
+ "version": "1.15.0",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
package/overlay-test.js DELETED
@@ -1,84 +0,0 @@
1
- const MacRecorder = require('./index');
2
-
3
- async function testOverlayImprovements() {
4
- console.log('🎯 Testing Overlay Improvements\n');
5
-
6
- const recorder = new MacRecorder();
7
- const WindowSelector = MacRecorder.WindowSelector;
8
- const selector = new WindowSelector();
9
-
10
- try {
11
- console.log('1️⃣ Testing Window Selection with custom buttons...');
12
- console.log(' - Custom "Start Record" and "Cancel" buttons should appear');
13
- console.log(' - ESC key should cancel selection');
14
- console.log(' - Cancel button should cancel selection');
15
- console.log(' - Starting window selection...\n');
16
-
17
- // Start window selection (non-blocking)
18
- await selector.startSelection();
19
-
20
- console.log('✅ Window selection started. Move mouse over windows to see overlay.');
21
- console.log(' - Press ESC to cancel');
22
- console.log(' - Click Cancel button to cancel');
23
- console.log(' - Click Start Record to select window\n');
24
-
25
- // Wait for selection or timeout
26
- const startTime = Date.now();
27
- const timeout = 30000; // 30 seconds
28
-
29
- while (selector.getStatus().isSelecting && (Date.now() - startTime) < timeout) {
30
- await new Promise(resolve => setTimeout(resolve, 100));
31
- }
32
-
33
- const selectedWindow = selector.getSelectedWindow();
34
-
35
- if (selectedWindow) {
36
- console.log('🎬 Window selected:', selectedWindow.appName, '-', selectedWindow.title);
37
- console.log(' Size:', selectedWindow.width + 'x' + selectedWindow.height);
38
- console.log(' Position: (' + selectedWindow.x + ', ' + selectedWindow.y + ')');
39
-
40
- console.log('\n2️⃣ Testing Recording Preview Overlay...');
41
- console.log(' - Should show darkened overlay with window area transparent');
42
-
43
- await selector.showRecordingPreview(selectedWindow);
44
- console.log('✅ Recording preview shown. Check if window area is highlighted.');
45
-
46
- // Wait 3 seconds
47
- await new Promise(resolve => setTimeout(resolve, 3000));
48
-
49
- await selector.hideRecordingPreview();
50
- console.log('✅ Recording preview hidden.');
51
-
52
- } else {
53
- console.log('🚫 No window selected (cancelled or timeout)');
54
- }
55
-
56
- console.log('\n3️⃣ Testing Screen Selection with custom buttons...');
57
- console.log(' - Custom "Start Record" and "Cancel" buttons should appear on each screen');
58
- console.log(' - ESC key should cancel selection');
59
- console.log(' - Cancel button should cancel selection');
60
-
61
- const selectedScreen = await selector.selectScreen().catch(err => {
62
- console.log('🚫 Screen selection cancelled:', err.message);
63
- return null;
64
- });
65
-
66
- if (selectedScreen) {
67
- console.log('🖥️ Screen selected:', selectedScreen.name);
68
- console.log(' Resolution:', selectedScreen.resolution);
69
- console.log(' Position: (' + selectedScreen.x + ', ' + selectedScreen.y + ')');
70
- } else {
71
- console.log('🚫 No screen selected (cancelled or timeout)');
72
- }
73
-
74
- console.log('\n🎉 Overlay improvements test completed!');
75
-
76
- } catch (error) {
77
- console.error('❌ Test failed:', error.message);
78
- } finally {
79
- await selector.cleanup();
80
- }
81
- }
82
-
83
- // Run test
84
- testOverlayImprovements().catch(console.error);