# v1.21.0: NApplets in Notes, drss.io Listening, WebXDC, and Pico 8

Highlights:

- **Runs napplets inside their notes**, on Android 11+ and on desktop, and
  plays **webxdc apps** attached to posts in a sandbox with no network.
- **Hosts napplets and nSites on desktop** in a bundled Chromium, at parity
  with Android.
- **Plays Pico-8** posted as `.p8.png` images, full screen, with
  touch, keyboard and gamepad controls.
- **Listens with drss.io**: episodes resume where you stopped, a listen
  queue, history, chapters, clips and speed, and drss lists that stay in sync.
- Adds a **Post Layout** setting: Indented, Full Width or Borderless notes.
- **Downloads every Home content type from your follows**, and adds forum
  threads, calendar events, code snippets and git to Home.
- Offers **web of trust from a card on Home**, with the provider's relay
  adopted in one step.
- Shows **HDR video in HDR** in the fullscreen viewer, and keeps HDR when
  compressing with H.265.
- **Plays chess over Nostr** in every build: a Chess feed with your games
  and the lobbies of your lists, draw offers, abandonment claims and end
  screens, interoperable with Jester and nostr.blue.
- **Redesigns the poll composer** in New Post, and puts the drawing button in
  every composer.
- Hardens napplets, nSites and webxdc after a security review: decrypting
  needs its own grant, cookies and WebRTC stay out of every frame, and site
  cards prefetch within a budget.
- Fixes memory leaks across view models, navigation and app-wide caches, and
  uploads that failed with "Stream Closed".

## New Features

### Napplets, nSites and webxdc

- Runs a napplet in place inside its note: Run here, a bar with Open and
  Stop, and the last frame left behind when it stops. The feed never prompts:
  anything that would ask you is refused and offered as Open instead.
- Runs webxdc apps (`.xdc` attachments and kind-1063 files) from an app card
  with Start, in their own storage per account and app, with no network, no
  WebRTC and no access to your keys. Shows a progress bar while the archive
  downloads, and opens a newer archive of the same app instead of the old one.
- Plays webxdc apps inside their notes, like napplets.
- Adds NAP-OUTBOX: napplets read and publish through people's own relays,
  with bounded routing and consent per read or signed kind.
- Follows the current NIP-5D manifests and NAP contracts: single-artifact
  manifests, verified icons and kind-aware storage. Napplets published with
  the old path-aggregate manifest must be republished.
- Takes WebRTC away from napplets, and from Tor sites on Android.
- Closes the router's local-network and DNS leaks, keeps each site's cached
  files to itself per account, and keeps a napplet's game saves when the app
  is killed.
- Tells you when Android can't open an nSite.
- Adds NAP-FS: a napplet opens and saves files you pick in the system file
  dialog, on Android and desktop, so apps like PhotoHop open. An app inside
  a note never opens a picker, and repeated dismissals back off.
- Adds NAP-INC, so napplets like Relay Browser, Blobbi and Emoji Pack
  Creator launch and talk to each other, scoped to the account they run as.
- Adds NAP-UPLOAD, which uploads through your Blossom servers, and
  NAP-COMMON: profiles, follows, NIP-19 codes, and follow, react and report
  under the same prompts as publishing.
- Adds NAP-INTENT: a napplet hands a task to another, and your favorites,
  in their order, choose which app handles it.
- Names the capabilities Amethyst doesn't support on a napplet's card
  instead of hiding Open.
- Delivers any file type a napplet loads (3D models, archives) except SVG,
  HTML and XML, which would run with the napplet's grants.
- Keeps desktop favorites across restarts, and loads their manifests at
  start on desktop as on Android.
- Hardens the hosts after a security review:
  - Relay reads decrypt DMs, gift wraps and private lists only with a
    decrypt grant, and never against a peer the app chose; only events with a
    valid signature reach an app.
  - `signEvent` needs the signer capability, which only websites hold.
  - A declined prompt backs off before it can ask again, Block denies every
    capability, and each app has one storage quota across its instances.
  - Inline launches run the newest version of an app seen on the device, so
    an old signed version can't run with today's grants.
  - Cookies and WebRTC are taken from every frame an app makes, the in-app
    browser follows the page's Tor route for WebRTC, and desktop turns off
    Chromium's network prediction.
  - `window.nostr` is offered only on https, .onion and the device itself, and
    the file chooser hands pages only other apps' files and fresh captures.
  - Site cards prefetch within one shared budget, only from public https
    servers, and not when the media setting wouldn't load images.
- Deletes the unpacked webxdc apps opened longest ago once they pass 1 GB,
  and caps a Concord channel's webxdc signals at 4 MB.

### Game Cartridges

- Adds a Play button to images that are fantasy-console carts (a 160x205
  `.p8.png`), opening a full-screen player on Android and desktop.
- Reads only the first 24 bytes of a candidate image to detect a cart, through
  the Tor-aware image client, and only when images may load.
- Plays with a sliding direction pad and O/X buttons that a thumb rolls
  between, a haptic tick per press, keyboard and gamepad keys, and sound.
- Opens the game's pause menu on Back instead of closing the player, keeps
  the screen on and hides the system bars in landscape.
- Keeps game saves when the app is killed, each cart's saves its own (by the
  hash of the cart), and only the two latest games in memory.
- Stops re-encoding a PNG cart on upload, which destroyed the game in its
  pixels.

### Chess

- Moves Chess into the navigation catalog as a feed, in release builds too:
  listed under Feeds in the drawer and menus, and pinnable to the bottom bar.
- Shows one feed driven by the top-bar list: "Mine" is the games you started,
  were challenged to or moved in; any other list is a lobby of its people's
  games, and Global every open challenge.
- Plays like a chess site: tap or drag a piece, last-move and check
  highlights, and the board always from your own side.
- Adds draw offers that ride on your next move, and a Claim win when the
  opponent has been silent for three days.
- Replays only the validated main line, so a player can't rewrite earlier
  moves, and refuses illegal moves.
- Shows end screens with the result and the score by player, move notes with
  their board, and the games a user ended on their profile's Notes tab.
- Redesigns the new-game dialog and the NIP-64 game viewer.

### drss.io

- Draws drss.io records as cards: shows, episodes, folders and feed lists.
- Resumes a long-form episode from where drss.io says you stopped, and
  marks episodes you have heard. Amethyst reads drss's listening progress
  (kind 30078) but never writes it.
- Adds a Listen screen with the episodes you are part way through, then the
  unfinished ones from your river, in one player that moves on by itself.
- Adds a listening History by day with a Feeds heard chart.
- Adds -15s/+30s, chapters from the show notes, per-feed speed, and clips
  saved as NIP-84 highlights of the episode.
- Reads a drss folder or feed list as a feed, from the Home picker or "Read
  as feed" on its card.
- Adds a drss lists organizer that sets the read and write lists, and renames,
  moves, merges and deletes lists and folders, with list pictures.
- Lets a show's owner edit its settings and on-air status.
- Keeps drss's reader records, like playback progress, out of feeds.

### Post Layout

- Adds a Post Layout setting with three modes: Indented (the author picture
  in a column beside the post, as before), Full Width (the author on top, the
  post across the width) and Borderless (Full Width with images, videos,
  Markdown media and link cards running out to the screen edges).
- Heads a full-width repost with both authors' rows beside their pictures.

### Home

- Requests every content type Home can show from your follows, so music,
  podcasts, fundraisers and attestations no longer appear only after another
  screen loaded them.
- Adds forum threads, calendar events, zap goals, code snippets, stream clips,
  git repositories, issues and pull requests, publications and torrent
  comments to Home, with new toggles in Settings › Home.
- Loads bursty catalog kinds (ebooks, magazines, music, podcasts, git repos)
  on their own subscription so one album upload can't crowd notes out.
- Keeps git repository announcements off Home.

### Web of Trust

- Shows a circle card on Home to accounts that follow 10 or more people and
  have no trust provider, and turns web of trust on from there.
- Sends your profile, follows, mutes and relay list to the provider before
  sign-up, so the first scores start from your current graph.
- Adopts the provider's relay into your trusted, search, indexer and favorite
  relays, and moves feeds set to Global onto it.
- Redesigns the card with animated rings, a typical circle size and an
  Activate button; the provider stays a visible choice, and after Activate the
  card explains that the first scores take about 10 minutes, then closes.

### Polls

- Redesigns the New Post poll composer on the group poll's design: options
  drawn as the rows a voter taps, an empty row that takes the next option,
  Enter and Tab to move between rows, and duplicates flagged.
- Takes @ mentions, :emoji: and image links in poll options.
- Gathers the settings in one card: Vote with zaps, Multiple answers, the
  zap range and Close after.

### Publications and Payments

