Skip to content

feat: Adding bleed option to SpriteBatch#3871

Draft
erickzanardo wants to merge 8 commits intomainfrom
feat/bleed-in-spritebatch
Draft

feat: Adding bleed option to SpriteBatch#3871
erickzanardo wants to merge 8 commits intomainfrom
feat/bleed-in-spritebatch

Conversation

@erickzanardo
Copy link
Copy Markdown
Member

@erickzanardo erickzanardo commented Mar 23, 2026

Description

Adds a bleed parameter to SpriteBatch.add() and SpriteBatch.addTransform() that slightly expands the rendered sprite beyond its source boundaries in all directions. This prevents seam artifacts (visible lines between tiles) that appear when texture filtering samples neighbouring pixels at tile edges in tilemaps.

How it works

  • Atlas path (useAtlas = true, default): applies a uniform scale to the RSTransform via _computeBleedTransform, keeping the sprite centre fixed in world space. A uniform scale using max(bleedScaleX, bleedScaleY) is used to preserve rotation; for non-square source rects the shorter axis is scaled slightly beyond the requested bleed value.
  • Non-atlas path (useAtlas = false / web fallback): expands BatchItem.destination by bleed pixels in every direction. This always expands by exactly bleed pixels on every side, regardless of aspect ratio.

For best results, the atlas should include padding between sprites.

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

Addresses seam/ghost-line artifacts commonly reported when using SpriteBatch for tilemaps.

@erickzanardo erickzanardo marked this pull request as draft March 23, 2026 00:13
Comment thread packages/flame/lib/src/sprite_batch.dart
Comment on lines +325 to +327
if (bleed == 0) {
return transform;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (bleed == 0) {
return transform;
}
if (bleed <= 0) {
return transform;
}

Comment on lines +334 to +335
final scos = transform.scos * scaleX;
final ssin = transform.ssin * scaleY;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not scale by x or y but by math.max of either so we can preserve rotation (and ensure scale happens uniformly even if width and height are not equal).

And then the tx and ty should be multiplied by the scos and ssin (subtract for tx, addition for ty). That should keep the centerr fixed to bleed across the borders when we are dealing with rotation

@spydon
Copy link
Copy Markdown
Member

spydon commented May 8, 2026

Any update on this @erickzanardo ?

spydon and others added 3 commits May 9, 2026 13:49
…ng path

Bleed was only applied via _computeBleedTransform for the drawAtlas path.
The non-atlas (web fallback) path used batchItem.destination which was
always set to Offset.zero & source.size, ignoring bleed entirely.

Now BatchItem expands its destination rect by the bleed amount in each
direction when bleed > 0, so drawImageRect in the fallback path also
renders the sprite slightly larger to prevent edge seams. The replace()
method is updated to recalculate destination when the source changes.
- Zero-size source guard in _computeBleedTransform to prevent Infinity/NaN
- Convert BatchItem.matrix lazy field to nullable+getter so replace() can
  invalidate it when source or transform changes, fixing stale matrix bug
  in the non-atlas render path
- Use original source rect (not bleed-expanded destination) for the
  background color drawRect in the non-atlas path, matching atlas path
  behaviour
- Fix wording of transform/rotation comment in _computeBleedTransform
- Document the non-square uniform-scale trade-off in bleed docstrings
- Document that bleed cannot be changed via replace()
- Add tests: negative bleed assertion, non-square atlas scale behaviour,
  non-square non-atlas exact expansion, zero-size source guard, matrix
  invalidation after replace(transform) and replace(source)
- Add CHANGELOG entry
- Fill in PR description and checklist
- Fix trailing whitespace in example description string
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.

3 participants