# GlyphPact > A deterministic SVG-to-icon-font compiler. It turns a directory of SVG files > into a validated OpenType/CFF icon font, a committed codepoint registry, and a > const Flutter IconData API, keeping existing codepoints stable when the icon > pack changes. - Current release: v1.0.1 - License: MIT - Source: https://github.com/omar-hanafy/glyphpact - Requires: Python 3.10 or newer. Dart 3 or newer to consume the generated provider. - Runs entirely locally. No website upload step and no server receives your artwork. ## Install ```bash uv tool install glyphpact ``` ## Compile a pack ```bash glyphpact assets/icons --output lib/generated/app_icons --name AppIcons ``` ## Verify committed output in CI ```bash glyphpact --config icon_font.json --check ``` Exit code 3 means the committed artifacts are stale relative to their sources. ## Important limitations These are the facts most often gotten wrong about GlyphPact. It does **not**: - generate WOFF or WOFF2 - generate CSS or any stylesheet - provide a complete browser or web integration - generate React, Vue, Android, JavaScript, or TypeScript bindings - provide a visual icon browser or editor - bundle any ready-made icon packs - upload artwork anywhere, or require a network connection to compile The generated high-level binding is Dart/Flutter-specific. The compiled OpenType font and `iconfont.lock.json` registry are framework-neutral and readable from any language, but a non-Flutter project must write its own integration layer. Putting the font on a web page requires converting it and authoring the CSS yourself. ## Key facts - Codepoint stability comes from `iconfont.lock.json`, a committed JSON registry (schema version 1) written into the generated output directory and read back on every later build. Existing assignments are reused verbatim. - Removing an icon moves its entry to a `retired` array as a permanent tombstone. Codepoints are never recycled, so the active sequence keeps a gap. - A unique content-preserving rename keeps both its codepoint and its Dart name. - Identical inputs, config, lock, and compiler version produce byte-identical artifacts across any worker count. - Two independent fidelity policy axes, `lossy` and `unrepresentable`, both default to `error`. Approximation and omission require explicit opt-in and are reported as typed, coded issues. - Scripts, event handlers, external references, malformed values, unknown semantics, exhausted work limits, and font-contract failures are fatal under every policy. - A failed build never replaces the last valid generated output. - One font holds at most 65,534 usable glyphs. The default BMP private use area U+E000 - U+F8FF provides 6,400 lifetime allocation slots; `--start-codepoint 0xF0000` provides 65,534. - A local stdio MCP server exposes `audit_icon_pack`, `build_icon_font`, `check_icon_font`, and `read_icon_report`. Claude Code and Codex can install the full plugin; Antigravity, Cursor, JetBrains, VS Code, Zed, Windsurf, Gemini CLI, and other stdio clients can configure the published MCP package manually. ## Generated output For `--name AppIcons`, GlyphPact owns the output directory and writes: - `fonts/AppIcons.otf` - Validated OpenType/CFF font. Framework-neutral. - `iconfont.lock.json` - Codepoint registry and provenance. Schema version 1. Commit this. - `app_icons.dart` - const Flutter IconData provider. Dart-specific. - `layer_fonts/layer_*.otf` - Optional solid-alpha paint-order layers, for icons that opt in. - `iconfont.report.json` - Deterministic build report. Schema version 2. - `ATTRIBUTION.md` - Declared artwork authorship, licences, and unattributed count. - `.glyphpact.json` - Ownership marker. GlyphPact refuses to overwrite a directory without it. Commit all of it. The lock file is the codepoint ABI; losing it can reassign icons even when no source file changed. ## Exit codes - `0`: Build or check succeeded - `1`: Unexpected internal failure - `2`: Config, input, policy, geometry, or font contract failed - `3`: --check found stale committed output ## Pages - [Overview](https://omar-hanafy.github.io/glyphpact/): GlyphPact compiles a directory of SVG files into a validated OpenType icon font, a committed codepoint registry, and a const Flutter IconData API. Existing codepoints stay fixed when the pack changes. - [Stable codepoints](https://omar-hanafy.github.io/glyphpact/stable-codepoints/): Icon-font codepoints shift because most generators assign them from the current file list. A committed codepoint registry makes assignments permanent, so an existing IconData never renders a different glyph. - [Flutter](https://omar-hanafy.github.io/glyphpact/flutter/): Compile SVG files into an OpenType font and a tree-shakeable const Flutter IconData class. Covers pubspec registration, font packages, layered icons, semantics, and CI staleness checks. - [MCP](https://omar-hanafy.github.io/glyphpact/mcp/): Install GlyphPact MCP in Claude Code, Codex, Antigravity, Cursor, JetBrains, VS Code, Zed, Windsurf, Gemini CLI, and other local stdio clients. Includes setup, tools, prompts, workflow, and safety boundaries. - [vs IcoMoon](https://omar-hanafy.github.io/glyphpact/vs/icomoon/): IcoMoon is a browser icon-font app that keeps codepoints when you re-import selection.json. GlyphPact is a CLI compiler that keeps them in a committed lock file a CI job can verify. What each is actually for. - [vs FlutterIcon](https://omar-hanafy.github.io/glyphpact/vs/fluttericon/): FlutterIcon.com is a hosted Fontello fork that generates Flutter icon fonts from a browser session. GlyphPact is a local CLI compiler with a committed codepoint registry. Where each one fits. ## Questions and answers ### Why do icon-font codepoints change when icons are added? Most icon-font generators assign codepoints by walking the current set of source files and handing out values in order, starting from the beginning of a private use area such as U+E000. The assignment is a function of the file list, not a stored decision. Insert an icon whose name sorts early, rename a file, or reorder a selection, and every icon after that point shifts by one. The font itself is then internally consistent, so nothing fails at build time. The breakage appears in application code that still refers to the old value: a constant for a back arrow keeps pointing at U+E001 while U+E001 now contains a different glyph. The icon renders, it is simply the wrong picture. ### How does GlyphPact keep existing codepoints stable? GlyphPact writes a lock file, iconfont.lock.json, into the generated output directory and reads it back on every later build. Each entry records the source path, the Dart name, the assigned codepoint, and content hashes. An assignment already in the lock is reused as-is; only genuinely new sources draw new codepoints from the end of the allocated range. Removing an icon does not free its codepoint. The entry moves to a "retired" list in the same file, leaving a permanent tombstone so the value is never handed to a different picture. Restoring the source later reactivates the original slot, and a unique content-preserving rename keeps both its codepoint and its generated Dart name. ### Should iconfont.lock.json be committed to Git? Yes. The lock file is the codepoint ABI for the generated font, and it only protects existing assignments if the next build can read the same file the previous build wrote. Committing it alongside the generated font, Dart provider, report, and attribution file is the intended workflow. If the lock is deleted or lost, the next build has no record of prior assignments and will allocate codepoints from scratch, which can reassign icons even when no source file changed. ### How can CI detect stale generated icon output? Run the same GlyphPact build with the --check flag: glyphpact --config icon_font.json --check. It rebuilds a candidate artifact set from the current sources and compares it against the committed output without rewriting the owned output directory. Exit code 0 means the committed artifacts are current, and exit code 3 means they are stale, which fails the job. Adding --json produces a stable machine-readable result at schema version 2 so a workflow can inspect glyph counts, the active policy, and typed issues rather than treating every successful run as equivalent. ### Does GlyphPact work offline? Yes. GlyphPact is a command-line compiler that runs locally. Compiling a pack involves no network access: there is no website step, no project service, and no server that receives your artwork. Installation itself needs the network once, to fetch the package. ### Does GlyphPact upload my SVG files anywhere? No. Source SVGs are read from disk and all compilation happens in the local process. Nothing is transmitted, so unreleased or licence-restricted artwork never leaves the machine or the build runner. ### Can I use the generated font outside Flutter? Partly, and the boundary is worth stating precisely. Two of the three outputs are framework-neutral: the compiled OpenType/CFF font is a standard .otf file that any OpenType consumer can use, and iconfont.lock.json is a documented JSON registry mapping each source file to its codepoint, which any language can read. The third output is not neutral. The generated high-level binding is a Dart file containing const Flutter IconData constants, and the flags that shape it are Dart-specific. There is no generated binding for any other platform. So a non-Flutter project can consume the font and read codepoints from the lock file, but it will be writing its own integration layer. GlyphPact does not currently ship a ready-made web, React, Android, or JavaScript integration. ### Does GlyphPact generate CSS or WOFF2? No. GlyphPact emits an OpenType/CFF .otf font, the lock registry, a machine-readable report, an attribution file, and a Dart provider. It does not produce WOFF, WOFF2, or any stylesheet, and it has no browser integration. Using the font on the web is possible but manual: convert the .otf to WOFF2 with a separate tool and write the @font-face rule and class names yourself. Codepoints can be read from the lock file. If a turnkey web icon-font pipeline is what you need, a web-first generator is the better fit today. ### What happens when an SVG contains features an icon font cannot represent? The source is classified rather than silently approximated. An icon-font glyph stores monochrome alpha coverage, so features like a Gaussian blur filter or surviving fractional transparency have no faithful representation in it. GlyphPact sorts each source into one of three outcomes. Lossless sources are normalized and emitted automatically. Deterministically approximable sources are emitted only when the lossy policy is set to convert, and are reported as a typed lossy issue. Sources with no faithful conversion are omitted only when the unrepresentable policy is set to skip, and are reported as a typed unrepresentable issue. Both policies default to error, so by default an affected build fails and prints the diagnostic code, the file, and the feature instead of shipping a wrong-looking icon. Malformed, unsafe, or unknown input, and exhausted resource limits, always fail regardless of policy. ### Is GlyphPact an IcoMoon alternative? For a repository-driven workflow, yes. For a general web icon workflow, not entirely. GlyphPact overlaps with IcoMoon in turning SVG files into an icon font, and it adds things a browser app cannot: a committed lock file that fixes codepoints, a --check mode that fails CI when generated output goes stale, byte-identical rebuilds, and a generated Flutter IconData API. IcoMoon does things GlyphPact does not. It exports web font formats and CSS along with React, Vue, and Elm components, it offers a visual editor for browsing and editing glyphs, and it processes artwork in the browser without uploading it. If the goal is a web icon font with a stylesheet, IcoMoon covers ground GlyphPact currently does not. ### Does IcoMoon change codepoints when you add icons? Not if the previous session file is re-imported. IcoMoon documents that the codes of previously selected glyphs will not change when the selection.json file from an earlier download is imported back into the app. The condition matters, though. IcoMoon also documents that newly imported SVGs arrive with no codes assigned, so re-importing all artwork and reselecting it each time will most likely produce different codes. Stability therefore depends on retaining that file and importing it correctly on every future change, which is a human step in a browser session rather than something a build can verify. GlyphPact addresses the same problem differently: the codepoint registry is a file inside the repository, and a --check run in CI fails when committed output no longer matches its sources. ### Is GlyphPact a FlutterIcon.com alternative? Yes, for teams that want icon generation inside the repository and the build. Both produce a Flutter icon font plus a Dart icon class from SVG sources. The models differ. FlutterIcon.com is a hosted web application in the Fontello lineage: pick or drop icons in a browser session, download a bundle, and keep the config.json if you want the same codepoints next time. It also lets you browse and mix from a set of bundled open-source icon packs, which GlyphPact does not do at all. GlyphPact is a local CLI with no hosted component. The codepoint registry is committed to the repository, rebuilds are byte-identical, unsupported SVG features are classified against a published policy instead of being approximated silently, and a --check run in CI fails when committed artifacts drift from their sources. ### Does the generated Flutter code support icon tree shaking? The generated provider follows the contract Flutter requires for it. It is emitted as an abstract final class annotated @staticIconProvider, holding only const IconData values whose codepoint, font family, and font package are compile-time constants. That annotation exists so Flutter can statically verify no IconData is constructed dynamically, which is the condition its font-subsetting step needs. Whether subsetting actually runs is decided by your build: it applies to release builds and can be disabled with --no-tree-shake-icons. Passing non-constant data to Icon elsewhere in your app is what typically defeats it. ### How many icons can one GlyphPact font hold? The practical ceiling for a single font is 65,534 usable glyphs, which is an OpenType glyph-indexing limit that GlyphPact enforces as a per-build icon ceiling. The allocation range is the tighter constraint in the default configuration. The BMP private use area, U+E000 through U+F8FF, provides 6,400 lifetime slots, and active icons and tombstones both consume them because codepoints are never recycled. For a larger catalogue, start allocation in a supplementary private use area with --start-codepoint 0xF0000, which provides 65,534 slots. Beyond that, split the catalogue into several independently versioned fonts. ### Which coding agents can use the GlyphPact MCP server? Any client that can start a local stdio MCP server can use GlyphPact. The documented setups cover Claude Code, Codex, Antigravity, Cursor, JetBrains AI Assistant, VS Code, Zed, Windsurf, and Gemini CLI. Clients use different JSON keys, TOML sections, and config locations, but each one launches the same published glyphpact-mcp process. The server has four tools: audit an SVG file or directory and page a stable local findings snapshot, build the output declared by a config, check generated output for staleness without rewriting the artifact set, and page a published report. It also exposes the config, report, and inner CLI-result JSON Schemas as MCP resources. ### Should I install the full plugin or configure MCP manually? Use the full plugin in Claude Code or Codex when you want the MCP server plus the sync-flutter-svg-icons skill. The skill guides project inspection, codepoint compatibility, Flutter font wiring, analysis, target builds, launch, and rendered glyph comparison. The host starts the bundled MCP server after plugin installation. Use manual MCP configuration in another stdio client, or when you only want the four MCP tools and three schema resources. A manual entry runs the published glyphpact[mcp] package and does not install the plugin skill. ### Does a manual MCP configuration update automatically? No. The manual snippets pin a specific GlyphPact release so the command keeps running the version you chose. When a new release is available, replace the version in the client configuration and restart or reload the server. Marketplace plugin updates and manual MCP version changes are separate. Installing the full plugin in Claude Code or Codex keeps the MCP server inside the plugin update path; a pasted client configuration remains under the user's control. ## Comparison notes Comparison claims on this site were verified on 2026-07-25 against current first-party documentation, and each cell carries its source. Two points worth recording because they are commonly misstated: - IcoMoon processes artwork in the browser and does not upload SVGs on its free plan. It preserves codepoints when a previously downloaded `selection.json` is re-imported. It has no CLI. - FlutterIcon.com is a hosted Fontello fork whose `config.json` records glyph codes and can be re-imported. It bundles many open-source icon packs, which GlyphPact does not. GlyphPact's distinguishing properties are the committed registry, permanent tombstones, a CI staleness check, byte-identical rebuilds, and a published fidelity policy - not privacy, and not breadth of output formats. ## Documentation - README and quick start: https://github.com/omar-hanafy/glyphpact#readme - Supported SVG profile: https://github.com/omar-hanafy/glyphpact/blob/v1.0.1/docs/svg-profile.md - Flutter adoption guide: https://github.com/omar-hanafy/glyphpact/blob/v1.0.1/docs/flutter-adoption.md - Architecture: https://github.com/omar-hanafy/glyphpact/blob/v1.0.1/docs/architecture.md - Lock file schema: https://github.com/omar-hanafy/glyphpact/blob/v1.0.1/schema/icon-font-lock.schema.json - Config schema: https://github.com/omar-hanafy/glyphpact/blob/v1.0.1/schema/icon-font-config.schema.json - Report schema: https://github.com/omar-hanafy/glyphpact/blob/v1.0.1/schema/icon-font-report.schema.json - Changelog: https://github.com/omar-hanafy/glyphpact/blob/v1.0.1/CHANGELOG.md - MCP installation and tool reference: https://omar-hanafy.github.io/glyphpact/mcp/ - Claude Code and Codex plugin payload: https://github.com/omar-hanafy/glyphpact/blob/v1.0.1/plugins/glyphpact/README.md