From ScrollSpy Assistant
Optimizes Flutter scroll_spy performance by diagnosing rebuild storms and guiding subscription choices (ScrollSpyItem vs Lite, listeners, snapshots).
How this skill is triggered — by the user, by Claude, or both
Slash command
/scroll-spy:optimize-scroll-spy-performanceThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Get the cost model right first: the engine's compute pass is tens of
Get the cost model right first: the engine's compute pass is tens of microseconds even with hundreds of mounted items (O(1) cached arithmetic per item on the hot path, allocation-free, no render-tree walks). Measurable scroll cost in an app almost always comes from widget rebuilds you subscribed to, not from the engine. Optimize subscriptions, not the engine.
ScrollSpyPrimaryListener, ScrollSpyItem*Listener):
side effects with zero rebuilds. Correct for play/pause, analytics,
haptics, prefetch.ScrollSpyItemLite,
ScrollSpyItem{Primary,Focused,Visible}Builder): rebuild only when a
flag flips. Correct for highlights, badges, borders.ScrollSpyItem, ScrollSpyItemFocusBuilder):
rebuild whenever metrics drift past tolerance, which during scrolling
means nearly every frame. Reserve for items that genuinely animate from
focusProgress/visibleFraction.controller.snapshot, ScrollSpySnapshotBuilder):
notifies every compute pass and materializes the full immutable frame.
One dashboard-style consumer at most; never one per item.The engine bills only for what is consumed: with no snapshot listeners no snapshot is materialized; per-item notifiers are created lazily, updated diff-only, and auto-evicted. An unheard signal costs nothing, so the win comes from moving consumers down this ladder, not from removing scroll_spy.
ScrollSpyItem whose builder only uses isPrimary/
isFocused to ScrollSpyItemLite.child:; the builder wraps
child and never reconstructs the card. Confirm the static part is
genuinely const/stable.setState.snapshot listeners; threshold scans (impressions) use one
snapshot listener for the whole screen, or per-item boolean listeners.debug: false and includeItemRectsInFrame unset in release paths
(rect capture allocates per item per pass; debug frames are gated but the
overlay itself repaints).perFrame is not a CPU problem; but if metric
subscriptions (ladder rung 3) must exist and flings rebuild too much, use
ScrollSpyUpdatePolicy.hybrid(ballisticInterval: 50ms) to throttle
ballistic recomputes, or onScrollEnd when only settled state matters.
These change semantics (staleness mid-scroll), so state the tradeoff.
Store non-const policies in fields (no ==; inline construction churns
engine config every rebuild).ScrollSpyRegion.custom allocates
by design.flutter run --profile).debugPrint in one item builder or use
DevTools "Track widget builds"; with the ladder applied, boolean items
rebuild only on flips (a handful per scroll), never per frame.ScrollSpyItemLite.
Its own perf regression test (test/perf/compute_pass_benchmark_test.dart
in the package repo) documents expected compute-pass magnitudes.Report what moved down the ladder, before/after frame times or rebuild counts, and any semantic tradeoffs (update policy changes).
Guides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.
Dispatches multiple subagents concurrently for independent tasks without shared state. Use when facing 2+ unrelated failures or subsystems that can be investigated in parallel.
npx claudepluginhub omar-hanafy/scroll_spy --plugin scroll-spy