Commit Graph

478 Commits

Author SHA1 Message Date
sjg 806a66b8c6 [fix](trx-frontend-http): fix about tab data and sub-tab navigation broken by deferred templates
About-tab element refs were cached at script load time but the elements
live inside a <template> that hasn't been cloned yet, so all refs were
null. Convert to lazy resolution via _resolveAboutEls() called on first
about-tab render. Also extract _wireSubTabBar() so sub-tab click
listeners are attached after template cloning (the about Client sub-tab
was unreachable). Decoder status elements use the same lazy pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-04-04 15:04:09 +02:00
sjg bed49ce13b [fix](trx-frontend-http): fix map and statistics tabs requiring refresh to show data
Move template cloning into navigateToTab() so deferred <template>
content is materialized before any tab-specific initialization runs.
Previously the document-level template cloner fired after navigateToTab
due to event propagation order, causing initAprsMap() and
scheduleStatsRender() to target elements that did not yet exist. Also
defer statistics control wiring until the first render so event
listeners are attached after the template is cloned.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-04-04 13:48:08 +02:00
sjg 9f29876afc [fix](trx-frontend-http): show map loading message, sync active rig marker, align recorder actions with bookmarks
- Display "Loading map…" placeholder on first map tab click while
  map-core.js is still loading; hide it once the module initializes.
- Sync receiver marker highlight when switching rigs so the map
  reflects the currently active rig immediately.
- Add "Actions" header to recorder files table and match button
  sizing to bookmarks table style.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-04-04 13:04:42 +02:00
sjg 02ed6d918c [fix](trx-frontend-http): redirect to login when navigating to protected tabs unauthenticated, right-align recorder table buttons
Show the auth gate instead of silently blocking navigation to non-main
tabs when not logged in. Also fix recorder file table layout so the file
column takes full width and action buttons are right-aligned.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-04-04 12:54:11 +02:00
sjg e1554d95c0 [fix](trx-frontend-http): eliminate bookmark chip wobble by using compositor-friendly transforms
Batch offsetWidth reads before writes to prevent layout thrashing, and
position chips via transform instead of left to avoid sub-pixel jitter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-04-04 12:36:08 +02:00
sjg 13aceb35c6 [fix](trx-frontend-http): stop reloading shared decode history on rig switch
The decode SSE stream and history endpoint are unfiltered and carry data
for all rigs. Reconnecting them on rig switch needlessly tore down the
entire decode state and re-fetched identical data. Also removed the
FT8/FT4/FT2/WSPR history table clearing since that data is shared.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-04-04 12:22:35 +02:00
sjg 79068e55af [fix](trx-frontend-http): buffer decode messages until map-data plugins are ready
Eagerly load map-data plugins (AIS, APRS, VDES, HF-APRS) on startup and
buffer any decode history or live SSE messages that arrive before plugin
handlers register. Each plugin drains its pending buffer on init.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-04-04 12:08:18 +02:00
sjg e467ba0537 [fix](trx-frontend-http): fix WEFAX toggle button and bookmark decoder wiring
Per-entry caching in _ensureDecoderToggles prevents stale guard from
blocking re-scan. Direct syncWefaxToggle path ensures dataset.enabled
stays current for bookmark prefill.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-04-04 07:54:26 +02:00
Claude daa31fb6e5 [feat](trx-wefax): implement WEFAX decoder with full server and frontend integration
Pure Rust WEFAX (Weather Facsimile) decoder supporting 60/90/120/240 LPM,
IOC 288 and 576, with automatic APT tone detection and phase alignment.

Core DSP pipeline:
- Polyphase rational resampler (48k→11025 Hz)
- FM discriminator (Hilbert FIR + instantaneous frequency)
- Goertzel tone detector (300/450/675 Hz APT tones)
- Phase alignment via cross-correlation on phasing signal
- Line slicer with linear interpolation pixel clock recovery
- Image assembler with PNG encoding

State machine: Idle→StartDetected→Phasing→Receiving→Stopping

Server integration:
- WefaxMessage/WefaxProgress in trx-core DecodedMessage
- DecoderConfig, DecoderResetSeqs, RigCommand wefax variants
- DECODER_REGISTRY entry in trx-protocol
- DecoderHistories/DecoderLoggers wefax support
- run_wefax_decoder() async task in trx-server audio.rs
- History persistence in pickledb store

