Compare commits

...

5 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
Smittix 8cd64ce3ca fix: PWA install prompt - add PNG icons and fix apple-touch-icon
Browsers require PNG icons (192x192, 512x512) in the manifest to show
the install prompt. SVG-only manifests are not sufficient. Also adds the
180x180 apple-touch-icon PNG for iOS home screen, bumps SW cache to v3,
and adds scope to the manifest.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 19:36:28 +00:00
11 changed files with 124 additions and 80 deletions
+17 -1
View File
@@ -2,13 +2,29 @@
All notable changes to iNTERCEPT will be documented in this file. 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 ## [2.22.0] - 2026-02-23
### Added ### Added
- **Waterfall Receiver Overhaul** - WebSocket-based I/Q streaming with server-side FFT, click-to-tune, zoom controls, and auto-scaling - **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 - **Voice Alerts** - Configurable text-to-speech event notifications across modes
- **Signal Fingerprinting** - RF device identification and pattern analysis mode - **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 - **SignalID** - Automatic signal classification via SigIDWiki API integration
- **PWA Support** - Installable web app with service worker caching and manifest - **PWA Support** - Installable web app with service worker caching and manifest
- **Real-time Signal Scope** - Live signal visualization for pager, sensor, and SSTV modes - **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 import sys
# Application version # Application version
VERSION = "2.22.0" VERSION = "2.22.2"
# Changelog - latest release notes (shown on welcome screen) # Changelog - latest release notes (shown on welcome screen)
CHANGELOG = [ 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", "date": "February 2026",
"highlights": [ "highlights": [
"Waterfall receiver overhaul: WebSocket I/Q streaming with server-side FFT, click-to-tune, and zoom controls", "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", "Voice alerts for configurable event notifications across modes",
"Signal fingerprinting mode for RF device identification and pattern analysis", "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", "SignalID integration via SigIDWiki API for automatic signal classification",
"PWA support: installable web app with service worker and manifest", "PWA support: installable web app with service worker and manifest",
"Mode stop responsiveness improvements with faster timeout handling", "Mode stop responsiveness improvements with faster timeout handling",
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

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"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<rect width="512" height="512" fill="#0b1118" rx="80"/> <!-- Background -->
<!-- Signal wave arcs radiating from center-left --> <rect width="100" height="100" fill="#0a0a0f"/>
<g fill="none" stroke="#4aa3ff" stroke-linecap="round">
<!-- Inner arc --> <!-- Signal brackets - left side -->
<path stroke-width="22" d="M 160 256 Q 192 210 192 256 Q 192 302 160 256" opacity="0.5"/> <path d="M15 30 Q5 50, 15 70" stroke="#00d4ff" stroke-width="4" fill="none" stroke-linecap="round" opacity="0.5"/>
<!-- Small arc --> <path d="M22 35 Q14 50, 22 65" stroke="#00d4ff" stroke-width="3.5" fill="none" stroke-linecap="round" opacity="0.7"/>
<path stroke-width="22" d="M 130 256 Q 180 185 180 256 Q 180 327 130 256" opacity="0.65"/> <path d="M29 40 Q23 50, 29 60" stroke="#00d4ff" stroke-width="3" fill="none" stroke-linecap="round"/>
<!-- Medium arc -->
<path stroke-width="24" d="M 100 256 Q 175 155 175 256 Q 175 357 100 256" opacity="0.8"/> <!-- Signal brackets - right side -->
<!-- Large arc --> <path d="M85 30 Q95 50, 85 70" stroke="#00d4ff" stroke-width="4" fill="none" stroke-linecap="round" opacity="0.5"/>
<path stroke-width="26" d="M 68 256 Q 170 120 170 256 Q 170 392 68 256" opacity="0.95"/> <path d="M78 35 Q86 50, 78 65" stroke="#00d4ff" stroke-width="3.5" fill="none" stroke-linecap="round" opacity="0.7"/>
</g> <path d="M71 40 Q77 50, 71 60" stroke="#00d4ff" stroke-width="3" fill="none" stroke-linecap="round"/>
<!-- Horizontal beam line -->
<line x1="190" y1="256" x2="420" y2="256" stroke="#4aa3ff" stroke-width="20" stroke-linecap="round"/> <!-- The 'i' letter -->
<!-- Signal dot at origin --> <circle cx="50" cy="22" r="7" fill="#00ff88"/>
<circle cx="190" cy="256" r="18" fill="#4aa3ff"/> <rect x="43" y="35" width="14" height="45" rx="2" fill="#00d4ff"/>
<!-- Target reticle at end --> <rect x="36" y="35" width="28" height="5" rx="1" fill="#00d4ff"/>
<circle cx="420" cy="256" r="28" fill="none" stroke="#4aa3ff" stroke-width="14"/> <rect x="36" y="75" width="28" height="5" rx="1" fill="#00d4ff"/>
<circle cx="420" cy="256" r="8" fill="#4aa3ff"/>
</svg> </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; if (!mapEl) return;
const globeReady = await ensureWebsdrGlobeLibrary(); 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)) { if (globeReady && initWebsdrGlobe(mapEl)) {
websdrMapType = 'globe'; websdrMapType = 'globe';
} else if (typeof L !== 'undefined' && await initWebsdrLeaflet(mapEl)) { } else if (typeof L !== 'undefined' && await initWebsdrLeaflet(mapEl)) {
+11
View File
@@ -3,10 +3,21 @@
"short_name": "INTERCEPT", "short_name": "INTERCEPT",
"description": "Unified SIGINT platform for software-defined radio analysis", "description": "Unified SIGINT platform for software-defined radio analysis",
"start_url": "/", "start_url": "/",
"scope": "/",
"display": "standalone", "display": "standalone",
"background_color": "#0b1118", "background_color": "#0b1118",
"theme_color": "#0b1118", "theme_color": "#0b1118",
"icons": [ "icons": [
{
"src": "/static/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/static/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{ {
"src": "/static/icons/icon.svg", "src": "/static/icons/icon.svg",
"sizes": "any", "sizes": "any",
+1 -1
View File
@@ -1,5 +1,5 @@
/* INTERCEPT Service Worker — cache-first static, network-only for API/SSE/WS */ /* INTERCEPT Service Worker — cache-first static, network-only for API/SSE/WS */
const CACHE_NAME = 'intercept-v2'; const CACHE_NAME = 'intercept-v3';
const NETWORK_ONLY_PREFIXES = [ const NETWORK_ONLY_PREFIXES = [
'/stream', '/ws/', '/api/', '/gps/', '/wifi/', '/bluetooth/', '/stream', '/ws/', '/api/', '/gps/', '/wifi/', '/bluetooth/',
+3 -3
View File
@@ -10,7 +10,7 @@
<meta name="theme-color" content="#0b1118"> <meta name="theme-color" content="#0b1118">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="apple-touch-icon" href="/static/icons/icon.svg"> <link rel="apple-touch-icon" href="/static/icons/apple-touch-icon.png">
<!-- Disclaimer gate - must accept before seeing welcome page --> <!-- Disclaimer gate - must accept before seeing welcome page -->
<script> <script>
// Check BEFORE page renders - if disclaimer not accepted, hide welcome page // Check BEFORE page renders - if disclaimer not accepted, hide welcome page
@@ -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/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/toast.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/components/ux-platform.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> <script>
window.INTERCEPT_MODE_STYLE_MAP = { window.INTERCEPT_MODE_STYLE_MAP = {
aprs: "{{ url_for('static', filename='css/modes/aprs.css') }}", aprs: "{{ url_for('static', filename='css/modes/aprs.css') }}",
@@ -78,8 +79,7 @@
gps: "{{ url_for('static', filename='css/modes/gps.css') }}", gps: "{{ url_for('static', filename='css/modes/gps.css') }}",
subghz: "{{ url_for('static', filename='css/modes/subghz.css') }}?v={{ version }}&r=subghz_layout9", 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", 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') }}", spaceweather: "{{ url_for('static', filename='css/modes/space-weather.css') }}"
waterfall: "{{ url_for('static', filename='css/modes/waterfall.css') }}?v={{ version }}&r=wfdeck19"
}; };
window.INTERCEPT_MODE_STYLE_LOADED = {}; window.INTERCEPT_MODE_STYLE_LOADED = {};
window.ensureModeStyles = function(mode) { window.ensureModeStyles = function(mode) {