Skip to content

fix: Apply opacity to text shadows and keep the style color of TextComponent - #4043

Draft
spydon wants to merge 1 commit into
mainfrom
fix/text-component-opacity-shadows
Draft

fix: Apply opacity to text shadows and keep the style color of TextComponent#4043
spydon wants to merge 1 commit into
mainfrom
fix/text-component-opacity-shadows

Conversation

@spydon

@spydon spydon commented Sep 8, 2026

Copy link
Copy Markdown
Member

Description

When an OpacityEffect ran on a TextComponent, TextPaint.copyWithPaint replaced the style's
foreground with the component's paint. That threw away the color defined in the TextStyle (the
text snapped to white when the effect started) and left the shadows at their original alpha, so a
fading text left a non-fading glow behind.

TextPaint.copyWithPaint now treats the component paint as a layer on top of the style. The opacity
of the paint scales the opacity of the text color, the shadows, the decoration color and the
background, and the paint's color filter, mask filter and shader are applied to the glyphs so
ColorEffect, tint and hue keep working. An existing foreground paint on the style, for
example stroked text, keeps its other properties instead of being thrown away. Only the opacity of
the paint color is used, which matches how sprites and every other renderer treat the paint color.

TextComponent keeps the renderer that was set on it: textRenderer always returns that renderer,
and the copy with the paint applied is the new internal paintedTextRenderer, derived again on
every paint change. Repeated opacity updates therefore never compound, and the pattern of reading
textRenderer, copying it with a change, and setting it back is safe after an effect has run.
Setting a new textRenderer while the paint has been changed applies the current paint to it right
away.

TextBoxComponent previously only picked up paint changes on its next redraw, which for a static
box never happened. It now draws its cached image with the component's paint, so opacity and color
filters apply to the whole box, including the background, without re-rendering the text. Its
onChanged is a no-op since the text does not need to be formatted again.

SpriteFontRenderer.copyWithPaint had the same class of bug: it dropped scale, letterSpacing
and the color filter set through fromFont(color:). It now keeps them and only multiplies in the
opacity. DebugTextRenderer in flame_test keeps its own color as well, and the contract is now
documented on the abstract TextRenderer.copyWithPaint.

Behavior notes: setColor on a text component no longer changes the text color, only its opacity,
since the paint color's RGB is ignored like it is for sprites; use ColorEffect or tint to color
text. Stroke settings on the component paint are no longer forwarded to the glyphs; set them on the
style's foreground instead.

Checklist

  • I have followed the Contributor Guide when preparing my PR.
  • I have updated/added tests for ALL new/updated/fixed functionality.
  • I have updated/added relevant documentation in docs and added dartdoc comments with ///.
  • I have updated/added relevant examples in examples or docs.

Breaking Change?

  • Yes, this PR is a breaking change.
  • No, this PR is not a breaking change.

Related Issues

Closes #4013

@spydon
spydon force-pushed the fix/text-component-opacity-shadows branch from 8ae253e to 8d51db4 Compare September 8, 2026 20:10
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.

TextComponent shadows are not affected by OpacityEffect

1 participant