Frontend integration:
- wefax.js plugin with live canvas rendering and gallery
- HTML sub-tab with canvas, gallery, toggle/clear controls
- SSE dispatch for wefax/wefax_progress events
- Decode history worker and restore support
- Toggle/clear API endpoints

19 unit tests covering resampler, FM discriminator, tone detection,
phasing, line slicing, image encoding, and decoder state machine.

https://claude.ai/code/session_019eyxgx3LuhcFZ7T5tr2Trm
Signed-off-by: Claude <noreply@anthropic.com>
2026-04-03 06:50:42 +02:00
sjg dd8b86b38f [feat](trx-frontend-http): hide decoder tabs not present in server registry
After fetching /decoders, hide sub-tab buttons, panels, overview
descriptions, about-status rows, and settings clear-history buttons
for decoders the server doesn't advertise. This makes feature-gated
decoders like FT2 fully invisible in the UI when disabled.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-04-01 22:20:36 +02:00
sjg 6502d59e54 [feat](trx-frontend-http): use monospace font for signal strength units
Wrap unit labels (dBm, dBf, dBFS, S, dB) in a .sig-unit span styled
with the system monospace stack, keeping numeric values in DSEG14.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-04-01 19:42:32 +02:00
sjg 9ab3db287a [fix](trx-frontend-http): expose missing functions on window.trx namespace
Add markDecodeMapSyncPending, decodeHistoryMapRenderingDeferred,
decodeHistoryReplayActive, decodeMapSyncPending, updateDocumentTitle,
activeChannelRds, _activeTab, and locationSubtitle to window.trx so
map-core.js can access them via the T alias.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-04-01 18:52:31 +02:00
sjg cb78070c59 [fix](trx-frontend-http): fix map not loading on direct /map navigation
navigateToTab now calls loadPluginsForTab to ensure map-core.js is
injected on initial page load from /map URL. map-core.js auto-inits the
map if the map tab is already visible when the module loads.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-04-01 18:47:09 +02:00
Claude de3b9f0bbb [fix](trx-frontend-http): move escapeMapHtml to global scope in app.js
escapeMapHtml was defined inside the map-core.js IIFE, making it
inaccessible to app.js and plugin files (aprs, ais, vdes, cw, hf-aprs)
that call it from global scope, causing ReferenceError at runtime.

Move the function definition to app.js (global scope), export it via
window.trx, and destructure it in map-core.js like other shared utils.

https://claude.ai/code/session_01RhL8cCcszaguKqoWn5XUxL
Signed-off-by: Claude <noreply@anthropic.com>
2026-04-01 12:59:09 +02:00
Claude 25c59405b5 [feat](trx-frontend-http): split app.js into ES modules with lazy loading
Extract map-core.js (3,483 lines) and screenshot.js (261 lines) from
the monolithic app.js, reducing it by ~30% (11,967 → 8,427 lines).

Modules communicate via a window.trx shared namespace with getter/setter-
backed state proxying. Map and statistics code lazy-loads on first tab
activation; screenshot code lazy-loads on first "S" keypress. All cross-
module calls use optional chaining for safe access before modules load.

Adds Rust infrastructure (include_str, gz_cache, Actix routes) for
serving the new JS assets.

https://claude.ai/code/session_01HgW8UpscRRA3CgSLqQDzdp
Signed-off-by: Claude <noreply@anthropic.com>
2026-04-01 12:43:07 +02:00
Claude c9167177e0 [fix](trx-frontend-http): fix rig initialization freeze caused by auth-badge inside template
The auth-badge element was wrapped inside <template id="tmpl-about">,
making it invisible to document.getElementById() at page load.
updateAuthUI() accessed badge.style without a null check, throwing a
TypeError that halted app initialization before connect() was called.

Move auth-badge outside the template so it is always in the live DOM,
and add defensive null guards on badge/badgeRole access.

https://claude.ai/code/session_01Km7uxYUzehpYBdYqncnt4n
Signed-off-by: Claude <noreply@anthropic.com>
2026-04-01 11:02:54 +02:00
Claude 941a37494b [feat](trx-frontend-http): implement frontend styling & performance improvements
CSS: reduce backdrop-filter to modals only, add contain/content-visibility
for inactive tabs, optimize transitions to background-color, pre-compute
color-mix results, add container queries, split themes to lazy-loaded file.

JS: cache DOM refs in render path, add field-level diffing for SSE updates,
replace innerHTML with replaceChildren() in hot paths, add WebGL colour
cache invalidation on theme switch.

HTML: add defer to scripts, lazy-load plugin scripts on tab activation,
SVG sprite sheet for tab icons, template elements for deferred tab content,
improve aria-live/keyboard nav/colour contrast accessibility.

Server: upgrade Cache-Control to immutable, add Brotli compression alongside
gzip with Accept-Encoding negotiation.

Implements all items from docs/frontend_improvements.md except app.js ES
module split (P1, requires major refactor) and Web Worker migration (P3).

https://claude.ai/code/session_015rQNMGvusj5jY66MPUgYqt
Signed-off-by: Claude <noreply@anthropic.com>
2026-04-01 10:36:12 +02:00
Claude 1fe0b75e20 [fix](trx-rs): fix LRPT pass detection status never updating during active decoding
The #sat-status element was stuck on "Waiting for satellite pass" because:

1. The client audio handler (audio_client.rs) did not include AUDIO_MSG_LRPT_IMAGE
   in its message type match, so LRPT image messages from the server were silently
   dropped and never reached the frontend.

2. No progress was reported during active LRPT decoding — the only status update
   happened when a complete image was finalized, which could take the entire pass.

3. The sat-status text was never updated when the decoder was enabled/disabled,
   leaving it permanently at the HTML default text.

Changes:
- Add DecodedMessage::LrptProgress variant for live MCU progress reporting
- Send LRPT progress updates from the decoder task when new MCUs are decoded
- Add AUDIO_MSG_LRPT_IMAGE and AUDIO_MSG_LRPT_PROGRESS to client audio handler
- Update sat-status text when decoder state changes (enabled/disabled)
- Handle lrpt_progress messages in the frontend to show "Receiving — N MCU rows"

https://claude.ai/code/session_017knbD7dr6hJGAWR6pModL7
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-31 16:21:12 +02:00
sjg 10f25349e2 [feat](trx-frontend-http): add recorder file management and pagination
Add download/remove buttons per file, filename filter, sort dropdown, and paginated file list. Restore header REC toggle button. Add GET /api/recorder/download/{filename} and DELETE /api/recorder/files/{filename} endpoints with path traversal protection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-31 02:52:34 +02:00
sjg bccb66f250 [feat](trx-frontend-http): replace header REC button with Recorder tab page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-31 02:32:16 +02:00
sjg f2048c583c [feat](trx-rs): add client-side Opus audio recorder
Record Opus audio streams to OGG files on the client. Includes manual start/stop via HTTP API, scheduler-driven auto-recording per schedule entry, and a header REC button in the web UI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-30 23:37:09 +02:00
sjg 2296a53916 [feat](trx-frontend-http): add S-meter unit to signal strength selector
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-30 22:13:40 +02:00
sjg 691f0727b2 [feat](trx-frontend-http): display S-meter in standard S-unit steps
Show S0–S9 as whole units and S9+xdB in 10dB steps instead of fractional S-unit values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-30 21:35:08 +02:00
sjg bb1fdbb43d [refactor](trx-frontend-http): wire JS frontend to decoder registry
Fetch /decoders on page load and use the registry to drive all
decoder-related UI instead of hardcoded lists:

- bookmarks.js: bmReadDecoders/bmWriteDecoders and bookmark form
  checkboxes generated from registry; bmApply() decoder toggle gate
  uses registry active_modes instead of hardcoded DIG/FM check
- background-decode.js: delete SUPPORTED_DECODERS constant, derive
  bookmarkDecoderKinds() from registry
- app.js: _decoderToggles and SSE status sync built from registry;
  updateDecodeStatus() and setModeBoundDecodeStatus() driven by
  registry mode_bound/toggle entries
- index.html: replace 8 hardcoded decoder checkboxes with dynamic
  container populated from registry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-30 20:57:13 +02:00
