Repository navigation
Conversation
VoiceAssistantStatusBar mounts VoiceBars only while the assistant is speaking, so the effect's else branch never ran for an unmount and the three Animated.loop chains kept going. On web RNW's Animated uses the JS driver: each loop is a requestAnimationFrame chain that restarts forever (iterations: -1), leaking three 60 fps loops, their closures and Animated.Values per speech turn for the life of the tab. Stop the bars in the effect cleanup; the else branch stays for the mounted case. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Every native ShimmerText ran its own infinite withRepeat loop, one per visible thinking row, for as long as the row stayed on screen. The progress value now lives in a module-level makeMutable shared by all instances: the first mount starts the loop, the last unmount cancels it, each useAnimatedStyle just reads the shared value. Web is untouched (Metro resolves ShimmerText.web.tsx there, which is a pure CSS shimmer). Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two animation loops that outlive the component that started them.
VoiceBars(sources/components/VoiceBars.tsx) starts threeAnimated.loopchains in an effect whose else branch stops them whenisActiveturns false.VoiceAssistantStatusBarmounts the component only while the assistant is speaking, so on unmount the else branch never ran and the loops were never stopped. On web react-native-web'sAnimateduses the JS driver, where each loop is arequestAnimationFramechain that restarts forever (iterations: -1): every speech turn leaked three 60 fps rAF loops, their closures andAnimated.Values for the life of the tab. The effect now returns a cleanup that callsstopAnimation()on the three values; the else branch is kept for the mounted case.ShimmerText(sources/components/ShimmerText.tsx, the native implementation) ran one infinitewithRepeatloop per instance, one per visible thinking row for as long as the row stayed on screen. The sweep progress now lives in a single module-levelmakeMutableshared value created lazily (not at import time): the first mounted instance starts the loop, the last one to unmount cancels it (ref-counted), and eachuseAnimatedStylejust reads the shared value. Same shape as the shared elapsed-time ticker in #1776. Web is untouched: Metro resolvesShimmerText.web.tsxthere, a pure CSS shimmer, so this part only affects native.Related: #1796 (StatusDot pulse
cancelAnimationon unmount) and #1798 (ShimmerView repeatcancelAnimationon unmount) are the same family of animations left running after unmount.Changes
Animated.loopchains in the effect cleanup so a conditional unmount cannot leave them runningmakeMutablesweep value instead of onewithRepeatloop per instanceTest plan
pnpm typecheck(clean)pnpm exec vitest run sources/hooks/useNavigateToSession.test.ts sources/hooks/useImagePicker.test.ts(37 passed)ShimmerText.web.tsx) and was not exercised on that deployment; it typechecks and follows the same start-on-first-mount / cancel-on-last-unmount pattern as perf(hooks): drive useElapsedTime from a single shared ticker #1776🤖 Generated with Claude Code