GSoC 2026 Idea Discussion — Native Per-Character Text Animation for TextLayer

Hi everyone,

I’m currently exploring ideas for a potential GSoC 2026 proposal for Synfig and wanted to get some feedback from the community before developing the full proposal.

One thing I noticed while experimenting with text animation in Synfig Studio is that text is currently treated as a single object inside TextLayer. If you want to animate characters individually, it usually requires workarounds like plugins or manually splitting each letter into separate layers and offsetting them in time.

I’m considering a feature that would add native per-character animation support. The idea is to internally break the text into individual glyph elements (something like a TextGroupLayer containing per-character elements) so that each character could be animated independently.

This would allow effects such as:

  • typewriter-style text

  • staggered letter animation

  • wave/bounce effects across characters

  • individual transforms like position, rotation, scale, color, or opacity

From a quick look at the codebase, it seems text rendering currently relies on Pango + Cairo. My tentative idea is to use the glyph layout information from Pango and render characters individually rather than drawing the entire layout as a single block. Those glyphs could then expose transform parameters that integrate with Synfig’s existing ValueNode and waypoint system.

I’m currently experimenting with a small prototype to see how feasible it is to render glyphs individually and apply transforms per character.

Before I turn this into a full proposal, I wanted to ask:

  1. Does this direction sound like a reasonable project idea for Synfig?

  2. Would extending TextLayer be preferable, or would introducing something like a TextGroupLayer make more sense architecturally?

  3. Are there any limitations in the current text rendering pipeline that I should be aware of?

Any feedback or suggestions on scope would be really helpful.

Thanks!

3 Likes

No, it doesn’t use neither Pango nor Cairo.

It uses FreeType + HarfBuzz + FriBiDi. :slight_smile:

Yes, it is a good idea and a requested feature by some users (if I recall well, it would allow users to reproduce the “range selector” from Adobe After Effects).

Maybe it would also allow to import SVG text spans and effects.

IMO it depends on how many new parameters would be added (or changed) in the TextLayer.

2 Likes

Thanks for the clarification!

I’ve started looking into the FreeType + HarfBuzz + FriBiDi pipeline to understand how glyph shaping and positioning work in Synfig.

The “range selector” comparison is really helpful — that’s very close to the kind of workflow I had in mind.

For the architecture, I’m currently exploring whether it makes more sense to extend the existing TextLayer or introduce a separate grouping layer for per-character elements. I’ll experiment a bit more to see what fits better with the current system.

I’m working on a small proof-of-concept to validate this approach and will share updates as I make progress.

Thanks again for the guidance!:heart:

I love the idea, and yes it would significantly enhance Synfig’s capability to animate text, and be very helpful to animators.

I was thinking of if we can extend the scope of idea to have to have a bit more and create a general “multi element animation” (kindaa) layer.

What I have on mind is, within group layer, we can have multiple layers. So the things that you plan to do for individual characters (glyphs) of text, will be similarly applied to elements of the group. So for end user the workflow would be, just use let’s say "Animate Group” , we will animate some property for this “Animate Group” layer, for example scale property, and then this animated property will be applied to all the elements of the group with staggering / delay (which can be configured through the property of Animate Group layer).

If you decide to work on text only, just keep this idea in mind during development, so that you can design the solution in such a way that it can be extended to such usecase later.

2 Likes

That’s a really interesting direction, thanks for suggesting it!

I can see how the stagger/offset mechanism could be generalized to groups of layers, not just text.

I’ll explore how this could fit within the project scope, and try to design the solution in a way that keeps it extensible toward a more general “Animate Group” type system.

I’ll keep this in mind while working on the prototype.

1 Like

Quick update: i just Got a basic TextGroup-style prototype working — text is now split into individual glyph layers and shows up correctly in the layer panel.

Each glyph behaves like a normal layer, so per-character transforms are already working.

Currently I am refining synchronization between the layer tree and canvas rendering, and then I’ll move on to animation and staggered effects.

i have submitted my GSoC proposal based on this direction but i also wanted to get it reviewed and I’d really appreciate any feedback or suggestions to improve it.

Hi everyone,

I’m Yukta, third year computer science student , selected for GSoC 2026 with the project “Per-Character Text Animation Layer”.

I had previously started exploring this idea in this thread, and I’ll continue using it as the official project log.

Project Overview

The goal of this project is to introduce native per-character animation support in Synfig.

Currently, text is rendered as a single combined shape, which makes effects like staggered animation, typewriter effects, or per-letter transformations difficult without workarounds.

This project proposes a new TextGroup-style layer that decomposes text into individual glyph elements (based on HarfBuzz clusters), allowing each character to be independently transformed and animated while integrating with Synfig’s existing ValueNode and waypoint system.

Current Progress

I have already implemented an initial version of this approach directly inside Synfig.

  • Text is decomposed into individual glyph layers within a sub-canvas
  • Each glyph behaves like a standard layer
  • Rendering is working correctly for the decomposed text
  • Per-character transformations are already functional

This validates that the approach fits naturally within Synfig’s existing layer and rendering architecture.