sjg e6dbfd1edb [feat](trx-protocol): add centralised decoder registry
Add DECODER_REGISTRY in trx-protocol::decoders as the single source of
truth for all decoder metadata (activation mode, supported rig modes,
background-decode capability). Replace duplicated resolver functions in
background_decode.rs and sse.rs with shared resolve_bookmark_decoders().
Add GET /decoders endpoint to expose the registry to the frontend.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-30 20:47:12 +02:00
Claude 5c43bac42b [feat](trx-rs): remap decoder modes — remove DIG/PKT from SDR, wire decoders to standard modes
For SDR backends, DIG and PKT are removed from supported_modes and
replaced by USB and FM respectively. CAT backends (FT-817, FT-450D)
retain DIG/PKT as before.

Decoder mode allowances updated:
- APRS: FM | PKT (was PKT only)
- HF-APRS: USB | DIG (was DIG only)
- AIS: AIS | FM | PKT (was AIS only)
- VDES: VDES | FM (was VDES only)
- FT8/FT4/FT2/WSPR: USB | DIG (unchanged)
- CW: CW | CWR (unchanged)
- LRPT: FM (unchanged, mode-independent)

Frontend status text, bookmark decoder toggles, background-decode
fallbacks, and scheduler wiring updated to match.

https://claude.ai/code/session_01DCAaMH8RF5FNB2gRtVu4pY
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-30 18:55:04 +02:00
Claude 7dfac0c38c [fix](trx-frontend-http): remove duplicate bandplan overlay from spectrum canvas
The bandplan strip was rendered twice: once as a DOM element above the
spectrum and again via WebGL directly on the spectrum canvas. Remove the
WebGL duplicate and keep only the DOM-based strip.

https://claude.ai/code/session_01TA1pCDuAr7V6oSnQs7JYvU
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-30 11:08:41 +02:00
Claude f6f59f3d00 [fix](trx-frontend-http): move band plan strip above waterfall in z-order
The band plan strip was visually positioned between the waterfall and
waveform areas. Move it to the top of .signal-visual-block (above the
overview/waterfall) so it renders above the waterfall. Remove the
bp-webgl transparent overrides since the strip now shows colored
segments in its own position rather than overlaying the spectrum canvas.

https://claude.ai/code/session_01KoxcohG6hn5b7kSc3mC4dA
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-30 10:35:25 +02:00
Claude 9dbf6fc64e [feat](trx-frontend-http): move band plan overlay to top of spectrum view
Repositions the bandplan strip from the bottom of the combined spectrum
canvas to the top. Updates HTML element order, CSS bp-webgl absolute
positioning, and WebGL rendering Y coordinates.

https://claude.ai/code/session_015sRhGsk7ggRYoxJANDY72S
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-30 10:11:43 +02:00
Claude b8f6208aa7 [fix](trx-frontend-http): move band plan strip above waterfall instead of between waveform and waterfall
Relocate the band plan strip from the top of the spectrum canvas to the
bottom, directly above the waterfall canvas. Move the DOM element inside
.spectrum-wrap before the waterfall canvas so it flows naturally in the
correct position. Remove the reparenting logic since the element is now
always inside .spectrum-wrap.

https://claude.ai/code/session_01FUD2eKgeXMFGhhYTzmA4Z6
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-30 10:00:42 +02:00
Claude 71bf8d9456 [style](trx-frontend-http): move bandplan strip from bottom to top of spectrum
Repositions the bandplan rendering above the waterfall instead of below
the spectrum waveform. Updates both the WebGL draw position (y=0) and
the CSS overlay positioning (top:0) for the label layer.

https://claude.ai/code/session_01Bt6iUi6Pc1v7yvLffEjweJ
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-30 08:34:09 +02:00
Claude 67f0d451b9 [fix](trx-frontend-http): guard initAprsMap against missing Leaflet variable
Prevent ReferenceError when navigating to the map tab before the
Leaflet CDN script has finished loading.

