Skip to content

Rich text support for BitmapText - #7354

Open
skhoroshavin wants to merge 19 commits into
phaserjs:masterfrom
skhoroshavin:rich-bitmap-text
Open

Rich text support for BitmapText#7354
skhoroshavin wants to merge 19 commits into
phaserjs:masterfrom
skhoroshavin:rich-bitmap-text

Conversation

@skhoroshavin

@skhoroshavin skhoroshavin commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds opt-in rich text support to BitmapText: segmented rendering with each segment having its own font, size and color. Fully backward compatible - when the feature is unused, rendering is pixel-identical to the previous code path (proved by Playwright tests added from the very beginning of development). setText is untouched and stays plain-only.

Usage

var text = this.add.bitmapText(x, y, 'lato', '', 48);

text.addTextStyle('name',    { font: 'clarendon', color: 0xff6666 });
text.addTextStyle('item',    { color: 0x66ff66 });
text.addTextStyle('vehicle', { size: 72, color: 0xff8800 });

text.setRichText('[name]T-800:[/name] Give me your [item]clothes[/item], your [item]boots[/item] and your [vehicle]motorcycle[/vehicle].');

Programmatic alternative without markup:

text.setRichText([
    { text: 'T-800:', style: 'name' },
    { text: ' Give me your ' },
    { text: 'clothes', style: 'item' },
    { text: ' motorcycle', size: 72, color: 0xff8800 }   // inline overrides work too
]);

Feature set:

  • Named styles via addTextStyle(name, { font?, size?, color? }); styles without a font inherit the object's font
  • Markup syntax [style]...[/style] with [[ / ]] escapes; malformed markup warns and degrades gracefully
  • Per-segment fonts, kerning applies only within one font, not across segments
  • Baseline alignment across mixed fonts and sizes
  • Existing setCharacterTint (charColors) still takes precedence over style colors
  • Canvas renderer degrades to flat default-font text with a one-time console warning (Canvas has no tint support anywhere in Phaser; full rich rendering is WebGL-only)

Rich text rendered on WebGL

Notes for reviewers

When I conceived this feature initially, I hoped it wouldn't require serious refactorings, however it turned out GetBitmapTextSize was quite entangled, and in the end I had to basically rewrite it. Since backward compatibility was a top priority, I actually started with adding a set of screenshot-based tests, and only then moved on to actual implementation, moving in small steps, and making sure tests stay green. The whole process can be audited in the commit history.

Even though this PR looks huge (~2400 lines added), actual code changes are significantly smaller. Actual composition:

  • ~600 LoC: actual engine changes in src/, majority of which are purely additive, except GetBitmapTextSize function
  • ~150 LoC: new unit tests (mostly for markup parsing)
  • ~350 LoC: visual-test infrastructure and actual test html/js
  • ~1300 LoC: lato.xml and clarendon.xml BMFonts copied from Phaser examples - used in visual tests

Frankly speaking, I'm not fully happy with the current implementation, and have some ideas for how to unify setText and setRichText internal paths, but that would be a bigger refactoring with more changes in plain text code paths, so I'd like to discuss it with maintainers before actually implementing, either here or in a separate follow-up PR.

@rexrainbow

Copy link
Copy Markdown
Contributor

Is creating a third-party plugin a better option?

@skhoroshavin

Copy link
Copy Markdown
Contributor Author

@rexrainbow it could be, but it would duplicate quite a ton of logic from BitmapText. Actually we had this discussion about 1 month ago in discord, unfortunatelly I had some "life" in between, so I returned with draft impleentation only now.

@skhoroshavin
skhoroshavin marked this pull request as ready for review August 23, 2026 01:58
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.

2 participants