every 200ms flush shifted all sliver indices (reverse list), and the
per-row ObjectKeys without findChildIndexCallback made the framework
deactivate and re-inflate every built row instead of moving it. add the
callback so elements move, and cache ChatMessage widget instances per
message (Expando) so unchanged rows skip build() entirely via the
identical-widget short-circuit. IRCMessage.renderRevision invalidates
rows the CLEARCHAT/CLEARMSG handlers mutate in place.
also decode emotes/badges at display size (memCacheHeight = logical
size x devicePixelRatio) instead of the CDN's 3x-4x intrinsic size:
several-fold less image memory and raster cost, animation preserved
(ResizeImage applies the target size to the whole codec).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>