https://claude.ai/code/session_018nDze1zN1AR3UgYRx5pqcL
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-30 08:03:38 +02:00
Claude c3b9d2d6fd [fix](trx-frontend-http): close IIFE before bandplan strip declarations
The spectrum floor/gamma IIFE (line 11507) was missing its closing
`})();`, causing all bandplan strip variables and functions to be
trapped inside the IIFE scope. This made `bandplanRegion`,
`updateBandplanStrip`, and `_bandplanServerDefaultApplied` invisible
to the rest of the file, throwing ReferenceErrors that crashed
`render()` before the frequency display update could run — leaving
the frequency input stuck at its initial "--" placeholder.

https://claude.ai/code/session_01RgKhusmnk7AHEJqn1KHffU
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-30 08:00:06 +02:00
Claude 64682a900f [fix](trx-frontend-http): record decode statistics for all decoder types
The "Decodes by type" statistics panel only showed AIS because
statsRecordDecode was only called from dispatchDecodeMessage, which
was bypassed by two code paths:

1. dispatchDecodeBatch: uniform-type batches dispatched to specialized
   batch handlers (onServerFt8Batch, etc.) returned early without
   recording stats.

2. restoreDecodeHistoryGroup: history messages restored on page load
   were never recorded in the statistics log.

Fix both paths by recording stats up-front in dispatchDecodeBatch
before dispatching to batch handlers, and in restoreDecodeHistoryGroup
before restoring to plugin views. Add a skipStats parameter to
dispatchDecodeMessage to prevent double-counting when the fallback
per-message loop runs inside dispatchDecodeBatch. Also accept an
optional timestamp in statsRecordDecode so history entries use their
original ts_ms rather than Date.now().

https://claude.ai/code/session_01Ss2AD2bQgXu1ir1Z1WE3VY
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-30 07:54:47 +02:00
Claude 2150f61828 [feat](trx-frontend-http): add Statistics panel, move summaries from Map tab
Extract the three summary sections (longest decode paths, strongest/weakest
signals) from the Map tab into a new dedicated Statistics tab. Add new
analytics: decode counters, unique stations/grids, decode rate, decode-by-type
breakdown, band activity, per-receiver comparison, and DX distance histogram.
The Statistics panel has its own receiver and history filters independent of
the map view.

https://claude.ai/code/session_01R9T4Byg7uw6qpkTsyVJd9k
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-30 07:31:14 +02:00
Claude 8c5706f6c3 [feat](trx-client): add bandplan display config to client settings
Add bandplan_enabled (default: true) and bandplan_region (default:
"iaru_r1") fields to [frontends.http] config section, allowing the
operator to control the initial bandplan display setting from the
server config rather than requiring each browser session to configure
it manually. The server-provided default is applied on first connect
only when the user has no existing localStorage override.

https://claude.ai/code/session_01H7427hzbJepJzkoUJzoDmH
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-30 00:28:53 +02:00
sjg 6000c30d9c [fix](trx-client): R hotkey no-ops when frequency already on step grid
Previously R would retune even when the frequency was already aligned
to the jog step boundary. Now it shows "Already on step" and sends no
command. Also remove the stale "retune" label from the shortcut help.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-30 00:13:58 +02:00
Claude 3a2733850c [feat](trx-frontend-http): render bandplan strip via WebGL on spectrum canvas
Move bandplan segment rendering from DOM elements to WebGL, drawing
coloured rectangles at the bottom of the spectrum canvas (above the
waterfall). All segments are batched into a single drawTriangles() call
for efficiency. The DOM strip is reparented into .spectrum-wrap and
restyled as a transparent text-label overlay (bp-webgl class). Non-SDR
rigs without a spectrum canvas retain the original DOM-coloured fallback.

https://claude.ai/code/session_01XTizHhXbXSAPQVAf1j9CSF
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-30 00:13:32 +02:00
Claude 9abd2b7748 [fix](trx-frontend-http): make bandplan strip visible for all rig types
Move the bandplan strip out of the SDR-only spectrum panel into the
always-visible signal-visual-block. Add bandplanComputeRange() that
derives a frequency range from the current tuned frequency and band
edges when no spectrum data is available (non-SDR rigs). Trigger
bandplan updates on frequency changes and from the overview draw loop.