- Renders PressStr ebooks (kind 33953), magazines (34609) and magazine
  issues (39731) as cards, opening PDFs in the in-app reader.
- Translates and crops kind-30041 publication sections like notes, with
  Copy Translated.
- Shows a one-line "Lightning Invoice · 50 sats" or "LNURL" label where
  previews are off, instead of a wall of bech32.
- Says when an invoice expires.

### Media

- Shows HLG and PQ video in HDR in the fullscreen viewer.
- Compresses video with LightCompressor-enhanced 2.3.0: HDR video stays
  10-bit HDR with H.265 where the encoder can keep it, and is tone mapped to
  proper SDR everywhere else. iPhone Dolby Vision recordings compress instead
  of failing.
- Tells you under the H.265 switch whether a picked HDR video stays HDR or is
  converted to SDR, and why.
- Names the picked video's own resolution on the Android quality slider.
- Stops the video encode when you cancel a post.
- Adds the drawing button to every composer: comments, public messages,
  articles, listings, group DMs, edits and git issues.

## Improvements and Bug fixes

- Stops uploading to NIP-95, which is deprecated. NIP-95 files still display.
- Fixes uploads that failed with "Stream Closed" when OkHttp retried a
  Blossom or NIP-96 upload over a dropped connection.
- Encrypts each file of a multi-file NIP-17 DM under its own key and nonce,
  instead of crashing on the second file.
- Retries only the files that failed, reports errors uploaders return
  silently, and leaves files removed mid-upload out of the result.
- Stops downloading translation models for blocked languages (Hebrew,
  Indonesian and Norwegian slipped through), deletes the models of blocked
  languages, and translates Filipino notes.
- Adds a Translation Models setting: Always, Wi-Fi only or Never.
- Fixes memory leaks: view models scoped to their item, eager collectors
  added per recomposition, app-wide watchers pinning notes, chess polling
  after leaving chess, and caches that only grew.
- Bounds each Concord channel's message buffer and prunes Concord channels
  under memory pressure.
- Keeps other people's local relays (localhost, LAN, tailnet) out of the
  dialer while keeping your own, and exempts only your own from Tor.
- Stops signer rejections from crashing the app, and handles a refusal in
  each flow instead of dropping it.
- Doesn't crash when a gift wrap or seal opens to something that isn't an
  event.
- Serializes a NIP-46 signer's reloads of the paired apps' relays.
- Dedupes Blossom servers so the media servers list can't crash.
- Shows zaps to the host of service-signed live streams in the chat.
- Closes the media viewer into the thumbnail of the media on screen.
- Keeps the emoji panel open while searching.
- Seeds the profile-zap notification card from the decrypt cache.
- Centers the hidden-note warning inside reposts.
- Deletes an addressable's current version even after a cleanup.
- Keeps a saved account saved across a transient login of it.
- Clears a screen's view models when navigation hands it new arguments.
- Switches tabs from the drawer's Navigate rows when the drawer stands in for
  the bottom bar.
- Paints the theme background under navigation, so going back on a light
  window no longer flashes dark.
- Makes Namecoin resolution errors selectable, and replaces the dead ElectrumX
  default server.
- Offers member removal in Marmot groups to admins only.
- Fixes a crash when replacing one mention with another while editing a
  post on Samsung Keyboard, and stops composers restarting the keyboard
  session on every recomposition.
- Renders the descriptions of Shorts, Longs and Stories as rich text, with
  mentions, clickable links and translation, and drops a description that
  only repeats the title.
- Keeps a cashu token, invoice or NIP-19 link whole when Show More shortens
  a long note, so its card renders before the note is expanded.

## Desktop

- Opens napplets and nSites in Chromium through JCEF, downloaded on first
  use, each in its own window with the main window's macOS title bar.
- Puts a napplet window's toolbar in the macOS title bar row beside the
  traffic lights, drops its Close button for the window's own, and opens
  the shield's access sheet as a popover without a title bar.
- Fixes crashes on macOS when closing a napplet window and when clicking
  while Chromium starts for the first time.
- Stops a focus loop with Chromium that overflowed the stack each time a
  napplet inside a note was clicked.
- Runs napplets inside notes with off-screen Chromium.
- Plays videos the native engine can't decode, like WebM on macOS, in
  Chromium, plus WebM and Ogg audio, through the same Tor-aware media relay.
- Plays GIFs of any length by decoding frames as they show.
- Filters OS notifications by the Notifications top-nav filter.
- Keeps each card's video its own when posts share one file.
- Opens links on Windows through the shell's own process.
- Reads relay sockets on virtual threads, so mass dials no longer queue
  behind thread start.
- Starts logged in or with a new account through `AMETHYST_LOGIN` and
  `AMETHYST_SIGNUP`, and adds local relays through `AMETHYST_LOCAL_RELAYS`,
  for test runs.
- Loads feed videos far faster, most of all on slow hosts: a scroll no longer
  starts every video it passes, the video you stop on gets the bandwidth while
  it starts, and videos scrolled past stop downloading at once.
- Plays hour-long episodes whose index is several MB by fetching the index to
  disk before the player opens the file, and tries a video natively once more
  before giving it to Chromium.
- Plays AV1 videos in Chromium on Macs without AV1 hardware (M1 and M2),
  which played only their sound under a blurred picture.
- Fixes a crash on macOS while playing videos: the app ships its own build of
  the video library's macOS player, without the audio tap that crashed.
- Falls back through your other Blossom servers when one refuses an upload,
  as Android does, and counts an upload as done when the server already
  holds the exact file.

## Cli

- Backdates the seal and the wrap in `amy gift wrap`; `--no-backdate` opts
  out.
- Sends Content-Digest when mirroring a release APK to Blossom.
- Adds `amy cordn migrate resume`, and `migrate export` stands the old home
  down.
- Reads relay sockets on virtual threads.
- Adds `amy chess challenge|show|move|resign|play`, with draw offers and
  claims, and a minimax bot to play the app end to end over Nostr.

## Quartz

- Moves to Quartz 2.13.0, which drops Jackson for Kite everywhere, adds
  the drss.io (with kind-30078 listening progress), PressStr and NIP-5D
  classes, and validates a chess game's main line.
- Moves cordn's protocol code to cordn-kmp 1.2.1, and Marmot's leave,
  permissions, timeline, edit, poll and emoji rules to marmot-kmp 2.2.1.
- Plays carts with kiko-kmp 0.2.3, a new library for the fantasy-console
  runtime, through its kiko-player and kiko-compose modules.
- Builds on crypto-kmp 2.1.0, mls-kmp 1.3.0 and quic-kmp 1.2.0.

## Build & Documentation

- Bumps `LightCompressor-enhanced` to 2.3.0.
- Bumps the Android Gradle Plugin to 9.5.0, Ktor to 3.6.1 and Lucene to
  10.6.0.
- Builds every module and target with no compiler or Gradle warnings.
- Adds a desktop video timeline log (`-Damethyst.videoTimeline=true`) that
  shows where a video's start time goes.
- Runs Android lint in the pre-push hook.
- Moves hardcoded strings from the shared UI, commons and desktop into
  Compose resources, with plurals for counted strings.
- Makes a thrashing Kotlin daemon exit instead of grinding.
- Runs the pre-push build without parallel tasks, which ran the Kotlin
  daemon out of memory.
- Disables the automatic Crowdin sync while the project is suspended.

## Contributors

- @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- @npub1e2yuky03caw4ke3zy68lg0fz3r4gkt94hx4fjmlelacyljgyk79svn3eef
- @npub1gvv9ahktvavf9qjtrgm62le7gplmmchd5usp5wpfhr85hf79kncqj8xchs
- @npub1uac67zc9er54ln0kl6e4qp2y6ta3enfcg7ywnayshvlw9r5w6ehsqq99rx
- Kaio Rabelo

## Translations

- Czech, German, Swedish, and Portuguese by @npub1e2yuky03caw4ke3zy68lg0fz3r4gkt94hx4fjmlelacyljgyk79svn3eef
- Portuguese by Kaio Rabelo
- Dutch by @npub1w4la29u3zv09r6crx5u8yxax0ffxgekzdm2egzjkjckef7xc83fs0ftxcd
- Hindi by @npub1ww6huwu3xye6r05n3qkjeq62wds5pq0jswhl7uc59lchc0n0ns4sdtw5e6
- Hungarian by @npub1dnvslq0vvrs8d603suykc4harv94yglcxwna9sl2xu8grt2afm3qgfh0tp
- Polish by @npub16gjyljum0ksrrm28zzvejydgxwfm7xse98zwc4hlgq8epxeuggushqwyrm
- Slovenian by @npub1qqqqqqz7nhdqz3uuwmzlflxt46lyu7zkuqhcapddhgz66c4ddynswreecw
- Uzbek by fiddleway
