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:
Does this direction sound like a reasonable project idea for Synfig?
Would extending TextLayer be preferable, or would introducing something like a TextGroupLayer make more sense architecturally?
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.
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.
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.
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.
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.
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.
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
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.
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
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.
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.
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.
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.
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.