https://claude.ai/code/session_01AyBktp6b8qFjchyyqwL7dv
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-29 23:59:08 +02:00
Claude 4c095e64f0 [feat](trx-frontend-http): add bandplan strip above spectrum waterfall
Add a bandplan display strip that shows IARU frequency allocations
(CW, Phone, Digital, FM, Beacon, Satellite) above the spectrum plot.
Includes IARU Region 1/2/3 data for all HF/VHF/UHF bands, a settings
submenu for region selection and label toggle, and color-coded segments
that pan/zoom with the spectrum view.

https://claude.ai/code/session_01AyBktp6b8qFjchyyqwL7dv
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-29 23:49:36 +02:00
sjg 4aae2fa725 [feat](trx-client): merge R/T hotkeys into single R, add F for freq input
Combine round (R) and retune (T) into a single R hotkey that rounds to
the nearest jog step boundary, or retunes if already rounded. Update F
hotkey description to "Pick frequency" in the F1 help overlay.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-29 23:10:03 +02:00
sjg 0a60684e28 [feat](trx-rs): remove NOAA APT decoder
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-28 23:32:10 +01:00
Claude 8e700fb98a [feat](trx-frontend-http): optimize HTTP frontend performance
Server-side:
- Cache index_html() with OnceLock (avoids 3 string replacements per request)
- Pre-compress all static assets (JS/CSS/HTML) with gzip at startup, serve
  cached bytes with ETag + Cache-Control headers for browser caching
- Add If-None-Match / 304 Not Modified support for conditional GETs
- Serialize SSE state+meta in single serde pass via SnapshotWithMeta,
  eliminating the serialize → parse → flatten → re-serialize round-trip
- Add Cache-Control: immutable for favicon/logo (never change)

Client-side:
- Replace atob() + charCodeAt loop with direct base64 lookup-table decoder
  that writes to a reusable Int8Array (avoids UTF-16 string allocation)
- Spectrum bins now flow as Int8Array throughout the pipeline, reducing
  waterfall row memory from ~8 bytes/element to 1 byte/element
- Add isBinsArray() helper to support both Array and TypedArray in all
  spectrum/waterfall guard checks

https://claude.ai/code/session_01J3VCWZeEPsyFJiHjJRBREo
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-28 20:20:33 +01:00
Claude 731410a7e6 [fix](trx-frontend-http): skip redundant DOM writes in render() hot path
The render() function runs on every SSE event (5-20×/sec) and was
unconditionally writing to decoder toggle buttons and About-tab
decoder status elements — 8 getElementById calls + 32 DOM property
writes per frame — even when values hadn't changed. This caused
unnecessary style recalculation overhead on every SSE frame,
contributing to spectrum stuttering.

Changes:
- Cache all 7 decoder toggle button elements at module init instead
  of calling getElementById on every render() call
- Track last-written enabled state per button; skip DOM writes when
  the value is unchanged (steady-state cost: 0 DOM writes per frame)
- Same pattern for 8 About-tab decoder status elements
- Gate updateSatLiveState className/textContent writes on value change

Net effect: eliminates ~50 unnecessary DOM operations per SSE frame
during normal operation (decoders rarely toggle).

https://claude.ai/code/session_01G6wuNCkckbHHsU7w5zCtW2
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-28 19:09:15 +01:00
Claude aacc7336d7 [fix](trx-frontend-http): optimize spectrum and waterfall rendering performance
Six hot-path optimizations that reduce per-frame CPU cost:

1. Waterfall color LUT: Pre-compute a 256-entry RGBA lookup table
   (bins are i8 = 256 possible values) instead of calling
   waterfallColorRgba() per-pixel with HSL→RGB math + Math.pow().
   Eliminates ~2000+ HSL conversions per frame across both waterfalls.

2. Noise floor O(N)→O(N log N): Replace .slice().sort() with an
   in-place quickselect algorithm for 15th-percentile estimation.
   For 1024 bins this is ~10× faster.

3. Reuse spectrum bin buffers: SSE handler and buildSpectrumRenderData
   now reuse pre-allocated arrays instead of creating new Array(N)
   and .map() allocations every frame. Reduces GC pressure.

4. Cache canvas dimensions: drawSpectrum and drawSpectrumWaterfall
   read cached CSS dimensions instead of querying clientWidth/
   clientHeight every frame (which forces layout recalculation).
   Dimensions refreshed on resize and layout changes.

