Skip to content

Mobile: a night scene on the welcome screen, plus a polish pass - #89

Merged
githubesson merged 6 commits into
mainfrom
mobile/unslop
Nov 3, 2026
Merged

githubesson merged 6 commits into
mainfrom
mobile/unslop

Conversation

@githubesson

@githubesson githubesson commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

What changed

Welcome screen. Signed-out users land on a record sliding out of its sleeve among the clouds, drawn through a pixel mesh, with a left-aligned headline, one primary action and one quiet link. It replaces the bubble parade, its purple glow and the hopping title. The scene is night in dark mode and morning in light mode.

  • scripts/render-welcome-art.py renders the art, which keeps it reproducible.
  • lib/welcome-mesh.ts holds a Skia shader that draws the mesh in whole device pixels. A mesh baked into the image would shimmer on any phone that scales it.
  • If Skia can't read the art or compile the shader, the plain image shows instead.

Polish pass.

  • Color: purple now only means Favorites. The Favorites wash is gone, swipe-to-favorite matches the tab's purple, and the account avatar is flat. Replay's chart and genres are neutral, with one accent on the busiest bucket and top genre.
  • Type: no uppercase tracked labels, weights stop at 600, and nothing is under 11pt. The Favorites large title keeps 700 to match native large titles, and the exported story sticker keeps its own weights.
  • Icons: the waveform replaces sparkles, since nothing here is AI.
  • Spacing and shape: values move onto the 4pt grid, with a few 2pt nudges. The Favorites controls row keeps its 14, which lib/favorites-header.ts depends on. Cards share a 16 radius and padding, and primary and secondary buttons share a 48pt height.
  • Copy: sentence case, … instead of ..., no period on one-sentence captions, and filler eyebrows and repeated figures removed.

Replay artist tiles. These followed the audit and are a behavior fix. A TIDAL-only artist has no library page, but the tile always opened one. It now follows core's topArtistAction, like desktop: open the page if there is one, else play their top tracks, else do nothing. Tiles show a cover from the artist's top tracks, with a person glyph when there's none.

One change outside mobile/. frontend/tests/ui/fixtures.ts gets a later expiry on its active invite. The old date, 2026-11-01, has passed, so revoke invite confirmation in frontend-ui failed on every viewport regardless of the branch. It's a one-line test fixture change in its own commit, because nothing can merge while that job is red.

Why

The /unslop audit of mobile/ found the app mostly designed, with slop concentrated on Welcome and Replay plus leftover purple and label styling. The welcome layout follows a reference the owner supplied.

How it was verified

  • npm run lint, npm run typecheck, npm test (59 files, 509 tests) and sync:core --check all pass in mobile/. The revoke invite confirmation and admin invites UI tests pass locally with the fixture fix.
  • New tests compile the mesh shader under real Skia (CanvasKit), check that its lines land on exact device pixels, and cover the art-loading fallbacks, the Welcome screen, Replay's artist tiles and the chart's peak.
  • Real Welcome components and real Replay and Settings components were rendered with react-native-web and CanvasKit in Chromium, in dark and light for Welcome and Replay and on several phone sizes for Welcome, and checked by eye. The full ReplayScreen wouldn't mount in that harness, so its wiring is covered by the unit tests only.

Not verified: nothing has run on an iOS device or simulator, including the shader through RN Skia's native runtime, Liquid Glass surfaces, and SF Symbols, which were placeholders in the harness. Please check it on a phone.

🤖 Generated with Claude Code

githubesson and others added 3 commits November 3, 2026 02:49
Signed-out users now land on a record sliding out of its sleeve among the
clouds, drawn through a pixel mesh, with the headline, one primary action and
one quiet link below it. It replaces the bubble parade, its purple glow and the
hopping title. The scene is night in dark mode and morning in light mode.

The art is rendered by scripts/render-welcome-art.py and the mesh is a Skia
shader, so its lines land on whole device pixels on every phone. If Skia can't
read the art or compile the shader, the plain image shows instead.

The auth screens' primary buttons fill with the text color, and their titles
stop at weight 600.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Color: purple now only means Favorites. The Favorites header loses its wash,
swipe-to-favorite matches the tab's purple, and the account avatar is flat.
Replay's chart and genre bars are neutral with one accent on the busiest bucket
and top genre. Quiet rows stop using the accent.

Type: no uppercase tracked labels, weights stop at 600, nothing is under 11pt.
The Favorites large title keeps 700 to match native large titles.

