2026-05-15
Generating gang sheets by merging Excel data
Automating the production of sports jerseys involves more than just swapping strings in a template. When you’re dealing with physical manufacturing, “4cm high” is a strict requirement, yet font rendering engines often treat sizing as a suggestion rather than a rule.
Here is a look at how we built a custom SVG templating engine in Flutter/Dart to bridge the gap between spreadsheet data and precision manufacturing.
The process starts with a shared Google Sheet or Excel file. The customer inputs player names, numbers, and garment sizes. While this is the most efficient way to collect data, the technical challenge lies in the normalization of that data into a high-fidelity SVG.
Glyph Measurement: Calculating the exact bounding box of the name and number.
Scaling & Kerning: Adjusting the font size and character spacing to fit physical constraints.
Composition: Combining the name, number, and a “size indicator” (e.g., “L” or “XL”) into a final layout.
In standard UI development, we set a fontSize in points or pixels. However, in typography, the font size refers to the em-square, which includes the ascent, descent, and often some “padding” (leading).
If a customer requests a name to be exactly 4cm tall, setting the font size to 4cm will result in text that is visually too small, because the actual glyphs rarely occupy the full em-box. This is further complicated by:
Descenders: Letters like “j” or “g” extending below the baseline.
Diacritics: Marks like Å, Â, or Õ that extend above the standard capital height.
Font Weights: Bold versions of fonts can vary in width, though some libraries fail to calculate this accurately.
When using Flutter for layout, you might reach for standard text painters. However, for manufacturing, we found current Dart ports of layout engines (like pretext) to be unreliable—for instance, failing to differentiate the width between Normal and Bold weights.
To solve this, we went “under the hood” of the TrueType Font (TTF) files.
Extracting Raw Paths Instead of relying on a high-level renderer, we access the raw shapes (glpyhs) inside the TTF file. This allows us to treat every letter as a mathematical path rather than a text character.
Iterative Scaling By measuring the actual bounding box of these paths, we can determine the exact height of the glyphs. We programmatically adjust the SVG font size attributes until the tallest character in a name (including diacritics) matches the 4cm target precisely.
Precision Kerning Most font files contain a kerning table—instructions on how much space to put between specific pairs (like “AV”). By extracting this data, we can manually position each character path in the SVG to ensure the name fits within the maximum width (e.g., 28cm) without looking cramped or uneven.
The Final Composition Once the name and number are calculated, we merge them into a single SVG group. A key feature of our system is adding the fabric size directly into the print file (usually hidden or placed in a non-printing area).
By embedding the size (e.g., “L”) underneath the graphics, the production team can identify the correct shirt for the correct name instantly, removing the need to cross-reference a master list during the heat-press process.
Moving from “screen-accurate” to “physically accurate” requires stripping away the abstractions of modern UI frameworks. By digging into TTF path data and manual SVG manipulation, we’ve turned a manual design task into a predictable, automated pipeline.
SVG also supports masking, which enables to nice extra touch of adding a cutout/transparent (club) logo in the bottom of the big numbers on the back of jerseys.
Written by: Jesper Halvorsen