Description
When an OpacityEffect runs on a TextComponent whose TextPaint style defines shadows, the glyph color fades but the shadows keep their original alpha. The shadows stay at full strength for the whole animation, so a fading text leaves a non-fading shadow or glow behind, which reads as a visual glitch.
There is also a related gotcha in the same code path: the first time the effect updates the paint, the style's fill color is replaced entirely by the component's HasPaint paint (white by default), so a colored text visibly snaps to white when the fade begins unless the user remembers to seed paint.color with the same color as the style.
Cause
TextComponent.onChanged applies opacity through TextRenderer.copyWithPaint, and TextPaint.copyWithPaint only swaps the style's foreground:
@override
TextRenderer copyWithPaint(Paint paint) {
return copyWith(
(style) {
return style.copyWith(
foreground: paint,
);
},
);
}
style.shadows is left untouched, so shadow alpha never follows the component's opacity.
Steps to reproduce
final text = TextComponent(
text: '+1 kr',
textRenderer: TextPaint(
style: const TextStyle(
color: Color(0xFF2E9940),
shadows: [Shadow(color: Color(0x99FFFFFF), blurRadius: 4)],
),
),
)..add(OpacityEffect.fadeOut(EffectController(duration: 1)));
Expected behavior
The text and its shadows fade out together, in the text's own color.
Actual behavior
The text snaps to white when the effect starts (foreground paint replaces the style color) and fades, while the white shadow stays at constant alpha until the component is removed.
Suggested fix
In TextPaint.copyWithPaint, scale each shadow's color alpha by the incoming paint's alpha (and consider multiplying the paint color into the existing style color instead of replacing it, so OpacityEffect composes with a styled color the way it does for sprites).
Observed on the perf/component-set-backing branch, but the copyWithPaint implementation is the same on main.
Description
When an
OpacityEffectruns on aTextComponentwhoseTextPaintstyle definesshadows, the glyph color fades but the shadows keep their original alpha. The shadows stay at full strength for the whole animation, so a fading text leaves a non-fading shadow or glow behind, which reads as a visual glitch.There is also a related gotcha in the same code path: the first time the effect updates the paint, the style's fill color is replaced entirely by the component's
HasPaintpaint (white by default), so a colored text visibly snaps to white when the fade begins unless the user remembers to seedpaint.colorwith the same color as the style.Cause
TextComponent.onChangedapplies opacity throughTextRenderer.copyWithPaint, andTextPaint.copyWithPaintonly swaps the style'sforeground:style.shadowsis left untouched, so shadow alpha never follows the component's opacity.Steps to reproduce
Expected behavior
The text and its shadows fade out together, in the text's own color.
Actual behavior
The text snaps to white when the effect starts (foreground paint replaces the style color) and fades, while the white shadow stays at constant alpha until the component is removed.
Suggested fix
In
TextPaint.copyWithPaint, scale each shadow's color alpha by the incoming paint's alpha (and consider multiplying the paint color into the existing style color instead of replacing it, soOpacityEffectcomposes with a styled color the way it does for sprites).Observed on the
perf/component-set-backingbranch, but thecopyWithPaintimplementation is the same onmain.