I’ve attached a short demo showing the current state of glyph decomposition and rendering.

Project Goals

The main goals for this project are:

  • Implement a TextGroup layer to manage glyph-level elements
  • Introduce a reusable stagger/offset system for per-character animation
  • Enable independent animation of glyph properties (position, rotation, scale, color, opacity)
  • Support multi-line text and handle edge cases (including RTL/BiDi text)
  • Integrate cleanly with Synfig Studio UI and animation workflow
  • Ensure proper SIF/SIFZ serialization and backward compatibility
  • Provide documentation and example animations

Next Steps

  • Refine glyph decomposition and synchronization logic
  • Ensure correct alignment and rendering consistency
  • Begin implementing the stagger and animation system

I’ll be posting regular updates here as development progresses. Feedback and suggestions are very welcome.

Looking forward to working with everyone!

4 Likes

I’ve been spending some time reading through the relevant parts of the codebase and getting familiar with the architecture. I wanted to ask if there’s anything specific you’d generally like contributors to focus on during the bonding phase besides understanding the workflow and code structure.?

If your idea doesn’t get much interest, I’d suggest trying another idea. You could try creating a ValueAtTime system similar to SmartBone in Moho. The main idea would be a kind of controller for basic shapes — similar to shape keys in Blender.

Hello, @y_ukta.

The Community Bonding has this essential goal: time to you be welcomed and be prepared to code since day one (yet to come :slight_smile:)

@zainal the project idea is already defined and approved by us :wink:

1 Like

Good luck, and I hope the result will be useful for users. Even so, what I’m personally still hoping for the most is a SmartBone-like system in Synfig Studio. It could greatly improve character rigging and workflow flexibility in the future

1 Like

Week 1 Progress Update (May 25 – May 31)

Completed:

  • Refactored Layer_TextGroup font loading to reuse Layer_Freetype infrastructure, including FontConfig lookup and shared FT_Face caching.

  • Added configurable font family, style, weight, and direction parameters.

  • Replaced TextGroup-specific UTF-8 processing with Layer_Freetype::fetch_text_lines(), reusing existing UTF-8 decoding, line splitting, script segmentation, and BiDi handling.

  • Reworked sync_glyphs() to separate glyph generation from layer synchronization and reuse existing contour conversion utilities.

  • Removed obsolete local FT_Face ownership and cleaned up related code paths.

  • Added required build-system and translation integration files and resolved CI issues discovered during testing.

Investigation and design:

  • Evaluated approaches for sharing functionality between Layer_Freetype and Layer_TextGroup.

  • Investigated how HarfBuzz shaping can be integrated into TextGroup while preserving glyph identity for animation workflows.

Current status:

TextGroup now shares the existing font-loading and text-preprocessing pipeline used by Layer_Freetype. Basic glyph generation, font selection, and direction-aware text processing are functioning.

Next steps:

  • Replace direct codepoint-to-glyph mapping with HarfBuzz shaping.

  • Introduce cluster-aware glyph tracking to preserve glyph identity across text edits.

  • Continue groundwork for per-glyph animation and transform support.

3 Likes

Week 2 Progress Report (June 1 – June 8)

Completed

  • Added text layout controls to Layer_TextGroup, including kerning, grid fitting, horizontal/vertical spacing, alignment, color and invert support.

  • Added initial multiline text layout support.

  • Extended sync_glyphs() to perform line layout, alignment and contour generation before updating glyph layers.

  • Added parameter vocabulary and UI integration for the new controls.

  • Moved text style, weight and direction enums into shared headers so they can be reused by both Layer_Freetype and Layer_TextGroup.

  • Fixed CI issues related to translation extraction and compiler warnings.

Bug fixes

  • Fixed a crash caused by cached font faces loaded through load_font_static() missing required metadata initialization.

  • Fixed stale glyph layers remaining after text was cleared.

Challenges and design decisions

While integrating font loading into Layer_TextGroup, I investigated whether the existing Layer_Freetype::new_font_() logic could be reused directly.

new_font_() is tightly coupled to Layer_Freetype instance state (face, font, font_path_from_canvas, sync flags, etc.), so reusing it from Layer_TextGroup would require either introducing an artificial Layer_Freetype instance or refactoring existing text-layer code.

I experimented with refactoring the loading path to reduce duplication, but this changed existing Layer_Freetype behaviour and caused regressions in CI. I therefore kept load_font_static() as an independent shared loading path and limited changes to the new TextGroup implementation.

Current status

Layer_TextGroup now supports:

  • Shared text preprocessing via fetch_text_lines()

  • Font cache reuse

  • Kerning

  • Alignment/orientation

  • Horizontal and vertical spacing controls

  • Color and invert propagation

  • Initial multiline layout

The layer is now much closer to Layer_Freetype behaviour while still generating independent glyph layers.

Next steps

  • Replace direct FT_Get_Char_Index() usage with HarfBuzz shaping.

  • Add cluster-aware glyph identity tracking to preserve animation state across text edits.

  • Continue work toward per-glyph animation support.

3 Likes

Week 3 Progress Update (June 9 – June 15)

Completed

