Phase 1 — Sign zap requests:
- When the LNURL endpoint advertises allowsNostr + nostrPubkey and the
tipper has NIP-07, sign a kind-9734 zap request and pass it as the
nostr= param to the pay callback. Tags include e (event id), a
(naddr coords) and p (recipient) for feed-card / preview tips, or
just p for profile tips.
- Silent fallback to plain LNURL-pay for non-zap endpoints or
signed-out users. Tips never silently fail.
- Tiny "⚡ Tracked zap" badge in the invoice view when the zap path
engaged, so QR / copy users know their tip will count.
Phase 2 — Aggregate and display:
- Parse kind-9735 receipts via the embedded description tag (NIP-57
amount) or a bolt11 amount fallback (with multiplier table).
- _zapCache aggregates by event id and by author pubkey; receipts are
deduped by event id.
- Feed enrichment phase batch-queries receipts by #e for visible
designs; profile-page opens query by #p for the author and by #e
for each design in the grid.
- Feed cards display a "⚡ <total>" badge in the actions row.
- Design preview meta line gets the same badge.
- Profile page header shows "⚡ X sats received" under the npub.
Sort and visibility:
- New "⚡ Zapped" tab in both the Community modal and the welcome
modal. Sort is pure zap-total with date as the tiebreaker.
- Existing Popular sort now leads with zap totals, falling back to
reactions, trust, and date.
- isPreviewBroken now flags designs pre-emptively when the preview
URL is missing (for modes that require artwork) or uses a non-http
scheme, so broken designs sink to the bottom on first paint
instead of waiting for an actual image-load failure.
- Broken-image set persists to localStorage so detected breakage
survives reloads.
Payment detection:
- After a tracked invoice is issued, a background poller queries
kind-9735 events with #p=recipient + since=now. When a receipt
arrives whose embedded zap request matches the tipper's pubkey,
the event id, and the amount (within 10% tolerance), the modal
shows "✓ Payment received! Closing…" and auto-closes 1.2s later.
Polling stops after 5 minutes (invoice expiry), on close, or on
"New amount".
- WebLN auto-pay button appears in the invoice view when
window.webln is available; one click pays via the extension and
closes the modal on success. Rejections are handled quietly so
the QR / copy paths remain available.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
PROFILE_PAGES_FEATURE.md: URL-routed /u/:npub profile pages with banner,
avatar, kind-0 metadata, NIP-05, npub copy, action row, and a filterable
designs grid. Zaps and tips are explicitly out of scope.
LIGHTNING_ZAPS_FEATURE.md: minimal LNURL-pay → bolt11 → QR tip flow.
No NWC, no NIP-57 zap requests, no zap receipts. Vendors qrcode-generator
for in-browser QR rendering. Lands separately, behind profile pages.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
- Rename Use button to "Fork off!" with tooltip; clean customArt state on
fork to prevent leftover state from previous mode bleeding into the editor.
- Filter layers by current mode in renderLayers via isLayerForCurrentMode so
fork loads only show layers belonging to the active template type.
- Introduce WORKFLOW_ORDER + renumberWorkflowSteps to fix sidebar panel
order and visible step numbering across all five modes using CSS order.
- Replace template-browser wipe-and-rebuild with diffWallCards DOM diff so
cards no longer flash on progressive loads.
- Style Block and Report buttons as .danger; gate Block behind a confirm
dialog naming the author and pointing to the Blocked authors panel.
- Widen feed cards (minmax 240px) and let action row wrap so Block doesn't
clip on narrow viewports.
- Add designFingerprint + dedupByFingerprint to collapse identical
cross-author forks to the earliest post; preserve duplicates in Mine tab.
- Update Custom Art mode doc with shipped status and Phase D wishlist.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
Project metadata:
- New "+ Add Media Identifiers" button styled as a real button (not a
details-summary text link) on both the main metadata fieldset and the
disc-designer's metadata fieldset
- Expands to 4 optional inputs: IMDb ID, UPC, TheTVDB ID,
MusicBrainz Disc ID. Button label dynamically becomes
"Media Identifiers (N)" when any are filled
- State adds state.meta.upc / tvdbId / musicbrainzDiscId alongside
the existing imdbId. Old payloads with only imdbId continue to work
- Publish event tags emit NIP-73-style ['i', 'imdb:tt1234567'],
['i', 'upc:...'], ['i', 'tvdb:...'], ['i', 'musicbrainz:...'] alongside
the legacy ['i', 'tt1234567'] for backward compat
- Community feed search haystack now includes all four identifiers, so
typing a UPC into search finds matching designs
Docs:
- New docs/CUSTOM_ART_MODE_FEATURE.md spec for the upcoming 5th
template mode (generic canvas at arbitrary aspect ratios for
wallpapers, banners, social posts, posters). Three-phase plan:
Phase A editor, Phase B publish/share, Phase C browser+filter+export.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Layers:
- Layers panel now shows in disc-sheet and jewel template modes and inside
the disc-design designer (was hidden in all three)
- Layer target dropdown is mode-aware: disc shows Disc 1/Disc 2, jewel shows
the two inserts, cover shows trim/back/spine/front
"Use" button (template browser):
- Cover/disc/jewel "Use" now switches the editor out of designer mode via
switchAppMode('template'), so the right tool is visible after loading
- Disc-design "Use" always opens the disc-design designer unless an explicit
slot import target was set
Disc-sheet title:
- Template browser title for 2-disc sheets concatenates per-slot titles as
"Disc 1 title + Disc 2 title" via new discSheetDisplayTitle() helper
Jewel case spine text:
- New jewelSpineLabels {left,right} mirrored from the disc spine pattern
- Inputs in jewel artwork panel, vertical-rl labels rendered over both tray
spines, persisted via jewelTemplate.spineLabels in save/publish payloads
Jewel preview:
- New renderJewelPreviewDOM() renders front + tray with spines, spine text,
and any jewel-target layers in the template browser preview pane
Broken image flagging:
- _feedCache.brokenImages tracks failed preview URLs
- Broken cards get a "MISSING IMAGE" badge, dimmed/hatched thumbnail, and
are de-ranked to the end of the sort on New and Popular tabs
Disc-design panel:
- Removed standalone "Design name" input; design.name now mirrors
state.meta.title automatically
Welcome modal:
- Redesigned to match the community browser: New/Popular tabs, feedWall grid,
buildFeedCard tiles, "Browse all designs" + "Start from scratch" footer
- Search input now searches inline using the same card layout
Docs:
- New spec at docs/COLOR_AND_FONT_LAYERS_FEATURE.md covering the upcoming
color-fill layer type and text font-family picker
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Soft moderation (Phase 5):
- Blur cards that ≥2 hop-1 follows have muted (kind-10000) or reported (kind-1984)
- Overlay shows count + dominant reason; "Show anyway" reveals for the session
- Settings toggle under Community (on by default, hidden when logged out)
- Trust beats crowd: self/trusted authors never blurred
- Spec doc at docs/WOT_SOFT_MODERATION_FEATURE.md
Feed scrolling:
- Removed nested scroll container on .feedWall (max-height + overflow-y caused
the wall to only show ~2 rows because the outer .modalCard ate scroll events)
- Re-targeted infinite-scroll listener to .modalCard
- Added top-up loop in appendFeedRows so the first chunk fills the viewport
Template d-tag collisions:
- Cover/disc/jewel/disc-design publishes now prefix the d tag with the mode
(e.g. cover:tt12345 vs disc:tt12345) so a user can publish multiple template
types for the same IMDB without one replacing the other at the relay level
- buildRowsFromEvents and deduplicateRows now key by (address, mode) so legacy
events with unprefixed d-tags also coexist correctly in the UI
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
The template browser was returning zero results because kind 30078
(NIP-78 app data) is shared by many unrelated apps. A bare
{kinds:[30078], limit:200} query was getting flooded by other apps'
events (northlight-fragment alone had 300+ per relay), pushing
casewrap templates past the cutoff.
Narrow the relay-side query with #t:['casewrap'] for templates and
#k:['30078'] for deletions so the limit applies to this app only.
Also ships several supporting fixes that came out of the same
debugging session:
- queryRelays: add onEvent / onRelayDone streaming callbacks so
templates render as they arrive instead of after every relay
settles. Fast relays now populate the feed in < 1s.
- markRelayFailure: accept a context arg ('read' vs 'publish').
Read failures use 30s base / 5min max cooldowns (was 10min / 1hr).
A single transient read timeout no longer silently shrinks the
relay pool for an hour.
- fetchFeedAndReactions: stream into a Map, debounce a 150ms
rebuild of _feedCache.events, fire notifyFeedProgress() on each
batch so loadFeedTab re-renders progressively.
- loadFeedTab: register a per-tab rerender closure as
_currentFeedRerender, render whatever is cached immediately,
re-render on each progress tick. _currentFeedRerender === rerender
identity check prevents a late await from clobbering a tab the
user switched away from.
- Add live status line ("Streaming · N templates · R/T relays")
above the feed wall in New and Popular tabs.
- buildRowsFromEvents: respect NIP-09 deletion semantics by tracking
per-address deletion timestamps. Templates published AFTER a kind-5
deletion at the same address are no longer silently filtered.
- Drop wss://relay.nostr.pub from default relays (DNS no longer
resolves).
See docs/STREAMING_RELAY_SYNC_FEATURE.md for the full plan and
rationale.
Co-Authored-By: Claude Haiku 4.5 <[email protected]>
- Fix 'key is not defined' error in publishDiscDesignToNostr function
- Preserve layers when importing disc designs into template slots from both JSON files and Nostr
- Check both discDesign.layers and top-level payload.layers during import
- Populate designer metadata (title, category, imdbId) when loading projects
- Auto-set Nostr browse modal to 'disc-design' filter when importing from template slots
- Add undo/redo feature plan documentation for future implementation
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>