@blueharford/scrypted-spatial-awareness 0.6.1 → 0.6.2

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/dist/plugin.zip CHANGED
Binary file
@@ -41533,6 +41533,19 @@ exports.EDITOR_HTML = `<!DOCTYPE html>
41533
41533
  <p>Topology Editor</p>
41534
41534
  </div>
41535
41535
  <div class="sidebar-content">
41536
+ <div class="section" style="background: #1a3a5c; margin: -10px -15px 10px -15px; padding: 15px;">
41537
+ <div class="section-title" style="margin-bottom: 10px;">
41538
+ <span>Floor Plan Scale</span>
41539
+ </div>
41540
+ <div style="display: flex; gap: 10px; align-items: center;">
41541
+ <input type="number" id="scale-input" value="5" min="1" max="50" style="width: 60px; padding: 6px; background: #0f3460; border: 1px solid #1a4a7a; border-radius: 4px; color: #fff;" onchange="updateScale(this.value)">
41542
+ <span style="font-size: 12px; color: #888;">pixels per foot</span>
41543
+ <button class="btn btn-small" onclick="openScaleHelper()" style="margin-left: auto;">Help</button>
41544
+ </div>
41545
+ <div style="font-size: 11px; color: #666; margin-top: 8px;">
41546
+ Tip: If your floor plan is 800px wide and represents 80ft, scale = 10 px/ft
41547
+ </div>
41548
+ </div>
41536
41549
  <div class="section">
41537
41550
  <div class="section-title">
41538
41551
  <span>Cameras</span>
@@ -41841,6 +41854,14 @@ exports.EDITOR_HTML = `<!DOCTYPE html>
41841
41854
  let currentDrawing = null;
41842
41855
  let blankCanvasMode = false;
41843
41856
 
41857
+ // Floor plan scale: pixels per foot (default assumes ~5 pixels per foot for a typical floor plan)
41858
+ // User can adjust this by setting the scale
41859
+ let floorPlanScale = 5; // pixels per foot
41860
+
41861
+ // Helper functions for scale conversion
41862
+ function feetToPixels(feet) { return feet * floorPlanScale; }
41863
+ function pixelsToFeet(pixels) { return pixels / floorPlanScale; }
41864
+
41844
41865
  // Zone drawing state
41845
41866
  let zoneDrawingMode = false;
41846
41867
  let currentZonePoints = [];
