- 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]>