#Amethyst v1.20.0: Desktop Self-Update, an Emoji Picker, Hand-Drawn Posts, and Developer Tools
Highlights:
- **Updates the desktop app by itself** from releases signed with
Amethyst's key over Nostr (NIP-82), and tells Homebrew, Flatpak and
read-only installs how to update instead.
- Adds an **emoji picker** to every composer: Unicode emoji with search and
skin tones, your favorites, and a section per custom emoji pack. It docks
where the keyboard would be.
- Lets you **draw a post by hand** and post it as a GIF that replays the
drawing.
- Gives **~250 new event kinds their own cards** instead of raw JSON or
ciphertext, and a readable fallback card for kinds no one knows yet.
- Adds a small **Developer Tools**: a NIP-19 converter, an event inspector, a kind
browser that samples real events, and a raw relay console.
- Opens a **profile card on mouse-over** of faces and names, with follow,
message and block.
- **Spell-checks** the desktop composers and prose fields.
- Creates **git repositories** from the app, and attaches pictures to git
issues.
- Signs in via NIP-46 with a **NIP-05 address** through the signer its domain
advertises, and shows NIP-46 `auth_url` pages instead of waiting silently.
- Brings **Marmot groups up to MDK v0.14.0** (White Noise): encrypted
polls, custom emoji, admin deletion and in-group reports.
- Parses relay messages with **Kite**, Quartz's own JSON engine, in about
half the time of the old path.
## New Features
### Emoji Picker and Reactions
- Adds an emoji picker to the note, comment, DM, public chat, Concord and
Nest composers: Unicode categories, name search, skin tones, your
reaction choices as Favorites, and one section per selected NIP-30 pack.
- Docks the picker as a panel at the bottom of the view that owns the
composer, keeps it open between picks, and closes it with Back, Esc, its
close button or when the keyboard comes up.
- Draws emoji in the system's color emoji font on desktop, which had no
way to type an emoji.
- Rebuilds the reaction choices screen around the same picker: chosen
emoji as removable chips on top, one search over Unicode names and pack
shortcodes, and a second tap to remove a choice.
- Saves reaction choices on every tap, signing one event for a burst of
taps, and drops the Save button.
- Keeps keycaps and flags whole, and finds a choice saved in another skin
tone, so a tap no longer adds a near-duplicate.
- Imports images and `.zip` archives into an emoji pack in one go, each
image named after its file, with a live grid of the uploads and a summary
of what was skipped and why.
- Explains an empty emoji pack and offers the import from there.
### Hand-Drawn Posts
- Adds a Draw button to the short-note composer: brush (with stylus
pressure), pencil, spray, eraser and mirror, eight inks and a pen size.
- Draws on plain paper, sticky notes, a notebook page, grid, dots, a
chalkboard, or your own picture, kept per account to draw on again.
- Previews the replay before posting, then posts a looping GIF of the
drawing being made, plus a PNG of the finished drawing.
- Suggests alt text with the on-device describer on the Play build.
### Event Cards
- Adds feed and thread cards for about 250 kinds that printed raw JSON,
ciphertext or nothing: DVM jobs, Buzz records, agents and workflows,
moderation, git CI, P2P orders, chess, drafts and many more.
- Shows encrypted and machine-only records as one quiet "Private" line with
their alt text.
- Draws kinds Quartz doesn't know as a card of their title, summary,
picture, people, links and tags, and keeps them reachable by link.
- Sends the author prose in those cards through the translatable rich text,
with links, mentions and custom emoji.
- Adds cards for Open Markets product collections, shipping options and
product reviews, and status badges and shipping costs on listings.
- Renders NIP-51 release artifact sets with their notes.
- Draws decentralized list items in three tiers, from raw tags to custom
views for GitHub accounts, books and food places, with maps for places.
- Shows a rated list item's title and cover in entity ratings.
- Turns 3D Simple Nostr Objects in place in the feed, and accepts objects
over 512 vertices.
### Developer Tools
- Adds a Developer Tools hub under Settings › App settings.
- Converts any NIP-19 code or hex to every other encoding and opens it.
- Inspects a pasted event, relay frame or nembed: recomputes the id,
verifies the signature and flags odd fields. "Inspect event" opens it
from a note's menu.
- Samples a kind's recent events from your relays and groups them by
client or shape, each with a real example's JSON.
- Opens a raw WebSocket console to one relay, with REQ, COUNT and EVENT
builders and AUTH behind a confirmation.
### Profiles and Hover Cards
- Opens a profile card after resting the mouse 250 ms on a face or name,
in feeds, threads, chats and notification galleries, with message,
follow, lists and the block/report menu.
- Shows the NIP-85 follower count on the card when a provider has one.
- Adds a Repos tab to profiles with git repositories.
- Redesigns the edit-nickname dialog around the person's avatar and name.
- Plays GIF banners as muted images on the profile and hover card.
### Git
- Creates NIP-34 repositories from the Git Repositories screen, with a live
preview, GRASP servers and an identifier check, as `ngit init` writes them.
- Shows the owner of an empty repository how to push the first commit.
- Attaches pictures and videos to a new git issue.
- Searches git repositories by author with `from:npub…`, `from:name.bit`
or a NIP-05, rewriting the name in place once it resolves.
- Drops the Git Repositories inline filter, which sat hidden under the top
bar, for the top bar's search.
### Remote Signers (NIP-46)
- Signs in with `name@domain` through the remote signer the domain's
`nostr.json` advertises, instead of a read-only account.
- Shows a signer's `auth_url` page with an Open button, and takes it down
when the request ends.
- Moves to the signer's relays when it asks (`switch_relays`), and tells
the signer on logout.
- As a signer, moves nostrconnect apps to your inbox relays, and answers a
pairing only once it listens on the app's relays.
- Reaches signer relays directly, like your own relays, instead of waiting
for Tor.
### Marmot Groups
- Adds encrypted polls to Marmot groups: a new poll sheet with @ mentions
and `:emoji:`, votes cast inside the group with Change vote, and tallies
counted the way MDK counts them.
- Sends and shows custom emoji in group messages, edits, polls and
reactions as encrypted attachments, never fetching an emoji's public URL,
and suggests them as you type `:` in the group composer.
- Lets group admins delete a message for everyone (kind 4891), and reports
a group message inside the group, where an admin can dismiss the reports.
- Opens each attachment with the media key of the epoch that carried it,
and sends an upload in the epoch that encrypted it, so a commit during an
upload no longer leaves members unable to open it.
- Uses the current group-avatar scheme, publishes new members' commits to
the group's relays, and keeps KeyPackages confirmed and fresh.
- Keeps deleted group messages gone after a restart and out of
notifications.
- Stops showing votes, reports and labels as chat bubbles, and shows
`<t:…>` timestamps in your locale.
### Accent Colors and Synced Settings
- Lets each account pick its own accent color under Account Settings, and
keeps the application color for the login screen and the rest.
- Themes account-bound screens (signer consent, calls, nests) with their
account's color.
- Syncs more account settings across devices through NIP-78: home tabs,
feed filters, custom feeds, chat view modes, relay AUTH policy, upload
defaults and calls.
### Notes and Feeds
- Adds Show Less to expanded notes, pinned in the author column on notes
taller than the screen.
- Adds a back-to-top button to every feed screen and the profile.
- Makes Share a submenu of the 3-dot menu, and the reaction row's Share
button a dropdown.
- Shares a note as an image with its pictures, link previews and a still of
its videos, and waits for them to load.
- Previews three relays of a relay-list card and opens long lists, up to
thousands of relays, in their own screen.
- Shows each listed relay's icon, name and badges, and adds it to one of
your relay lists in one tap.
- Folds a Concord community's actions into one menu and its description
into the top bar's panel.
- Opens cordn.net share links and QR codes, and folds Cordn's header
actions into one menu.
- Clears cookies and site data for all sites from the browser menu.
## Performance
- Parses relay messages with Kite, Quartz's hand-written JSON engine: about
half the time of the Jackson path with ~40% less allocation, and 30%
faster again in Quartz 2.2.0.
- Interns an event's strings when the cache keeps it, not while parsing:
~60% of the parse, paid even by duplicates.
- Parses a zap receipt's embedded request only when it is read.
- Shares one object per relay URL: re-reading an 8,464-relay list went from
33-150 ms to 6-8 ms.
- Stops `fetchAsFlow` and `subscribeAsFlow` copying the whole list per
event, ~12.5M copies for a 5,000-event answer.
- Prunes muted authors in one pass per store, instead of one scan per mute.
- Stops verifying new kind 0 and kind 5 events twice, and rebuilding the
notification cards twice per deletion.
- Lets galleries wait for their first image's shape instead of polling it
five times a second.
- Sizes Android's warm video players by RAM and prefetches the first
512 KiB of the videos below the screen, releasing them under memory
pressure.
- Starts the watched video first on desktop media feeds: a cold Shorts open
went from 8-13 s to 4-5 s on a 4 MB/s link.
- Stops reading a link preview's page at the end of its head: a GitHub repo
page reads ~34 KB instead of ~495 KB.
## Improvements and Bug fixes
- Loads a single relay picked in a feed's top bar, which sent no request in
25 feeds (Pictures, Shorts, Videos, Music, Polls and more).
- Trusts the relays you favorited as feeds, which stayed unconnected.
- Fixes a second profile, community, repository or follow pack on the same
relay getting only the first one's recent history.
- Fixes an older version of an article, wiki or listing replacing a newer
one, and an old deletion removing the current version.
- Keeps a deletion that lands during a feed update from coming back.
- Watches for newer versions of on-screen articles and lists.
- Checks an NWC response's signature before it uses up the pending payment.
- Validates nSite path hashes, rumor ids, NIP-28 channel metadata, private
zap targets and nutzap amounts from other people.
- Asks before acting on `nostrconnect://` and relay-group invite links.
- Stops a malformed lightning address crashing the app on OkHttp's thread.
- Bounds nembed inflation to 256 KiB and parses `lnurlp` URLs without a
backtracking regex.
- Keeps pinned DM rooms on top when their newest entry is a draft.
- Keeps bare URLs whole in markdown notes, so `_SL1499_.jpg` images load.
- Shows anamorphic videos at their display shape, and uploads them that way.
- Keeps glyph icons at their weight under Android's Bold text.
- Stops the notification service crashing on start with
`ForegroundServiceDidNotStartInTimeException`.
- Fixes the scheduled-posts list crashing, and drains scheduled posts
through the shared publisher with its signature checks.
- Says when relays are waiting for a Tor that is not coming up: the
drawer's Tor icon turns red after a minute, and relay lists mark onion
badges "Waiting for Tor".
- Lets DM and untrusted relays connect after "Continue without Tor" on
Android, which still waited for Tor.
- Sends reactions, deletions, poll votes and reports on a Marmot or Concord
message through its room. Voting on a group poll from its notification
used to sign a public event.
- Shows edited text in Concord previews, and asks before "Delete for
everyone".
- Gives freshly logged-in accounts their Cashu counter store, which failed
until a restart.
- Fixes a nostrconnect login hang on Tor, a cancelled nutzap shown as a mint
failure, and a cancelled Marmot reset left half done.
- Fixes a crash while typing a coordinator pubkey in Cordn and a crash from
duplicate Concord list entries.
- Keeps a restarted audio-room publisher's audio after its broadcast ends.
- Fixes follow toggles answering for the previous hashtag, geohash or relay.
- Finds UI Preferences when searching for its options.
- Reads "What should we call you?" on sign-up.
## Desktop
- Updates itself from GitHub Release installs (DMG, MSI, zip, AppImage,
tarball, deb/rpm), checking each file's SHA-256 against the signed
release, and shows the release notes. Settings › App › Updates controls it.
- Draws OpenStreetMap maps for places, locations, geocaches and the
geocaches Map tab.
- Opens `nostr:` and `amethyst:` links, routing them to a running copy.
- Mirrors the drawer in the macOS menu bar, with a submenu per settings
category and a Window menu.
- Draws at the desktop's fractional scale on X11 (125%, 150%).
- Downscales images with mipmaps, so avatars are no longer blocky, and
decodes large JPEGs at a fraction of their size.
- Plays audio-only media (music, podcasts, voice notes) on macOS and
Windows.
- Gives each on-screen video card its own player, keeps videos in a 2 GB
disk cache, shapes Shorts before they play, and replays ended videos.
- Pauses a feed video on leaving its screen unless you chose to watch it.
- Folds the notifications panel into a strip with a missed-count badge.
- Shares notes as images to the clipboard.
- Offers a QR code and Copy for a payment no installed wallet can open.
- Scans QR codes from a file or the clipboard, posts calendar reminders and
refreshes the Web of Trust.
- Runs a second copy beside the first with its own Tor and caches.
- Mines proof of work with all cores but two, and shows the live hash rate.
- Stops GStreamer's segfault trap from closing the app on Linux.
- Fixes the reactions grid crashing on scroll, and dark-mode white columns
in the deck and chat panes.
## Cli
- Adds `amy releases publish`, which signs the desktop, Zapstore (APK) and
Orchard (Flatpak) NIP-82 events in one run.
- Adds `amy emoji` for NIP-30 packs and bulk imports from a folder, `.zip`
or list.
- Adds `amy publish --file` and `amy fetch --out` to move a corpus between
relays.
- Resumes `amy fetch --paginate` after a dropped connection.
- **Breaking:** `amy fetch --paginate` exits 1 with `incomplete` on a
partial walk, and reports silent relays as `timeout`.
- Logs in with `amy login name@domain` through the domain's signer, and
sends `switch_relays` and `logout` from bunker accounts.
- Saves a bunker account under the key its signer signs for.
- Speaks MDK v0.14.0 in `amy marmot`: `message delete` removes another
member's message as an admin, `group download-image` is new, `group
set-image` accepts `--mime`, and media sends stay in their epoch.
- Writes `--json` output and `~/.amy` files with kotlinx, byte for byte as
before.
## Quartz
- Moves to its own repository, vitorpamplona/quartz, published to Maven
Central. Crypto now comes from crypto-kmp, QUIC from quic-kmp, MLS from
mls-kmp, and the Marmot and cordn group managers from marmot-kmp and
cordn-kmp.
- Adds Kite (`JsonEngine.KITE`), a hand-written reader and writer for every
Nostr message, byte-identical to Jackson's output.
- Adds `publishStream` for windowed bulk publishing, `keepConnected`, and
`fetchAllPagesResuming`.
- Replays a fresh connection's subscriptions before anything else goes out,
keeps the messages a relay sent before closing, and redials when the
backoff ends.
- Fixes lost listener registrations under concurrency, the pool dropping a
relay under an in-flight EVENT, and `fetchAsFlow` never ending on a
refusal.
- Adds Open Markets collections, shipping options and reviews, and
OpenAgents capability and package events.
- Picks full or midstate SHA-256 per event for NIP-13 mining.
- Rejects malformed ids, keys and kinds in `naddr`, `nevent` and NIP-10
tags, and keeps NIP-11 documents with kind ranges or large fees.
## Geode
- Answers an oversized EVENT with `OK false` instead of only a NOTICE.
- Stops a negative filter limit from reading the whole store.
- Fixes a blank search narrowing a filter, and a `tagsAll` `#d` deleting
every row.
## Build & Documentation
- Removes Jackson from the app modules, which moved to kotlinx.
- Runs the CI lint job's KMP metadata compiles before pushing to main.
- Runs each JVM suite once in CI and starts every job at once.
- Fits a pre-push build in 16 GB of RAM.
- Adds a Flathub manifest that builds Amethyst from source, and a Linux
screenshot in the metainfo.
- Moves the release macOS legs to macos-15 and pins the JetBrains Runtime.
- Generates the changelog's contributors with `scripts/contributors.sh`.
- Moves to marmot-kmp 2.0.0 and mls-kmp 1.2.0.
- Bumps Gradle, Kotlin, Compose Multiplatform and dependencies.
- Bumps `appCode` to 465.
## Contributors
- @nprofile…vhl6
- @nprofile…kcfw
- @nprofile…0zgt
## Translations
- Czech, German, Swedish, and Brazilian Portuguese by @nprofile…kcfw
- Hindi by @nprofile…z0lu
- Hungarian by @nprofile…ns2l
- Polish by @nprofile…8c53
- Slovenian by @nprofile…3gag
- Uzbek by fiddleway