@@ -41896,6 +41917,12 @@ exports.EDITOR_HTML = `<!DOCTYPE html>
41896
41917
  if (response.ok) {
41897
41918
  topology = await response.json();
41898
41919
  if (!topology.drawings) topology.drawings = [];
41920
+ // Load floor plan scale if saved
41921
+ if (topology.floorPlanScale) {
41922
+ floorPlanScale = topology.floorPlanScale;
41923
+ const scaleInput = document.getElementById('scale-input');
41924
+ if (scaleInput) scaleInput.value = floorPlanScale;
41925
+ }
41899
41926
  // Load floor plan from separate storage (handles legacy imageData in topology too)
41900
41927
  if (topology.floorPlan?.imageData) {
41901
41928
  // Legacy: imageData was stored in topology
@@ -43065,6 +43092,8 @@ exports.EDITOR_HTML = `<!DOCTYPE html>
43065
43092
  function showCameraProperties(camera) {
43066
43093
  const panel = document.getElementById('properties-panel');
43067
43094
  const fov = camera.fov || { mode: 'simple', angle: 90, direction: 0, range: 80 };
43095
+ // Convert stored pixel range to feet for display
43096
+ const rangeInFeet = Math.round(pixelsToFeet(fov.range || 80));
43068
43097
  panel.innerHTML = '<h3>Camera Properties</h3>' +
43069
43098
  '<div class="form-group"><label>Name</label><input type="text" value="' + camera.name + '" onchange="updateCameraName(\\'' + camera.deviceId + '\\', this.value)"></div>' +
43070
43099
  '<div class="form-group"><label class="checkbox-group"><input type="checkbox" ' + (camera.isEntryPoint ? 'checked' : '') + ' onchange="updateCameraEntry(\\'' + camera.deviceId + '\\', this.checked)">Entry Point</label></div>' +
@@ -43072,7 +43101,8 @@ exports.EDITOR_HTML = `<!DOCTYPE html>
43072
43101
  '<h4 style="margin-top: 15px; margin-bottom: 10px; color: #888;">Field of View</h4>' +
43073
43102
  '<div class="form-group"><label>Direction (0=up, 90=right)</label><input type="number" value="' + Math.round(fov.direction || 0) + '" min="0" max="359" onchange="updateCameraFov(\\'' + camera.deviceId + '\\', \\'direction\\', this.value)"></div>' +
43074
43103
  '<div class="form-group"><label>FOV Angle (degrees)</label><input type="number" value="' + (fov.angle || 90) + '" min="30" max="180" onchange="updateCameraFov(\\'' + camera.deviceId + '\\', \\'angle\\', this.value)"></div>' +
43075
- '<div class="form-group"><label>Range (pixels)</label><input type="number" value="' + (fov.range || 80) + '" min="20" max="300" onchange="updateCameraFov(\\'' + camera.deviceId + '\\', \\'range\\', this.value)"></div>' +
43104
+ '<div class="form-group"><label>Range (feet)</label><input type="number" value="' + rangeInFeet + '" min="5" max="200" onchange="updateCameraFovRange(\\'' + camera.deviceId + '\\', this.value)"></div>' +
43105
+ '<div style="font-size: 11px; color: #666; margin-top: -10px; margin-bottom: 15px;">~' + (fov.range || 80) + ' pixels at current scale</div>' +
43076
43106
  '<div class="form-group"><button class="btn" style="width: 100%; background: #f44336;" onclick="deleteCamera(\\'' + camera.deviceId + '\\')">Delete Camera</button></div>';
43077
43107
  }
43078
43108
 
@@ -43091,6 +43121,36 @@ exports.EDITOR_HTML = `<!DOCTYPE html>
43091
43121
  camera.fov[field] = parseFloat(value);
43092
43122
  render();
43093
43123
  }
43124
+ function updateCameraFovRange(id, feetValue) {
43125
+ // Convert feet to pixels and store
43126
+ const camera = topology.cameras.find(c => c.deviceId === id);
43127
+ if (!camera) return;
43128
+ if (!camera.fov) camera.fov = { mode: 'simple', angle: 90, direction: 0, range: 80 };
43129
+ camera.fov.range = feetToPixels(parseFloat(feetValue));
43130
+ render();
43131
+ // Update the pixel display
43132
+ showCameraProperties(camera);
43133
+ }
43134
+ function updateScale(value) {
43135
+ floorPlanScale = parseFloat(value) || 5;
43136
+ // Store in topology for persistence
43137
+ topology.floorPlanScale = floorPlanScale;
43138
+ render();
43139
+ setStatus('Scale updated: ' + floorPlanScale + ' pixels per foot', 'success');
43140
+ }
43141
+ function openScaleHelper() {
43142
+ alert('How to determine your floor plan scale:\\n\\n' +
43143
+ '1. Measure a known distance on your floor plan in pixels\\n' +
43144
+ ' (e.g., measure a room that you know is 20 feet wide)\\n\\n' +
43145
+ '2. Divide the pixel width by the real width in feet\\n' +
43146
+ ' Example: 200 pixels / 20 feet = 10 pixels per foot\\n\\n' +
43147
+ '3. Enter that value in the scale field\\n\\n' +
43148
+ 'Common scales:\\n' +
43149
+ '- Small floor plan (fits on screen): 3-5 px/ft\\n' +
43150
+ '- Medium floor plan: 5-10 px/ft\\n' +
43151
+ '- Large/detailed floor plan: 10-20 px/ft\\n\\n' +
43152
+ 'Tip: Most outdoor cameras see 30-50 feet, indoor 15-30 feet');
43153
+ }
43094
43154
  function updateConnectionName(id, value) { const conn = topology.connections.find(c => c.id === id); if (conn) conn.name = value; updateUI(); }
43095
43155
  function updateTransitTime(id, field, value) { const conn = topology.connections.find(c => c.id === id); if (conn) conn.transitTime[field] = parseInt(value) * 1000; }
43096
43156
  function updateConnectionBidi(id, value) { const conn = topology.connections.find(c => c.id === id); if (conn) conn.bidirectional = value; render(); }