5. Cache DOM references: getElementById calls for zoom indicator and
   minimap elements moved to module-level constants instead of
   querying the DOM on every drawSpectrum call.

6. Efficient array trimming: Peak hold pruning uses in-place splice
   from front instead of .filter() (which allocates a new array).
   Waterfall row trimming uses splice instead of repeated .shift().

https://claude.ai/code/session_01G6wuNCkckbHHsU7w5zCtW2
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-28 19:00:58 +01:00
Claude 9920094008 [fix](trx-frontend-http): fix SAT prediction page degrading whole-page rendering
Three issues in the satellite predictions view caused page-wide
rendering performance degradation:

1. Unbounded DOM nodes: All satellite passes (200+ satellites × multiple
   passes = 500-1000 rows with 5 spans each) were rendered at once,
   creating thousands of DOM nodes that slowed style recalculation and
   layout across the entire page. Now caps at 50 visible rows with a
   "Show more" button.

2. No DOM cleanup on view switch: Prediction rows persisted in the DOM
   when navigating away from the predictions view or the SAT tab,
   bloating the page DOM indefinitely. Now clears prediction DOM when
   leaving the predictions view or switching decoder tabs.

3. Countdown timer never paused: The 1-second setInterval with
   querySelectorAll kept running even when the predictions view was
   hidden, wasting CPU on invisible DOM queries. Now only runs when
   predictions view is active, caches element references instead of
   querying the DOM each tick, and auto-pauses when the view is hidden.

Also caches prediction DOM element references at module init instead
of calling getElementById on every render invocation.

https://claude.ai/code/session_01G6wuNCkckbHHsU7w5zCtW2
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-28 18:51:42 +01:00
Claude 842ee6f076 [fix](trx-frontend-http): stop fetching /bookmarks on every SSE state update
applyRigList() was called on every SSE state update (since `remotes`
is always present in the payload), and it unconditionally called
bmFetch() which fires 2x GET /bookmarks (list + overlay). At the
default poll rate this generated ~20 bookmark fetches/second — visible
as constant GET /bookmarks traffic on each spectrum render cycle.

Now track the previous rig list + active rig as a key and only
re-fetch bookmarks (and re-init scheduler/background-decode) when
the rig list actually changes.

https://claude.ai/code/session_017g7VNMb6CChaiWrfzVBhbR
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-28 18:34:17 +01:00
sjg 171a1f4bbc [feat](trx-frontend-http): add F hotkey to focus frequency input
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-28 14:34:52 +01:00
sjg aab344b729 [feat](trx-rs): add NOAA/Meteor predictions; rename wxsat → sat
- Add NOAA-15/18/19 and Meteor-M N2-3/N2-4 to predictions list
- Rename PREDICTION_SATS (was HAM_SATS) to include weather + ham sats
- Rename all wxsat identifiers to sat throughout JS/HTML/CSS/Rust:
  wxsat.js → sat.js, WXSAT_JS → SAT_JS, /wxsat.js route → /sat.js,
  all #wxsat-* element IDs, .wxsat-* CSS classes, window.addWxsat* →
  window.addSat*, window.onServerWxsatImage → window.onServerSatImage,
  etc. (backend protocol strings unchanged)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-28 13:53:26 +01:00
sjg adec33708f [feat](trx-rs): add ham sat pass predictions; rename SAT tab
- Rename "Weather Satellites" sub-tab to "SAT"
- Add "Predictions" view: next 24 h flyby table for 13 ham sats
  (ISS, AO-91, AO-92, SO-50, AO-73, JO-97, PO-101, LilacSat-2,
  CAS-4B, EO-88, RS-44, SALSAT, GREENCUBE)
- trx-core/geo: add PassPrediction, HAM_SATS, compute_upcoming_passes(),
  find_passes_for_sat(), compute_az_el() helpers; spawn_tle_refresh_task
  now also fetches CelesTrak amateur group on startup and every 24 h
- trx-frontend-http: add GET /sat_passes endpoint
- app.js: locator tooltips now accumulate all receivers per station
  via remotes Set; _detailPassesRigFilter checks the Set

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-28 13:42:57 +01:00