WoT was previously global-feed only. Now it filters notes on every feed
tab (global, following, trending) and also gates reaction pills and zap
totals — so a reaction from someone outside your social graph no longer
shows up in the counts.
- engagement.ts: wotSet param threaded through groupReactions,
fetchReactions, fetchZapCount, fetchBatchEngagement. Zaps are filtered
by the pubkey inside the zap request (the actual zapper), not the
outer event.pubkey (the LNURL wallet). Extracted getZapperPubkey and
getZapAmountSats.
- useReactions / useZapCount: cache key embeds WoT state so filtered
and unfiltered counts don't collide. Hooks subscribe to the WoT store
so toggling re-renders.
- feed store: reads WoT state and passes wotSet to fetchBatchEngagement,
seeds cache with the correct key.
- Feed.tsx: drop the tab === "global" guard.
- SettingsView.tsx: update copy to reflect the wider scope.
Commit 214c42b (v0.12.6) added auto-detection of content-addressed
Blossom URLs (64-hex SHA-256 paths) as <img> elements. Blossom is
widespread in modern Nostr feeds — every feed page started rendering
3-5x more <img> elements. Combined with WebKitGTK's weak decoded-
bitmap eviction, feed scrolling grew the WebKit web process to
8-12 GB and triggered WebKit's self-kill threshold with:
Unable to shrink memory footprint of process (9022 MB) below
the kill threshold (8192 MB). Killed
Disable BLOSSOM_URL_REGEX in parseContent(). Real Blossom images
shared via standard upload flows (with proper extensions) still
render. Proper reintroduction (HEAD request + Content-Type
validation, or known-server whitelist) planned for v0.12.9.
Also restore feed depth caps to pre-crisis values now that memory
is under control:
- MAX_FEED_SIZE 30 → 200 (v0.12.6 baseline)
- fetchFollowFeed limit 30 → 100
- fetchGlobalFeed fetch 80 → 100
- Following tab slice 30 → 100
The earlier 30-caps were themselves OOM firefighting that shipped
in v0.12.7 and were no longer needed.
Memory verified 2026-04-16: oscillates 1.1-1.6 GB across all tabs
(Global / Following / Trending / Media / profile / thread) under
heavy use with embedded relay enabled. No crashes. Elastic cache
behaviour rather than monotonic leak — memory spikes briefly on
content loads and reclaims within seconds.
See private_docs/WEBKIT_OOM_INVESTIGATION.md for the full
investigation (4 days of chasing symptoms before finding the
one-line regex as the real cause).
- followNotes capped at 30 (was 80) — following feed was rendering 2.7x more
notes than global, causing 4GB+ spike on media-heavy follow content
- fetchFollowFeed limit 80→30 to match
- WEBKIT_FORCE_SOFTWARE_RENDERING=1 replaces WEBKIT_DISABLE_COMPOSITING_MODE=1
(compositing mode killed Wayland path → blank window on Hyprland)
- HardwareAccelerationPolicy::Never → OnDemand (Never also caused blank screen)
- set_enable_page_cache(false) — SPA never navigates, bfcache is pure waste
- Removed duplicate fetchNotifications calls on login (was firing 3x in 8s)
- First notification poll delayed 8s→90s to avoid competing with feed load
- Result: login 3600MB→453MB, following feed crash→737MB, plateau at ~950MB
New users now choose topics after backing up their key. Selected interests
are saved to localStorage (wrystr_interests) and surfaced as clickable
hashtag pills in the Following feed empty state, giving new users a path
into content without auto-following strangers.
Flow: welcome → create → backup → interests → app
Login path is unchanged.
SHA-256 hash filenames from content-addressed storage (Blossom/NIP-96)
now always treated as images regardless of extension. Also broaden
IMAGE_EXTENSIONS to cover avif, bmp, tiff, jp2 and common variants.
- DM messages now parse and render URLs as clickable accent links
- Image URLs show inline in the bubble (max-h-48)
- nostr:naddr and mentions rendered as styled clickable links
- nostr:nevent quotes show a subtle indicator
- Media URLs (video/audio/youtube etc.) rendered as clickable links
- parseContent regex now case-insensitive for nostr: prefix; entity
lowercased before nip19.decode for robustness
- renderTextSegments: add case for quote type (↩ note indicator)
- All selected images now upload and insert correctly (was: only last
image kept due to stale content closure in loop)
- Images inserted as a block with proper newline padding
- Thumbnail strip thumbnails are now clickable — opens a lightbox;
click overlay to dismiss
- NoteCard: title tooltip on truncated name and NIP-05
- NoteActions: emoji pill buttons dim (opacity-50) while disabled
- DMView: title tooltip on truncated conv name; focus ring on send button
- RelaysView: title tooltip on truncated relay URL
- OnboardingFlow: title tooltips on npub/nsec (nsec only when revealed)
- ArticleEditor: visible focus indicator on title and body textareas
- Move DMView console.log/error behind debug.log/error (silent in prod)
- Replace hard-coded text-[#ffffff] with text-white in NoteContent overlay
- Theme-ify Vimeo and Tidal media cards (bg-accent/15 instead of
bg-black/40 and bg-white/10) so they adapt to light themes
- Convert Vimeo play icon SVG to currentColor for theme-aware tinting
- Add aria-label to update banner dismiss button
- Replace remaining '...' with unicode ellipsis in loading states
- Fix bg-white toggle thumbs in Settings (broke on dark themes)
- Eliminate 2px layout shift when switching Media feed tabs
- Unify "Follow"/"Mute" capitalization in NoteCard context menu
- Replace ASCII "..." with unicode ellipsis across compose/search/article
- Add rounded-sm to dropdowns, emoji picker, post/reply buttons
- Add aria-labels to sidebar toggle and onboarding copy buttons
- Add role=tablist/tab/aria-selected to login mode tabs
- Replace inline width/height styles with Tailwind w-16 h-16 in ProfileView
- Replace inline transform style with rotate-90 class in SettingsView
- Unify sidebar active state opacity (bg-accent/8 → bg-accent/10)
- Pad sidebar badges with py-0.5 for consistent pill height
- Match thread reply button sizing to compose post button
- Use var(--font-reading) on non-zen article title for consistency
- Format 'saved Xs ago' as minutes/hours after 60s
- Unify expand chevron to ▶ + rotate-90 pattern
- PollWidget: transition-all → transition-colors (no layout animation)
- Remove cryptic 'Ctrl+Enter' hint from compose and thread reply
NIP-1068 polls: create and vote on polls inline in the feed.
Switch default relay to custom Go relay (relay2.veganostr.com).
Note action icons with tooltips, sidebar icon cleanup,
search dedup fix, thread indentation fix.
Subscribe to view changes in UI store and pause all video/audio
elements inside <main> when the view switches. Prevents double
audio when opening a thread from a note with playing video.
Podcast player audio is outside <main> and unaffected.
When audio hits the 15s loading timeout or fires an error event,
stop any active V4V streaming to prevent phantom sat payments
on episodes that aren't actually playing.
- New V4V store with budget tracking, cap enforcement, and history
- Dashboard: live streaming status, per-episode + weekly budget bars, stats
- Settings: auto-enable toggle (guarded by caps), per-episode cap, weekly
budget, default rate, info icons
- History: expandable list of past V4V episodes with recipient breakdowns
- Budget enforcement: streaming stops with toast when cap is hit
- Auto-streaming: starts automatically for V4V episodes when enabled
- Cap reached state: dashboard shows red card, ticker shows "(capped)"
- V4VIndicator: slimmed popup, AUTO badge, "open v4v" nav link
- Fix duplicate history entries on cap stop
- Add payKeysendViaNWC for node pubkey recipients with TLV records
- Route V4V payments to keysend or LNURL-pay based on recipient type
- Show recipient split breakdown in V4V panel (name + percentage)
- Add V4V nudge: brief tooltip when V4V episode starts (once per session)
- Highlight V4V button in amber when episode has recipients but streaming off
- Enhanced V4V badge in episode list with lightning icon and pill style
- Add audio.load() reset to prevent cascading failures between episodes
- Add onPlaying event handler for reliable post-buffer playback in WebKitGTK
- Add 15s loading timeout with user-friendly error for broken audio URLs
- Fix V4V LNURL-pay: use Tauri HTTP plugin instead of CORS-blocked browser fetch
- Fix Podcast Index API: use Tauri HTTP plugin for V4V enrichment
- Fall back to Podcast Index enclosure URL when Fountain.fm CDN is broken
- Update Lightning address to jure@getalby.com (Alby cloud migration)
- Add broad HTTPS scope for LNURL-pay across Lightning providers
Fountain-resolved episodes now get V4V payment splits by looking up
the show on Podcast Index and matching the episode. Enables streaming
sats to podcast creators directly from the player bar.
- Import fetch from @tauri-apps/plugin-http (browser fetch was CORS-blocked)
- Add fountain.fm to Tauri HTTP capability scope
- Extract og:audio meta tag for reliable audio URL resolution
- Parse OG title into show name + episode title
- React.memo on NoteCard and ArticleCard to skip re-renders
- Granular Zustand selectors in Feed.tsx and NoteCard.tsx
- Lazy-load 19 views with React.lazy + Suspense boundary
All text-dim values now meet 4.5:1 minimum contrast ratio against
their theme background. Midnight/Light text-muted also bumped from
borderline 4.42:1 to compliant. Colors stay on-hue — just brighter
(dark themes) or darker (light theme) to cross the threshold.
- Add accent-text and zap-text tokens to all 7 themes for proper contrast
on accent/zap-colored buttons (fixes white-on-light-accent in Catppuccin,
Nord Frost, Hackerman, Sepia, Gruvbox)
- Replace text-white → text-accent-text on all accent buttons (20+ instances)
- Replace text-white → text-zap-text on zap buttons
- Replace hover:text-white → hover:text-accent-text on follow/action buttons
- Replace bg-blue-500 → bg-accent in FountainCard (theme-aware)
- Remaining text-white is correct: overlays on bg-black, danger badges