AccountBalanceChart.tsx:45-56UI threadfunction formatTooltipUsd(num) { "worklet"; … } — a hand-duplicated copy of formatNumberWithCommas
Quoted from the source: LineChart.PriceText's format prop "runs as a Reanimated worklet on the UI thread and cannot call the shared JS helper." So the helper was duplicated, with a comment saying why. Duplication is usually a smell; here it is the price of never crossing a thread to draw a label that moves with your finger.
The "worklet" directive is right there on line 2 of the function.
AccountBalanceChart.tsx:20-25JS threadCHART_MOUNT_DEFER_MS = 500, header mounts immediately
Quoted from the source: the LineChart path computation "is the single biggest main-thread cost on this screen; deferring past the animation window keeps the stagger clean." The entrance is 380 + 180ms. The chart waits 500ms and arrives after the animation it would otherwise have stuttered.
A mount gate, not an animation. It exists so that the animations next to it stay on the UI thread's schedule.
AccountBalanceChart.tsx:136-155UI threadEasing.out(Easing.cubic), 380ms · title at 0ms, balance at +90ms, range at +180ms · translateY 12 / 16 / 12 → 0
A decelerate cubic and escalating 90ms delays make the card assemble top to bottom. The balance travels 16px rather than 12 — it is the hero, so it gets the longer arrival.
Three worklets, scheduled from a useFocusEffect on the JS thread.
AccountBalanceChart.tsx:136 → useAnimFrameTrace.tsUI threadanimTrace.start(620) — a UI-thread frame sampler sized to the 560ms stagger
Quoted from the source: Reanimated animations run on the UI thread, so a JS rAF loop cannot see UI-thread jank. useFrameCallback runs on the UI thread and reports the platform choreographer timestamp. The jank is measured on the thread the animation runs on.
The frame callback is itself a worklet. Only the summary log crosses to JS.
Sheet.tsx:27-30, 220-235UI threadwithTiming(DEFAULT_Y, { duration: 260, easing: Easing.out(Easing.cubic) })
Not a spring. A spring overshoots past the home indicator; ease-out-cubic decelerates into rest instead of arriving and correcting, which is what a physical panel sliding to a stop actually does.
useAnimatedStyle worklet; the JS thread seeds the shared value once.
SHEET_CLOSE_SETTLE_MS = 280 — unmount deferred until the slide settles
Quoted from the source: "unmount only after the slide settles, otherwise the modal vanishes mid-animation and the dismiss reads as a snap."
A timing constant, not an animation. It exists to stop React winning a race against the compositor.