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>
- 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>
Widen the recordings filter input (remove max-width cap, set min-width),
add search icon placeholder, use type=search for native clear button.
Also fix download/remove button size mismatch with explicit height.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
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>
Restructure the WEFAX tab to match the SAT/LRPT pattern with a
view switcher bar. Live view shows decoder description, live canvas,
and latest image card. History view adds a filterable, sortable table
of all decoded images with Clear All button.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
The WEFAX button had id="subtab-wefax" which duplicated the panel's id,
causing querySelector to match the button instead of the panel on click.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
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>
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>
sat.js was only in the 'map' plugin group but the SAT subtab lives
under digital-modes. History/Predictions buttons had no click handlers
until the map tab was visited. The loaded Set prevents double-loading.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Same issue as Leaflet — content blockers block the jsdelivr CDN request,
causing the seven-segment font to fail loading and fall back to monospace.
Also replace preload-to-stylesheet swap with media="print" onload swap
for themes.css and leaflet.css to eliminate Safari preload warnings.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Bundle Leaflet JS, CSS, and marker/layer images as embedded assets served
under /vendor/ instead of loading from unpkg.com, which content blockers
(e.g. Safari) prevent.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
The lazy plugin loader (25c5940) deferred scheduler.js to the 'settings'
tab, but initSettingsUI() runs at app boot before the user clicks any tab.
This meant initScheduler was undefined at boot, so the scheduler-control-row
on the main tab never showed and status polling never started.
Two fixes:
1. Add 'settings' to the eagerly-loaded plugin list so scheduler.js and
vchan.js load at startup alongside digital-modes and bookmarks.
2. Add auto-init at the end of scheduler.js: if authRole is already set
when the script executes (late/lazy load), it self-initializes without
waiting for initSettingsUI(). This makes it resilient to any load order.
https://claude.ai/code/session_01YNwgQGjCdLjVMcatVy3uQi
Signed-off-by: Claude <noreply@anthropic.com>
The lazy plugin loader introduced in 25c5940 incorrectly mapped
scheduler.js to the 'recorder' tab. The scheduler UI lives under
Settings → Scheduler, so the plugin must load with the 'settings' tab.
This caused the scheduler controls to be invisible and non-functional.
https://claude.ai/code/session_01NuatkhpFU7JCRnAbNUavPk
Signed-off-by: Claude <noreply@anthropic.com>
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>
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>
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>
Implement all 15 scheduler improvement tasks from docs/scheduler_improvements.md:
P0 — Usability Fixes:
- Highlight active entry in time-span table with sch-active class
- Bookmark existence validation on save with toast error
- Dirty-state indicator for satellite section via markDirty bridge
P1 — Information Density & Clarity:
- Show local time alongside UTC in entry table and timeline
- Expand entry details by default with localStorage persistence
- Richer "Now Playing" status card with freq, mode, active decoders
P2 — Interaction Improvements:
- Inline entry editing directly in table rows
- Drag-to-reorder entries with HTML5 drag-and-drop
- Timeline click-to-add with pre-filled hour range
- Improved extra-channels management with chip list and dropdown
P3 — Feature Enhancements:
- Grayline location lookup by Maidenhead grid square
- Expanded satellite preset library (NOAA 15/18/19, ISS, SO-50)
- Scheduler activity log with ring buffer backend and UI
- Timeline interleave visualization with alternating color stripes
- Keyboard shortcuts (Shift+R/N/P) for scheduler control
https://claude.ai/code/session_01VFLAHs1UMzPso3GWSQP9wJ
Signed-off-by: Claude <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
- IX-2: Add confirm() dialogs before all destructive actions (10 history
clear buttons, scheduler reset, background decode reset)
- IX-6: Add Select All / Deselect All buttons for background decode
bookmark checklist
- IX-1: Add dirty-state indicator (pulsing dot) on Save buttons when
unsaved changes exist in scheduler and background decode panels
- A-4: Add role="alert" and aria-live="polite" to toast notification
elements for screen reader accessibility
- A-3: Add Unicode symbol prefixes to background decode state labels
(checkmark/triangle/cross) so state is distinguishable without color
https://claude.ai/code/session_01ShfPMW9hPLD3czp9YovkbJ
Signed-off-by: Claude <noreply@anthropic.com>
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>
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>
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>
Remove the wxsat/NOAA APT checkbox from bookmark decoder form and all
JS references — the APT decoder no longer exists.
Fix LRPT decoder not activating when an FM-mode bookmark is applied:
bmApply() gated decoder toggles on DIG mode only, so LRPT bookmarks
(which use FM) never triggered SetLrptDecodeEnabled. Gate on DIG or FM.
Wire satellite pass scheduling into the scheduler loop: check configured
satellite entries against live pass predictions, activate the satellite's
bookmark (enabling LRPT decoder) when a pass is active, and expose
active_satellite in SchedulerStatus for the frontend.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
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>
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>
Visual 24h timeline bar, inline entry editor, interleave progress ring, filterable checkbox list for bookmarks, status cards moved to top, SVG dot state badges.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Move ~230 lines of satellite pass scheduling code from scheduler.js
into a new sat-scheduler.js plugin with cached DOM refs, createElement-
based rendering, and a clean bridge API. Refactor sat.js predictions
view to deduplicate row builders, extract countdown timer lifecycle
management, and cache all DOM references.
https://claude.ai/code/session_0144nUfHAKs7yRnYTsozNagw
Signed-off-by: Claude <noreply@anthropic.com>
Add HTML, JS, and CSS for the satellite pass scheduling overlay in the
scheduler settings panel. The satellite section is always visible
regardless of the base scheduler mode (Grayline/TimeSpan) since it
operates as a preemption overlay.
UI features:
- Enable/disable toggle for satellite pass preemption
- Configurable pre-tune seconds (time before AOS to start tuning)
- Satellite entry table with add/edit/remove (satellite name, NORAD ID,
bookmark, min elevation, priority)
- Preset dropdown for common weather satellites (NOAA 15/18/19,
Meteor-M2 3/4) that auto-fills name and NORAD ID
- Bookmark selector for each satellite (sets freq, mode, decoders)
- Live pass status badge showing active satellite from scheduler status
- Status card shows "[SAT: name]" label when satellite pass triggers
- Scheduler control row visible when satellites enabled (even with
base mode disabled)
https://claude.ai/code/session_01WzWvhFVhEP9Fqn4u6pXs3T
Signed-off-by: Claude <noreply@anthropic.com>
Add category selector (All/Weather/Ham Radio/Other) to predictions panel.
Split predictions into currently receivable passes with live countdown
timer and upcoming passes table. Add SatCategory enum to geo types
for CelesTrak group classification.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Iterate all TLE store entries (weather + amateur) for pass predictions instead of a hardcoded list. Add name/elevation filter bar to the predictions UI. Fix pre-existing missing fields in remote_client test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
- 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>
- 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>
Replace flat image list with two switchable views:
- Live: decoder state cards (Idle/Listening), descriptions, latest image
- History: filterable table with columns for time, type, satellite,
channels, lines, and download link. Supports text filter, type filter
(All/APT/LRPT), and sort order (newest/oldest).
https://claude.ai/code/session_01JA13DHuzuHUL4nSBBRU83f
Signed-off-by: Claude <noreply@anthropic.com>
Restructure trx-wxsat into noaa/ (APT) and lrpt/ (Meteor-M LRPT) submodules
with shared crate base. Add QPSK demodulator, CCSDS CADU framer, MCU channel
assembler for LRPT. Wire LRPT through full stack (core types, protocol, server
decoder task, client). Add Weather Satellites sub-tab in Digital Modes with
toggle buttons for NOAA APT and Meteor LRPT, descriptions, and image history.
https://claude.ai/code/session_01JA13DHuzuHUL4nSBBRU83f
Signed-off-by: Claude <noreply@anthropic.com>
Remap retune from R to T, and add a new R hotkey that rounds the
current frequency forward to the next jog-step boundary. Both the
new hotkey and the remapped retune are documented in the F1 help
overlay.
https://claude.ai/code/session_017neG2jL9uXFSRpmhyS1EqG
Signed-off-by: Claude <noreply@anthropic.com>