Icons: the waveform replaces sparkles, since nothing here is AI.

Spacing and shape: off-grid values move onto the 4pt grid, cards share a 16
radius and padding, and primary and secondary buttons share a 48pt height.

Copy: labels use sentence case, `...` becomes an ellipsis, one-sentence captions
lose their period, and filler eyebrows and repeated figures are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A TIDAL-only artist has no library page, but the tile always opened one. It now
follows core's topArtistAction like desktop: open the page if there is one, else
play their top tracks, else do nothing. Tiles show a cover from the artist's top
tracks instead of a random color, with a person glyph when there's none.

Also drops Replay's filler eyebrows, in the same file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-11-03T02:49:34.446886Z
We couldn’t complete this review. Comment @codex review to try again.
c2a4837 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 112 files, which is 12 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1241456b-db57-4c99-a339-ebe9e9c64cc9
Commits

Reviewing files that changed from the base of the PR and between 402462a and abf0969.

Files ignored due to path filters: 4
  • mobile/assets/images/welcome-morning.jpg is excluded by !**/*.jpg
  • mobile/assets/images/welcome-night.jpg is excluded by !**/*.jpg
  • mobile/assets/images/welcome-record.png is excluded by !**/*.png
  • mobile/package-lock.json is excluded by !**/package-lock.json
