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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions