@@ -85,7 +85,9 @@ import com.mikepenz.markdown.compose.components.markdownComponents
8585import com.mikepenz.markdown.m3.Markdown
8686import com.mikepenz.markdown.model.DefaultMarkdownAnnotator
8787import com.mikepenz.markdown.model.DefaultMarkdownAnnotatorConfig
88+import com.mikepenz.markdown.model.MarkdownAnimations
8889import com.mikepenz.markdown.model.MarkdownState
90+import com.mikepenz.markdown.model.markdownAnimations
8991import com.mikepenz.markdown.model.rememberMarkdownState
9092import org.intellij.markdown.MarkdownElementTypes
9193import org.intellij.markdown.ast.ASTNode
@@ -209,6 +211,21 @@ private fun MarkdownBody(
209211 }
210212 }
211213 val context = LocalContext.current
214+ // No-op [MarkdownAnimations] disables the library's [animateContentSize] wrapper applied
215+ // by [com.mikepenz.markdown.compose.elements.MarkdownText] via [MarkdownAnimations.animateTextSize].
216+ // That modifier triggers draw-phase remeasures through the nested SubcomposeLayout
217+ // (BasicText-with-links uses SubcomposeLayout for link hit-testing); during streaming and
218+ // during the Loading→Success state transition, these remeasures crash with an NPE in
219+ // AnimatedContentTransitionScopeImpl$ChildData.isTarget (an R8-rewritten frame throwing
220+ // NullPointerException). Overriding paragraph/heading components to [MarkdownTextNoAnim]
221+ // (which renders via [BasicText] directly) avoids the wrapper for those paths, but the
222+ // library's MarkdownText is still reached through the `text` component (bare TEXT nodes,
223+ // which appear during partial streaming parses), the `checkbox` component (GFM task lists),
224+ // and the inline-image path. Disabling animateTextSize globally closes all of them at once
225+ // — the size animation is decorative (only inline image placeholder→final size swaps), and
226+ // the crash it causes is a regression in the library's interaction with Compose's
227+ // SubcomposeLayout under streaming/recomposition bursts.
228+ val animations: MarkdownAnimations = markdownAnimations(animateTextSize = { this })
212229 // Intercept link taps so the scheme can be validated before the library fires an
213230 // implicit ACTION_VIEW. A hallucinated javascript:/file:/intent: URL must not launch
214231 // an unexpected intent chooser. Taps are routed to a dialog offering Open (only for
@@ -370,6 +387,7 @@ private fun MarkdownBody(
370387 modifier = modifier.semantics { liveRegion = LiveRegionMode.Polite },
371388 components = components,
372389 annotator = effectiveAnnotator,
390+ animations = animations,
373391 )
374392 }
375393 // A blinking caret at the end of a streaming reply gives a "live" typewriter feel.
@@ -393,6 +411,7 @@ private fun MarkdownBody(
393411 modifier = modifier.semantics { liveRegion = LiveRegionMode.Polite },
394412 components = components,
395413 annotator = effectiveAnnotator,
414+ animations = animations,
396415 )
397416 }
398417 }