Skip to content

perf: gallery virtualization#3675

Merged
isekovanic merged 2 commits into
developfrom
perf/gallery-scalability
Jun 23, 2026
Merged

perf: gallery virtualization#3675
isekovanic merged 2 commits into
developfrom
perf/gallery-scalability

Conversation

@isekovanic

Copy link
Copy Markdown
Contributor

🎯 Goal

Our image gallery was never properly virtualized and mounted one slide component per asset for all loaded media (assets.map(...)), so scroll/swipe jank scaled with the asset count. On a media heavy channel roughly 40% of frames were janky, driven by O(N) animated style worklets rerunning on the UI thread every frame. This bounds that cost so gallery performance no longer degrades as channels accumulate media. This was relatively fine before, when ChannelDetails hadn't been introduced yet but now poses an actual challenge.

🛠 Implementation details

  • Extracted the slide list into a windowed GalleryPager that mounts only the slides within PAGER_WINDOW_RADIUS of the current index, instead of all N. Mounted slides drop from ~N to ~9.
  • A single leading spacer reproduces the flex width of the skipped slides, so the rendered slides keep their exact natural positions. The per slide transforms (useAnimatedGalleryStyle) are a pure function of index + flex position, so windowing the mount should be fine
  • GalleryPager subscribes to currentIndex itself, so paging rerenders only the small slide list, never the parent (gesture objects/GestureDetector stay stable).
  • The existing per slide shouldRender load gate is retained (image +-3, video +-1) for now so windowing bounds the mount; shouldRender still bounds content load (notably capping live native video players within the mounted set).

Measured on a debug SampleApp (on a media heavy channel), provided below are the results (naturally, taken from the best 5 runs against baseline and the worst 5 runs against this branch across of many, many runs):

Metric Before After Improvement
Janky frames 40.4% 14.1% −65% (−26 pts)
Median frame time 42 ms 21 ms 2× faster (−50%)
90th-pct frame time 79 ms 46 ms −42%
95th-pct frame time 95 ms 67 ms −29%
99th-pct frame time 150 ms 133 ms −11%
Missed vsyncs 154 57 2.7× fewer (−63%)
Frames rendered (same path) 856 1,039 +21% throughput
Mounted slide components ~165 ~9 ~18× fewer

Jank no longer scales with asset count (after jank is flat across N, where before it rose).

🎨 UI Changes

iOS
Before After
Android
Before After

🧪 Testing

☑️ Checklist

  • I have signed the Stream CLA (required)
  • PR targets the develop branch
  • Documentation is updated
  • New code is tested in main example apps, including all possible scenarios
    • SampleApp iOS and Android
    • Expo iOS and Android

@isekovanic isekovanic requested review from oliverlaz and szuperaz June 23, 2026 12:50
Comment thread .claude/skills/perf-benchmarking/SKILL.md

@oliverlaz oliverlaz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥 🔥 🔥

Comment thread perf/drive-gallery-scenario.sh
@Stream-SDK-Bot

Copy link
Copy Markdown
Contributor

SDK Size

title develop branch diff status
js_bundle_size 1959 KB 1960 KB +759 B 🔴

@isekovanic isekovanic merged commit ab2b956 into develop Jun 23, 2026
8 of 10 checks passed
@isekovanic isekovanic deleted the perf/gallery-scalability branch June 23, 2026 14:07
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.

3 participants