Files selected for processing: 112
  • frontend/tests/ui/fixtures.ts
  • mobile/app/(auth)/login.tsx
  • mobile/app/(auth)/register.tsx
  • mobile/app/(auth)/reset-password.tsx
  • mobile/app/(auth)/welcome.tsx
  • mobile/app/(tabs)/(favorites)/_layout.tsx
  • mobile/app/(tabs)/(favorites)/index.tsx
  • mobile/app/(tabs)/(library,browse)/_layout.tsx
  • mobile/app/(tabs)/(library,browse)/albums/[id].tsx
  • mobile/app/(tabs)/(library,browse)/albums/edit.tsx
  • mobile/app/(tabs)/(library,browse)/artists/[id].tsx
  • mobile/app/(tabs)/(library,browse)/index.tsx
  • mobile/app/(tabs)/(library,browse)/tidal-albums/[id].tsx
  • mobile/app/(tabs)/(library,browse)/tidal-artists/[id].tsx
  • mobile/app/(tabs)/(library,browse)/track/[id].tsx
  • mobile/app/(tabs)/(library,browse)/track/edit.tsx
  • mobile/app/(tabs)/(library,browse)/upload.tsx
  • mobile/app/(tabs)/(playlists)/[id].tsx
  • mobile/app/(tabs)/(playlists)/_layout.tsx
  • mobile/app/(tabs)/(playlists)/edit/[id].tsx
  • mobile/app/(tabs)/(playlists)/index.tsx
  • mobile/app/(tabs)/(settings)/_layout.tsx
  • mobile/app/(tabs)/(settings)/admin-invites.tsx
  • mobile/app/(tabs)/(settings)/admin-library.tsx
  • mobile/app/(tabs)/(settings)/admin-new-invite.tsx
  • mobile/app/(tabs)/(settings)/admin-tidal.tsx
  • mobile/app/(tabs)/(settings)/download-log.tsx
  • mobile/app/(tabs)/(settings)/downloads.tsx
  • mobile/app/(tabs)/(settings)/replay.tsx
  • mobile/app/now-playing.tsx
  • mobile/app/playlist-picker.tsx
  • mobile/app/share-track.tsx
  • mobile/components/add-confirmation/add-confirmation-overlay.tsx
  • mobile/components/add-confirmation/store.ts
  • mobile/components/album-header.tsx
  • mobile/components/artist/artist-hero.tsx
  • mobile/components/auth/bouncing-title.tsx
  • mobile/components/auth/bubble-parade.tsx
  • mobile/components/auth/motion.ts
  • mobile/components/auth/welcome-art.ts
  • mobile/components/auth/welcome-hero.tsx
  • mobile/components/buttons.tsx
  • mobile/components/dock/dock-mini-player.tsx
  • mobile/components/eyebrow.tsx
  • mobile/components/favorites/favorites-list-header.tsx
  • mobile/components/favorites/favorites-list.tsx
  • mobile/components/favorites/mode-wash.tsx
  • mobile/components/form-field.tsx
  • mobile/components/library/browse-links-card.tsx
  • mobile/components/library/ranked-track-row.tsx
  • mobile/components/library/search-results.tsx
  • mobile/components/library/welcome-card.tsx
  • mobile/components/now-playing/hero-meta.tsx
  • mobile/components/now-playing/lyrics-language-selector.tsx
  • mobile/components/now-playing/lyrics-section.tsx
  • mobile/components/now-playing/queue-row.tsx
  • mobile/components/now-playing/queue-section.tsx
  • mobile/components/ota-updates.tsx
  • mobile/components/playback-device-button.tsx
  • mobile/components/playlist-picker/picker-row.tsx
  • mobile/components/playlist-picker/search-field.tsx
  • mobile/components/playlist-picker/track-card.tsx
  • mobile/components/playlists/playlist-cover-field.tsx
  • mobile/components/playlists/playlist-detail-header.tsx
  • mobile/components/primitives.tsx
  • mobile/components/remote-control-indicator.tsx
  • mobile/components/replay/activity-chart.tsx
  • mobile/components/replay/genre-list.tsx
  • mobile/components/replay/period-picker.tsx
  • mobile/components/replay/ranked-shelf-tile.tsx
  • mobile/components/replay/replay-action-button.tsx
  • mobile/components/replay/replay-empty-state.tsx
  • mobile/components/replay/replay-hero.tsx
  • mobile/components/replay/summary-grid.tsx
  • mobile/components/section.tsx
  • mobile/components/settings/account-card.tsx
  • mobile/components/settings/appearance-tile.tsx
  • mobile/components/settings/device-card.tsx
  • mobile/components/settings/lastfm-row.tsx
  • mobile/components/settings/replay-row.tsx
  • mobile/components/settings/settings-card.tsx
  • mobile/components/settings/smooth-mix-tile.tsx
  • mobile/components/share/share-action-button.tsx
  • mobile/components/share/share-panel.tsx
  • mobile/components/share/snippet-panel.tsx
  • mobile/components/share/story-background-crop-editor.tsx
  • mobile/components/share/story-share-menu-button.tsx
  • mobile/components/share/track-header.tsx
  • mobile/components/shelf-tile.tsx
  • mobile/components/swipe/favorite-mark.tsx
  • mobile/components/swipe/removal-strip.tsx
  • mobile/components/swipe/swipe-action.tsx
  • mobile/components/swipe/swipeable-track-row.tsx
  • mobile/components/track-actions-menu.tsx
  • mobile/components/track-info/info-grid.tsx
  • mobile/components/track-info/player-hero.tsx
  • mobile/lib/welcome-mesh.ts
  • mobile/package.json
  • mobile/scripts/render-welcome-art.py
  • mobile/tests/playlist-picker-screen.test.tsx
  • mobile/tests/queue-section.test.tsx
  • mobile/tests/replay-activity-chart.test.tsx
  • mobile/tests/replay-artist-tiles.test.tsx
  • mobile/tests/search-failures.test.tsx
  • mobile/tests/shelf-tile.test.tsx
  • mobile/tests/swipe-actions.test.ts
  • mobile/tests/tidal-album-versions.test.tsx
  • mobile/tests/track-info-screen.test.tsx
  • mobile/tests/welcome-hero.test.tsx
  • mobile/tests/welcome-mesh.test.ts
  • mobile/tests/welcome-screen.test.tsx
  • mobile/theme/theme.tsx

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

githubesson and others added 3 commits November 3, 2026 03:00
- Clamp the welcome art, so cells cut off by the screen's edge stay opaque.
- Drop the sampling prop on the art. RN Skia 2.6.2 reads its values as cubic
  coefficients, and leaving it out takes the same path.
- A shelf tile with nothing to do is plain, not "dimmed" for VoiceOver.
- Finish the labels: "Auto-download new tracks" and "New playlist".
- Finish the weights: lyric section labels and the language selector stop at 600.
- Declare canvaskit-wasm, which the mesh test imports directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fixture's only active invite expired on 2026-11-01, so /admin/invites showed
no Revoke button and "revoke invite confirmation" failed on every viewport, on any
branch. Its expiry now sits far in the future.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
If the phone switched between light and dark while Welcome was up, the old scene
drew with the new scheme's colors until the new one decoded, then snapped in. The
hero now draws nothing until the new scene is ready, and that scene fades in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@githubesson
githubesson merged commit 38cac55 into main Nov 3, 2026
10 checks passed
@githubesson
githubesson deleted the mobile/unslop branch November 3, 2026 03:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant