Compare commits

..

4 Commits

Author SHA1 Message Date
Smittix 4e67b77714 fix: first-load rendering for Waterfall CSS and WebSDR globe
- Waterfall: load waterfall.css eagerly in <head> instead of lazily on
  mode switch; the lazy inject raced with the panel becoming visible,
  leaving unstyled HTML for up to 20 s on cold cache
- WebSDR: await a requestAnimationFrame before calling Globe()(mapEl) so
  the browser has committed the display:flex layout and clientWidth/
  clientHeight are non-zero; previously the globe WebGL renderer was
  created at 0×0 (especially on warm-cache refreshes) and could not
  recover via the deferred resize calls
- Bump version to 2.22.2

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 20:25:05 +00:00
Smittix b1993847b5 docs: remove RF Heatmap references — feature was not shipped
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 19:40:15 +00:00
Smittix cde79f4619 fix: use official favicon.svg logo for all PWA and app icons
Regenerates icon-192.png, icon-512.png, apple-touch-icon.png, and
favicon-32.png from the official iNTERCEPT logo (favicon.svg) instead
of the placeholder icon.svg. Also replaces icon.svg with the official
logo so the SVG manifest entry is consistent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 19:37:44 +00:00
Smittix cc271819ad chore: bump version to 2.22.1 and update changelog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 19:36:55 +00:00
9 changed files with 59 additions and 26 deletions
+17 -1
View File
@@ -2,13 +2,29 @@
All notable changes to iNTERCEPT will be documented in this file.
## [2.22.2] - 2026-02-23
### Fixed
- Waterfall control panel rendered as unstyled text for up to 20 seconds on first visit — CSS is now loaded eagerly with the rest of the page assets
- WebSDR globe failed to render on first page load — initialization now waits for a layout frame before mounting the WebGL renderer, ensuring the container has non-zero dimensions
---
## [2.22.1] - 2026-02-23
### Fixed
- PWA install prompt not appearing — manifest now includes required PNG icons (192×192, 512×512)
- Apple touch icon updated to PNG for iOS Safari compatibility
- Service worker cache bumped to bust stale cached assets
---
## [2.22.0] - 2026-02-23
### Added
- **Waterfall Receiver Overhaul** - WebSocket-based I/Q streaming with server-side FFT, click-to-tune, zoom controls, and auto-scaling
- **Voice Alerts** - Configurable text-to-speech event notifications across modes
- **Signal Fingerprinting** - RF device identification and pattern analysis mode
- **RF Heatmap** - Geographic signal density visualization with Leaflet heatmap overlay
- **SignalID** - Automatic signal classification via SigIDWiki API integration
- **PWA Support** - Installable web app with service worker caching and manifest
- **Real-time Signal Scope** - Live signal visualization for pager, sensor, and SSTV modes
+10 -3
View File
@@ -7,18 +7,25 @@ import os
import sys
# Application version
VERSION = "2.22.0"
VERSION = "2.22.2"
# Changelog - latest release notes (shown on welcome screen)
CHANGELOG = [
{
"version": "2.22.0",
"version": "2.22.2",
"date": "February 2026",
"highlights": [
"Waterfall control panel no longer shows as unstyled text on first visit",
"WebSDR globe renders correctly on first page load without requiring a refresh",
]
},
{
"version": "2.22.1",
"date": "February 2026",
"highlights": [
"Waterfall receiver overhaul: WebSocket I/Q streaming with server-side FFT, click-to-tune, and zoom controls",
"Voice alerts for configurable event notifications across modes",
"Signal fingerprinting mode for RF device identification and pattern analysis",
"RF Heatmap for geographic signal density visualization",
"SignalID integration via SigIDWiki API for automatic signal classification",
"PWA support: installable web app with service worker and manifest",
"Mode stop responsiveness improvements with faster timeout handling",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 750 B

After

Width:  |  Height:  |  Size: 919 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 16 KiB

+19 -20
View File
@@ -1,21 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<rect width="512" height="512" fill="#0b1118" rx="80"/>
<!-- Signal wave arcs radiating from center-left -->
<g fill="none" stroke="#4aa3ff" stroke-linecap="round">
<!-- Inner arc -->
<path stroke-width="22" d="M 160 256 Q 192 210 192 256 Q 192 302 160 256" opacity="0.5"/>
<!-- Small arc -->
<path stroke-width="22" d="M 130 256 Q 180 185 180 256 Q 180 327 130 256" opacity="0.65"/>
<!-- Medium arc -->
<path stroke-width="24" d="M 100 256 Q 175 155 175 256 Q 175 357 100 256" opacity="0.8"/>
<!-- Large arc -->
<path stroke-width="26" d="M 68 256 Q 170 120 170 256 Q 170 392 68 256" opacity="0.95"/>
</g>
<!-- Horizontal beam line -->
<line x1="190" y1="256" x2="420" y2="256" stroke="#4aa3ff" stroke-width="20" stroke-linecap="round"/>
<!-- Signal dot at origin -->
<circle cx="190" cy="256" r="18" fill="#4aa3ff"/>
<!-- Target reticle at end -->
<circle cx="420" cy="256" r="28" fill="none" stroke="#4aa3ff" stroke-width="14"/>
<circle cx="420" cy="256" r="8" fill="#4aa3ff"/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<!-- Background -->
<rect width="100" height="100" fill="#0a0a0f"/>
<!-- Signal brackets - left side -->
<path d="M15 30 Q5 50, 15 70" stroke="#00d4ff" stroke-width="4" fill="none" stroke-linecap="round" opacity="0.5"/>
<path d="M22 35 Q14 50, 22 65" stroke="#00d4ff" stroke-width="3.5" fill="none" stroke-linecap="round" opacity="0.7"/>
<path d="M29 40 Q23 50, 29 60" stroke="#00d4ff" stroke-width="3" fill="none" stroke-linecap="round"/>
<!-- Signal brackets - right side -->
<path d="M85 30 Q95 50, 85 70" stroke="#00d4ff" stroke-width="4" fill="none" stroke-linecap="round" opacity="0.5"/>
<path d="M78 35 Q86 50, 78 65" stroke="#00d4ff" stroke-width="3.5" fill="none" stroke-linecap="round" opacity="0.7"/>
<path d="M71 40 Q77 50, 71 60" stroke="#00d4ff" stroke-width="3" fill="none" stroke-linecap="round"/>
<!-- The 'i' letter -->
<circle cx="50" cy="22" r="7" fill="#00ff88"/>
<rect x="43" y="35" width="14" height="45" rx="2" fill="#00d4ff"/>
<rect x="36" y="35" width="28" height="5" rx="1" fill="#00d4ff"/>
<rect x="36" y="75" width="28" height="5" rx="1" fill="#00d4ff"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

+11
View File
@@ -51,6 +51,17 @@ async function initWebSDR() {
if (!mapEl) return;
const globeReady = await ensureWebsdrGlobeLibrary();
// Wait for a paint frame so the browser computes layout after the
// display:flex change in switchMode. Without this, Globe()(mapEl) can
// run before clientWidth/clientHeight are non-zero (especially when
// scripts are served from cache and resolve before the first layout pass).
await new Promise(resolve => requestAnimationFrame(resolve));
// If the mode was switched away while scripts were loading, abort so
// websdrInitialized stays false and we retry cleanly next time.
if (!mapEl.clientWidth || !mapEl.clientHeight) return;
if (globeReady && initWebsdrGlobe(mapEl)) {
websdrMapType = 'globe';
} else if (typeof L !== 'undefined' && await initWebsdrLeaflet(mapEl)) {
+2 -2
View File
@@ -66,6 +66,7 @@
<link rel="stylesheet" href="{{ url_for('static', filename='css/components/function-strip.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/components/toast.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/components/ux-platform.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/modes/waterfall.css') }}?v={{ version }}&r=wfdeck19">
<script>
window.INTERCEPT_MODE_STYLE_MAP = {
aprs: "{{ url_for('static', filename='css/modes/aprs.css') }}",
@@ -78,8 +79,7 @@
gps: "{{ url_for('static', filename='css/modes/gps.css') }}",
subghz: "{{ url_for('static', filename='css/modes/subghz.css') }}?v={{ version }}&r=subghz_layout9",
bt_locate: "{{ url_for('static', filename='css/modes/bt_locate.css') }}?v={{ version }}&r=btlocate4",
spaceweather: "{{ url_for('static', filename='css/modes/space-weather.css') }}",
waterfall: "{{ url_for('static', filename='css/modes/waterfall.css') }}?v={{ version }}&r=wfdeck19"
spaceweather: "{{ url_for('static', filename='css/modes/space-weather.css') }}"
};
window.INTERCEPT_MODE_STYLE_LOADED = {};
window.ensureModeStyles = function(mode) {