Skip to content

Per-glyph effect hook for BitmapText (batched vertex offset + tint) #1522

Description

@obiot

Summary

Add a per-glyph effect hook to BitmapText (and ideally Text) so callers can offset/tint individual glyphs — wave, shake, per-glyph colour, per-glyph reveal — applied within the existing batched draw, not by splitting the string into N renderables.

Motivation

There's no per-glyph access today. To animate individual letters (the classic RPG "wavy text", shake-on-hit, rainbow, per-glyph typewriter) you must hand-roll one BitmapText/Text per character plus a Container — N draws, N renderables, per-frame bounds churn. The text example does exactly this (WavyText helper).

BitmapText already lays out and batches every glyph in a single draw. A per-glyph hook could offset each glyph's quad vertices (and apply a per-glyph tint via the per-vertex colour) inside that same batch, so an animated 100-char line stays ~1 draw call with zero extra objects. That is both more capable and dramatically cheaper than any userland helper — which is the main argument for doing it in-engine.

Proposed API (sketch)

A per-glyph callback invoked during layout/draw, receiving the glyph context and a reused, mutable output:

text.glyphEffect = (out, ctx) => {
  // ctx: { index, char, code, time, x, y }
  out.offsetY = Math.sin(ctx.time * 0.008 + ctx.index * 0.6) * 6; // wave
  // out.offsetX / out.scale / out.rotation / out.tint?.setColor(...) optional
};
  • out is a reused scratch (zero-alloc steady state).
  • Unset → the lean batched path is unchanged (no per-call cost).
  • The batcher applies the offset to each glyph's vertices and the tint to its per-vertex colour during the existing flush.

Open design questions

  • Scope to BitmapText first (WebGL batched path). Text rasterises the whole string to one texture, so per-glyph there is harder — likely a slower fallback or out of scope.
  • Callback vs a small declarative preset registry (wave / shake / rainbow), à la Godot's RichTextLabel effects.
  • Alternatively (or additionally) expose read-only glyph layout (positions) so callers can drive their own rendering.

Out of scope

Full BBCode / markup rich-text parsing. This ticket is just the per-glyph transform/tint primitive; presets and markup can build on it later.

References

  • The text example's WavyText helper — the userland workaround this would replace (N renderables → batched).
  • Godot RichTextLabel effects (wave/shake/rainbow + custom) as prior art.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions