feat(money): tilt-driven parallax on Money onboarding card (MUSD-1048)#32892
Conversation
Add a subtle, tilt-driven parallax animation to the "Fund your account" onboarding card on the Money home screen, driven by a Rive graphic whose layers respond to device orientation. - MoneyNextBestActionParallax renders the Rive "Parallax Block 1" artboard with data-bound xValue/yValue, a gradient background behind the transparent artboard, and a static-image fallback (feature flag / reduce-motion / error). - useDeviceOrientation derives absolute pitch/roll from the accelerometer with a natural-hold neutral (drift-free); the pure accelerationToTilt is unit-tested. - StepperCard gains an optional media slot so the graphic replaces the static step image without affecting other consumers. - Gate behind selectMoneyParallaxAnimationEnabledFlag.
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
The tilt-driven parallax on the Money onboarding card doesn't need a kill-switch — reduce-motion and the Rive-error fallback already provide graceful degradation. Remove selectMoneyParallaxAnimationEnabledFlag and its usage/tests; animation now gates solely on reduce-motion and Rive load errors.
The Rive file carries a second card artboard for the "Get MetaMask card"
onboarding step. Parameterize MoneyNextBestActionParallax with an artboardName
prop and render the appropriate block per step:
- PARALLAX_ARTBOARD_FUND ("Parallax Block 1") for step 1 (Fund your account)
- PARALLAX_ARTBOARD_CARD ("Parallax Block 2") for step 2 (Get MetaMask card),
shared across both step-2 variants
Block 3 is the 786x1704 full-screen reference artboard and is not used in-app.
The gradient background is shared (step 2 uses the same indigo-to-blue).
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 4 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 89aebb7. Configure here.
- Re-add selectMoneyParallaxAnimationEnabledFlag gating so Rive/accelerometer work only runs when the flag is on (falls back to the static image otherwise). - Default useReduceMotion to true so reduce-motion users never briefly see the animation before the async accessibility check resolves. - Guard applyTilt on the Rive instance before driving the view-model setters. - Restore full-size (w-full aspect-video) sizing to the static fallback branch so the image fills the stepper slot as before. - Mock MoneyNextBestActionParallax in MoneyHomeView tests; rendering the real Rive graphic pulled in device sensors that the unit-test env stubs out.
Add the parallax animation flag to the feature-flag registry so the CI registry check passes. Not yet in prod (inProd: false).
| * Optional custom media rendered in the image slot in place of `image` | ||
| * (e.g. an animated graphic). Falls back to `image` when not provided. | ||
| */ | ||
| media?: ReactNode; |
There was a problem hiding this comment.
I don't see the media being rendered in the StepperCard. It's only being used as a condition. Is that intended?
There was a problem hiding this comment.
not as a condition, but as a ??, so if media exists, it will use it, otherwise fallback to Image
| @@ -0,0 +1,132 @@ | |||
| import React, { useCallback, useState } from 'react'; | |||
There was a problem hiding this comment.
If you haven't already it would be worth creating a Testflight build via GH action to see how it responds on iOS. I noticed for the first time deposit animation that iOS and Android flipped the y-axis. Not a big problem tbh it's just something I didn't know until I tested on both.
There was a problem hiding this comment.
I don't have TF access, but will ask @shane-t to take a look if he has time
There was a problem hiding this comment.
We should get you access to TestFlight. When you get a sec can you ping the mobile-platform team in #metamask-mobile-dev and request to be added to the internal tester group? Seats are limited but we should still have room.
| source={NextBestActionParallaxAnimation} | ||
| artboardName={artboardName} | ||
| dataBinding={AutoBind(true)} | ||
| fit={Fit.Contain} |
There was a problem hiding this comment.
Non-blocking: I think Fit.Contain can sometimes aggressively shrink the Rive animation on different devices. I'm not a Rive expert but I think fit={Fit.Layout} is meant to be more responsive (as long as the animation file is leveraging responsive layout).
- Gate all accelerometer setup (interval + device-memory read) on `enabled`, so no sensor work happens when the flag is off or reduce-motion is on. - Default the parallax flag to off (opt-in): the local fallback now requires MM_MONEY_PARALLAX_ANIMATION_ENABLED="true", matching the registry's productionDefault of false, so the feature stays disabled unless explicitly on. - Document MM_MONEY_PARALLAX_ANIMATION_ENABLED in .js.env.example.
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsE2E Test Selection:
The changes are entirely within the Money/Card feature area. The StepperCard component is only imported by MoneyOnboardingCard (confirmed via importers search). The feature is off by default in production. The E2E test Performance Test Selection: |
|




Description
Adds a subtle, tilt-driven parallax animation to the "Fund your account" onboarding card on the Money home screen (part of the MUSD-1048 motion work).
The card graphic is a Rive animation (
Parallax Block 1artboard) whose layers respond to device orientation via data-boundxValue/yValue:MoneyNextBestActionParallaxrenders the Rive artboard with a gradient background behind the transparent artboard, and degrades gracefully to the existing static step image when the feature flag is off, reduce-motion is enabled, or Rive fails to load.useDeviceOrientationderives absolute pitch/roll from the accelerometer with a natural-hold (~45°) neutral, so it is drift-free and centred when the phone is held normally. The angle math (accelerationToTilt) is a pure, unit-tested function.StepperCardgains an optionalmediaslot so the animated graphic replaces the static step image without affecting any other consumer.selectMoneyParallaxAnimationEnabledFlag(version-gated remote flag with a local env fallback), and respects OS reduce-motion.Changelog
CHANGELOG entry: Added a subtle tilt-driven parallax animation to the Money "Fund your account" onboarding card.
Related issues
Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-1048
Manual testing steps
Screenshots/Recordings
Before
Static "Fund your account" card image (no motion).
After
IMG_4300.MOV
IMG_4299.MOV
Screen recording on a physical Android device to be attached.
Pre-merge author checklist
Performance checks (if applicable)
trace()for usage andaddTokenfor an exampleFor performance guidelines and tooling, see the Performance Guide.
Pre-merge reviewer checklist
Note
Low Risk
Opt-in UI motion with static fallbacks, accessibility reduce-motion, and no changes to money/account logic; main risk is accelerometer/Rive battery or perf on low-end devices, mitigated by throttling and feature gating.
Overview
Adds tilt-driven Rive parallax to Money onboarding StepperCard steps (fund + card), gated by
selectMoneyParallaxAnimationEnabledFlag(earnMoneyParallaxAnimationEnabledremote +MM_MONEY_PARALLAX_ANIMATION_ENABLEDenv, default off).StepperCardnow accepts optionalmediato replace the step image.MoneyOnboardingCardwiresMoneyNextBestActionParallaxper step artboard, with static PNG fallbacks.MoneyNextBestActionParallaxplaysnext_best_action_module_v1.riv, maps device tilt to RivexValue/yValue, and falls back when the flag is off, reduce motion is on, or Rive errors.useDeviceOrientation(accelerometer, low-pass, 30/60 Hz on low-end devices) anduseReduceMotionsupport that path.Registry entry for
earnMoneyParallaxAnimationEnabledand broad unit tests; parent tests mock the parallax component.Reviewed by Cursor Bugbot for commit 7df7e3c. Bugbot is set up for automated code reviews on this repo. Configure here.