- All 5 columns (Name, Public Key, Role, Last Seen, Adverts) are now
sortable by clicking the column header
- Click toggles between ascending/descending sort
- Visual indicator (▲/▼) shows current sort column and direction
- Sort preference persisted to localStorage (meshcore-nodes-sort)
- Removed old Sort dropdown since headers replace it
- Client-side sorting on already-fetched data
- Default: Last Seen descending (most recent first)
White semi-transparent square behind QR so black modules pop.
White rects in SVG already set to transparent by JS.
Same white backing in dark mode too (QR needs light bg to scan).
CSS fill-opacity selectors weren't matching the QR library's output.
Now JS directly sets white rects to transparent after SVG generation.
Overlay at 70% opacity so it doesn't fight the map for attention.
Removed 'Scan with MeshCore app' label from overlay version.
- QR globally reduced (140px → 100px, overlay 64px)
- Side pane: name/badges first, then map with QR overlaid in bottom-right corner
- Removed standalone QR section from side pane — saves vertical space
- Public key shown inline below map instead of separate section
- No-location nodes still get standalone centered QR
- Full detail page QR wrap narrower (max 160px)
- Map and QR code now sit side-by-side (flex: 3/1) instead of stacked
- QR section shows truncated public key below the code
- Stats section uses a compact 2-column table with alternating row stripes
- Name/badges/actions section tightened up with less vertical spacing
- Mobile (<768px): stacks map and QR vertically
- No-location nodes: QR centered at max 240px width
CSS changes:
- style.css: .live-dot.connected, .hop-global-fallback, .perf-slow, .perf-warn
now use var(--status-green/red/yellow) instead of hardcoded hex
- live.css: live recording dot uses var(--status-red), LCD text uses var(--status-green)
JS changes (analytics.js):
- Added cssVar/statusGreen/statusYellow/statusRed/accentColor/snrColor helpers
that read from CSS custom properties with hardcoded fallbacks
- Replaced ~20 hardcoded status colors in: SNR histograms, quality zones,
zone borders/patterns, SNR timeline, daily SNR bars, collision badges
(Local/Regional/Distant), distance classification, subpath map markers,
hop distance distribution, network status cards, self-loop bars
JS changes (live.js):
- Added statusGreen helper for LCD clock color
- Legend dots now read from TYPE_COLORS global instead of hardcoded hex
All colors now respond to theme customization via the customize panel.
Added --nav-text and --nav-text-muted CSS variables. All nav
selectors (.top-nav, .nav-brand, .nav-link, .nav-btn, .nav-stats)
use these instead of --text/--text-muted. Nav Text is in Basic
settings. Nav Muted Text in Advanced.
This is separate from page text because nav sits on a dark
background — page text color would be unreadable on the nav.
- Move --status-green/yellow/red from home.css to style.css :root (light+dark)
- Replace hardcoded status colors in style.css (.tl-snr, .health-dot, .byop-err,
.badge-hash-*, .fav-star.on, .spark-fill) with CSS variable references
- Replace hardcoded colors in live.css (VCR mode, stat pills, fdc-link, playhead)
- Replace --primary/--bg-secondary/--text-primary/--text-secondary dead vars with
canonical --accent/--input-bg/--text/--text-muted in style.css, map.js, live.js,
traces.js, packets.js
- Fix nodes.js legend colors to use ROLE_COLORS globals instead of hardcoded hex
- Replace hardcoded hex in home.js (SNR), perf.js (indicators), map.js (accuracy
circles) with CSS variable references via getComputedStyle or var()
- Add --detail-bg to customizer (THEME_CSS_MAP, DEFAULTS, ADVANCED_KEYS, labels)
- Move font/mono out of ADVANCED_KEYS into separate Fonts section in customizer
- Remove debug console.log lines from customize.js
- Bump cache busters in index.html
Changed nav brand, links, buttons from hardcoded #fff/#cbd5e1 to
var(--text) and var(--text-muted). Setting primary text color
now changes nav text too. Removed unnecessary --nav-text variable.
Badge colors were hardcoded in style.css with different values
than TYPE_COLORS, causing mismatch between customizer and actual
display. Removed all .badge-advert/.badge-grp-txt/etc color rules.
syncBadgeColors() in roles.js now generates them from TYPE_COLORS
on every page load.
Color changes dispatch theme-changed event → app.js re-navigates
to current page, rebuilding markers/rows with new colors.
Conflict badges (.hop-ambiguous, .hop-conflict-btn) now use
var(--status-yellow) so they follow the customized status color.
- Nav bar now uses CSS variables (was hardcoded gradient)
- 19 customizable colors: accent, text, backgrounds, borders,
surfaces, inputs, stripes, hover, selected, status indicators
- Light and dark mode have separate color sets
- Theme tab shows which mode you are editing
- Toggle ☀️/🌙 in nav bar to switch modes and edit the other set
- Export includes both theme and themeDark sections
- localStorage save/restore handles both modes
New color palette: deep navy (#060a13, #111c36) replacing
purple tones. Muted greens/yellows/reds for status indicators.
All functional CSS (hop conflicts, audio, matrix, region dropdown)
preserved and appended.
⚠3 is now a yellow button (not tiny superscript). Clicking it
opens a popover listing all regional candidates with:
- Node name (clickable → node detail page)
- Distance from observer region center
- Truncated pubkey
Popover dismisses on outside click. Each candidate is a link
to #/nodes/PUBKEY for full details.
New hop-display.js: shared renderHop() and renderPath() with
full conflict info — candidate count, regional/global flags,
distance, filter method. Tooltip shows all candidates with
details on hover.
packets.js: uses HopDisplay.renderHop() (was inline)
nodes.js: path rendering uses HopDisplay when available
style.css: .hop-current for highlighting the viewed node in paths
Consistent conflict display across packets + node detail pages.
1-byte (and 2-byte) hop IDs match many nodes globally. Previously
resolve-hops picked candidates from anywhere, causing cross-regional
false paths (e.g. Eugene packet showing Vancouver repeaters).
Fix: Use observer IATA to determine packet region. Filter candidates
to nodes seen by observers in the same IATA region via the existing
_advertByObserver index. Fall back to global only if zero regional
candidates exist (flagged as globalFallback).
API changes to /api/resolve-hops response:
- conflicts[]: all candidates with regional flag per hop
- totalGlobal/totalRegional: candidate counts
- globalFallback: true when no regional candidates found
- region: packet IATA region in top-level response
UI changes:
- Conflict count badge (⚠3) instead of bare ⚠
- Tooltip shows regional vs global candidates
- Unreliable hops shown with strikethrough + opacity
- Global fallback hops shown with red dashed underline
- Add width: max-content to dropdown menu for auto-sizing
- Add overflow ellipsis + max-width on dropdown items for very long labels
- Checkboxes already flex-shrink: 0, no text wrapping with white-space: nowrap
Instead of silently dropping notes or hoping gesture listeners fire,
show a clear overlay on first packet if AudioContext is suspended.
One tap resumes context and removes overlay. Standard pattern used
by every browser game/music site.
audio.js is now the core engine (context, routing, voice mgmt).
Voice modules register via MeshAudio.registerVoice(name, module).
Each module exports { name, play(ctx, master, parsed, opts) }.
Voice selector dropdown appears in audio controls.
Voices persist in localStorage. Adding a new voice = new file +
script tag. Previous voices are never lost.
v1 "constellation" extracted as audio-v1-constellation.js.
- Pre-create pool of 6 reusable markers (no create/destroy per frame)
- CSS transition: transform 80ms linear for position, opacity 200ms ease
- will-change: transform, opacity for GPU compositing
- Styles moved from inline to .matrix-char span class
- Marker positions updated via setLatLng, browser interpolates between
- Fade-out via CSS transition instead of rAF opacity loop
Revert to 8c3e2f4 if this doesn't feel better.
- Hex chars: 16px white text with triple green glow (was 12px green)
- Only render every 2nd step for wider spacing between bytes
- Animation speed: 45 steps @ 50ms (was 30 @ 33ms) — ~2.3s per hop
- Trail length reduced to 6 (less clutter)
- Map brightness down 10% (1.4 -> 1.25)
Dark mode tiles are already dark; previous filter was making them
invisible. Now brightens 1.4x + green tint via sepia+hue-rotate.
Also fixed ::before/::after selectors (same element, not descendant).
- Replaced sepia+hue-rotate chain with grayscale+brightness+contrast
- Green tint via ::before (multiply) + ::after (screen) overlays
- Much brighter base map — roads/coastlines/land clearly visible
- Markers dimmed to #005f15 at 40% opacity
- DivIcon markers at 35% brightness
- Map tiles desaturated + darkened to near-black with green tint
- CRT scanline overlay with subtle flicker animation
- All node markers re-tinted to Matrix green (#00ff41)
- Feed panel: dark green background, monospace font, green text
- Controls/VCR bar: green-on-black theme
- Node detail panel: green themed
- Zoom controls, attribution: themed
- Node labels glow green
- Markers get hue-rotate filter (except matrix hex chars)
- Restores all original colors when toggled off
New toggle in live map controls: 'Matrix' - animates packet hex bytes
flowing along paths in green Matrix-style rain effect.
- Hex bytes from actual packet raw_hex data flow along each hop
- Green (#00ff41) monospace characters with neon glow/text-shadow
- Trail of 8 characters with progressive fade
- Dim green trail line underneath
- Falls back to random hex if no raw data available
- Persists toggle state to localStorage
- Works alongside existing Realistic mode
CSS content:attr() doesn't support newlines in any browser. Replaced
with a real <span> child element with white-space:pre-line, shown on
hover via .sort-help:hover .sort-help-tip { display: block }.
Native title tooltips are unreliable (delayed, sometimes not shown).
Replaced with CSS ::after pseudo-element tooltip using data-tip attr.
Shows immediately on hover with proper formatting.
- Region filter container: remove margin-bottom, use inline-flex align
- Column dropdown checkboxes: 14x14px to match region dropdown
- Sort help ⓘ: use for newlines in title (\n doesn't render)
- Dark mode: .filter-bar .btn.active now retains accent background
(dark theme override was clobbering the active state)
- All filter-bar controls now exactly 34px tall with line-height:1 and border-radius:6px
- col-toggle-btn matched to same height/font-size as other controls
- Controls grouped into 4 logical sections (Filters, Display, Sort, Columns) with vertical separators
- Added title attributes with helpful descriptions to all controls
- Added sort help icon (ⓘ) with detailed tooltip explaining each sort mode
- Mobile responsive: separators hidden on small screens