Lucas Morris

Font Glyphs to Custom React Components

A pipeline that converts Keyrune font glyphs into 500+ Magic: The Gathering React components, with rarity-aware gradients, CSS styling support and consistent SVG scaling.

Tech Stack :
Font Glyphs to Custom React Components

Generating 400+ Magic: The Gathering Set Symbols as React Components

The Problem

The collectible card game, Magic: The Gathering (MTG), has published over 50,000 cards spanning 20 years. Cards are published in themed sets and include a unique symbol — a small icon that appears on every card marking the set it was published in. These symbols change appearance based on a card's rarity: common cards get are a simple black-and-white icon, while cards that are uncommon, rare, or "mythic rare" receive metallic gradient fills in silver, gold, and orange respectively.

I wanted all of these symbols rendered natively in my collection management app — not as raster images that blur at different sizes, but as crisp, scalable vector components that could respond to rarity dynamically or be used in creative ways with CSS (background images, opaque overlays, animations, etc). There are over 400 unique set symbols, many with intricate interior details, and some composed of multiple overlapping layers. No existing library offered what I needed for these ready-to-use React components.

So I built a data pipeline to generate them myself!


The Approach

The symbols originate from Keyrune, an open-source icon font that maps each MTG set symbol to a Unicode codepoint. My pipeline takes the raw font data and, through a series of automated steps, produces self-contained React TSX components — one per set — each with built-in rarity gradient support.

From Font Glyphs to Classified SVG Paths

The first stage exports every glyph from the Keyrune TrueType font as individual SVG files using FontForge. The conversion script then parses a companion CSS file (also from Keyrune) to map each Unicode codepoint back to its corresponding set code (e.g., MH3 for Modern Horizons 3).


Each SVG is decomposed into its constituent subpaths, and here's where things get interesting: the script uses the Shoelace formula to compute the signed area of each subpath. Positive area means the path is a filled shape; negative area means it's a hole — an interior cutout that should reveal whatever is behind it. This classification is critical because holes need to be rendered differently depending on a variety of factors.

Seven Rendering Modes

Not every set symbol follows the same visual rules. Through careful study of the official card renders, I identified and implemented seven distinct rendering modes:

ModeCommon RarityNon-Common Rarities
DefaultBlack fill, white border, transparent holesGradient fill, black border, transparent holes
Gradient-in-HolesBlack fill, white-filled holesBlack fill, gradient-filled holes
InvertedBlack fill, white-filled holes, white borderGradient fill, black-filled holes, black border
White HolesBlack fill, white-filled holes, white borderGradient fill, white-filled holes, black border
Always White BorderBlack fill, transparent holes, white borderGradient fill, transparent holes, white border
No BorderBlack fill, no borderGradient fill, no border
Multi-LayerPer-layer fill and hole rules composited togetherPer-layer fill and hole rules with gradient support

Each set is mapped to its correct rendering mode, and the generator produces the appropriate JSX structure automatically.


Multi-Layer Compositing

Some of the more recent and visually complex set symbols are composed of two or three separate glyphs layered on top of each other. The pipeline handles these by loading each layer's SVG independently, computing a unified bounding box across all layers, and generating a single component that composites them with per-layer fill rules, hole modes, and optional borders. The result is a single <svg> element that faithfully reproduces symbols like Innistrad: Midnight Hunt's dual-layer crescent moon or Thunder Junction Commander's three-layer badge.

Normalization and Scaling

Every generated component normalizes its paths into a consistent 1024x1024 coordinate space with uniform padding, ensuring symbols of wildly different original dimensions render at the same visual size. Stroke widths are inversely scaled to compensate, so borders appear consistent regardless of the underlying glyph geometry.

Additional Symbol Support

Beyond set symbols, a companion script handles other MTG iconography — mana symbols, ability icons, and other game-specific glyphs. These follow a simpler pipeline (no rarity gradients or hole classification needed) but use the same SVG-to-React pattern, producing lightweight components with configurable fill colors and consistent 32x32 viewBoxes.


The Result

The pipeline generates over 500 production-ready React component which are:

  • Fully scalable — Vector-based, sharp at any size
  • Rarity-aware — Pass a rarity prop and the correct gradient or fill is applied automatically
  • Self-contained — Each component includes its own gradient definitions, no external CSS or assets required
  • Lightweight — No runtime SVG parsing, no image loading, no layout shift
  • Consistent — Uniform coordinate space and stroke scaling across every symbol

From a single font and CSS file, all the symbols regenerate in seconds — making it trivial to update as new sets are released.