Per-character timing and glyph reuse

  • Added stagger_delay support to Layer_TextGroup.

  • Implemented per-glyph time offsets through set_time_vfunc(), allowing existing animations to cascade across generated glyphs.

  • Replaced simple index-based glyph matching with character-based glyph reuse to better preserve animation data when editing text.

Glyph animation infrastructure

  • Added per-glyph offset support to Layer_GlyphShape.

  • Added support for independent glyph transforms and animation-driven offsets.

  • Fixed cloning issues affecting glyph layers containing animation data.

  • Registered Layer_GlyphShape in the layer book to support correct duplication behaviour.

Procedural wave animation

  • Added wave_amplitude and wave_period parameters.

  • Implemented procedural sine-wave animation across generated glyphs.

  • Combined with stagger_delay, this produces wave and cascade effects without requiring per-glyph keyframes.

Animation persistence

  • Fixed save/load behaviour that could rebuild the generated glyph structure and discard loaded waypoint data.

  • Animation data is now preserved correctly when reopening saved files.

Challenges and Design Decisions

While working on glyph reuse and animation preservation, I investigated different approaches for maintaining glyph identity across text edits.

The current implementation reuses glyph layers based on character identity, which improves preservation of animation data when characters are inserted or removed. However, this approach will not correctly handle ligatures or more complex shaping cases, so future work will move toward HarfBuzz cluster-based glyph identity.

I also encountered several issues related to glyph positioning and offset application while introducing animation support. These were resolved by separating text layout positioning from animation-driven offsets.

Current Status

Layer_TextGroup now supports:

  • Per-glyph layer generation with individual transform parameters

  • Kerning and multiline layout

  • Per-glyph time offsets

  • Character-based glyph reuse

  • Per-glyph transform animation

  • Procedural wave animation

  • Preservation of animation data across save/load

Next Steps

  • Integrate HarfBuzz shaping for ligatures and complex scripts.

  • Replace character-based matching with cluster-aware glyph identity.

  • Continue work toward more robust per-character animation workflows.

4 Likes

Week 4 Progress Update (June 16 – June 22)

Completed

HarfBuzz shaping integration

  • Integrated HarfBuzz shaping into Layer_TextGroup, moving text generation onto the same shaping pipeline used by Layer_Freetype.

  • Replaced direct codepoint iteration with HarfBuzz-shaped glyph output.

  • Verified shaping with complex scripts including Arabic and Devanagari.

  • Added glyph cluster tracking alongside glyph indices for shaped text processing.

HarfBuzz-shaped Arabic text rendered in Layer_TextGroup. Glyph clusters are preserved and decomposed into independently animatable layers.

Shared text-processing module

  • Refactored text-processing utilities out of Layer_Freetype into a dedicated text_processing module shared by both Layer_Freetype and Layer_TextGroup.

  • This refactor establishes a shared shaping pipeline for both text layers and removes TextGroup’s dependency on Layer_Freetype’s internal text-processing implementation.

Cluster-based glyph identity

  • Replaced character-based glyph matching with cluster + glyph-index based identity.

  • Added support for HarfBuzz cluster information throughout the glyph synchronization pipeline.

  • Established groundwork for stable glyph identity across ligatures and complex-script shaping.

Real-time playback updates

  • Added a force-refresh path through Canvas and CanvasView.

  • Parameter changes now update correctly while animation playback is running.

  • Routed refresh requests through the root canvas so updates originating from generated glyph sub-canvases reach the active view.

Challenges and Design Decisions

The primary focus this week was replacing TextGroup’s simplified codepoint-based text handling with a shaping-aware pipeline.

Extracting shared functionality into a dedicated text-processing module required separating reusable text-processing utilities from Layer_Freetype-specific state and rendering logic. This reduced duplication while ensuring both layers continue to produce consistent shaping and contour generation results.

Moving glyph identity from raw characters to HarfBuzz clusters required redesigning the glyph reuse mechanism. Character-based matching works for simple Latin text, but does not correctly represent ligatures, contextual substitutions, or complex-script shaping. The new cluster-aware approach aligns glyph identity with the shaping engine’s output rather than the original character stream.

Current Status

Animation Features

  • Per-glyph layer generation

  • Independent glyph transforms

  • Staggered time offsets

  • Procedural wave animation

  • Animation preservation across save/load

  • Real-time parameter updates during playback

Text Features

  • Shared HarfBuzz shaping pipeline between Layer_Freetype and Layer_TextGroup

  • Kerning and multiline layout

  • Cluster-based glyph identity

  • Arabic shaping and contextual joining

  • Devanagari shaping support

Known Issues / Next Steps

  • HarfBuzz advances and offsets are not yet used for final glyph positioning; TextGroup currently relies on FreeType advance values.

  • Per-span text direction is not yet applied; shaping direction is currently fixed.

  • Initial glyph layout occasionally requires an additional synchronization cycle before first playback.

Next Steps

  • Use HarfBuzz advances and offsets for glyph positioning.

  • Apply per-span direction handling.

  • Continue testing with RTL and complex-script languages.

  • Improve synchronization stability and glyph reuse across text edits.

1 Like