Skip to content

feat(desktop): show who made each beta change and what it does - #57886

Merged
kitlangton merged 5 commits into
betafrom
beta-notes-rich
Oct 22, 2026
Merged

kitlangton merged 5 commits into
betafrom
beta-notes-rich

Conversation

@kitlangton

@kitlangton kitlangton commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Issue for this PR

N/A. Kit asked for the "What's new in beta" dialog to say who made each change and to show it with a small animated visual, instead of listing commit subjects.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Each entry in "What's new in beta" now shows its title (the PR title without type and scope), then a small looping animated SVG of what changed, then a quiet line with the author's avatar and name and the PR link. Entries without a visual show a small kind icon in the left gutter instead (a sparkle for new, a check for a fix, a bolt for a speedup). The list scrolls inside a fixed header and footer, and its edges fade as it scrolls.

Where the visuals come from. The PR template gets an optional ### Visual section with an svg code block. AGENTS.md gets a short rule asking user-facing feat/fix/perf PRs to include one: 240×72, drawn with currentColor and opacity, a good still before any animation runs, CSS or SMIL only, at most 8 KB, no scripts or external references.

Build. packages/desktop/scripts/beta-notes.ts reads every listed PR in one GraphQL query per 100 PRs. It takes the author (name or login, plus GitHub's public avatar URL) and the ### Visual block. packages/desktop/scripts/beta-visual.ts parses the block as XML (htmlparser2) and writes it out again from an allowlist of shape, paint, gradient, clip/mask, text and animation elements and attributes. It refuses the visual unless there is exactly one root <svg>. It also refuses a doctype or entity, a CSS escape (so @\69mport or u\72l( can't hide), an @import or another at-rule besides @keyframes/@media, a url() that isn't #id, and anything over 8 KB. It drops scripts, foreign objects, images, handlers, outside hrefs and SMIL that animates href. The build embeds two copies: the animated one and a still made by removing SMIL elements, @keyframes and every animation/transition declaration. A sentence or two from the PR body is kept as the visual's alt text, with template filler skipped and long text cut at 240 characters. With no token, or when GitHub errors or is slow, entries keep their git author name and show kind icons, and the build never fails. The token stays in the build script, and only public data reaches the bundle (the beta build step gets GITHUB_TOKEN, and the workflow gets pull-requests: read).

Runtime. A visual renders only as <img src="data:image/svg+xml,…"> at a fixed 240×72, so it can never run scripts or load anything. An image doesn't inherit the page's colour, so the dialog sets the SVG's currentColor to the theme's icon colour. Under reduced motion (the app setting or the system one), the dialog shows the build's still copy, which has no animation rules left that an authored !important or inline style could keep running. Avatars load lazily and fade in over the author's initial.

Unchanged: the dialog is still shown after an update unless release notes are off in Settings, along with "View all on GitHub", "Got it" and how the list picks its entries.

How did you verify your code works?

  • bun test scripts/beta-notes.test.ts in packages/desktop (46 pass). The cases cover rebuilding the visual with its namespace and its still, dropping scripts, foreign objects, images, handlers, outside references and SMIL that animates a link, removing important and inline animations from the still, refusing a missing section, a non-svg root, two roots, a doctype, @import plain or CSS-escaped, an escaped or entity-encoded or outside url() (in CSS, attributes and animations) and anything over 8 KB, keeping the SVG out of the alt text, template filler, the length cap, one query per batch, and the offline fallbacks.
  • bun test src/updater/beta-notes.test.ts in packages/gui-extensions (14 pass), including the theme colour and the reduced-motion still.
  • bun typecheck in both packages, and bun run lint:changed against the branch base (0 problems).
  • The stories' four example visuals come back from the rebuild byte for byte. The stories use fictional people and entries.
  • Storybook stills and clips from one headless HiveMind run.

Visual

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 72" fill="none"><style>.d{transform-box:fill-box;transform-origin:50% 100%;animation:g 4s cubic-bezier(.2,.8,.2,1) infinite}@keyframes g{0%,12%{transform:scaleY(.3);opacity:0}28%,72%{transform:none;opacity:1}88%,100%{transform:scaleY(.3);opacity:0}}</style><g class="d"><rect x="56" y="10" width="128" height="30" rx="6" fill="currentColor" fill-opacity=".08" stroke="currentColor" stroke-opacity=".35"/><circle cx="74" cy="25" r="6" fill="currentColor" fill-opacity=".5"/><rect x="86" y="21" width="60" height="4" rx="2" fill="currentColor" fill-opacity=".5"/><rect x="86" y="29" width="36" height="3" rx="1.5" fill="currentColor" fill-opacity=".25"/></g><rect x="48" y="40" width="144" height="24" rx="8" fill="currentColor" fill-opacity=".06" stroke="currentColor" stroke-opacity=".5"/></svg>

Screenshots / recordings

The dialog in real time, its visuals looping:

dialog-loop.mp4

Typical update (dark, light):

Typical update, dark and light

Entries without a visual show kind icons (left), and under reduced motion the visuals hold their still (right):

Fallback icons and reduced motion

Opening, dark:

open-dark.mp4

Opening, light:

open-light.mp4

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@kitlangton
kitlangton merged commit 5a023ed into beta Oct 22, 2026
12 of 32 checks passed
@kitlangton
kitlangton deleted the beta-notes-rich branch October 22, 2026 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant