How to add icons without breaking existing codepoints
- Step 1Keep one canonical ordered name list in version control — Store your icon names, one per line, in a tracked file. This ordered list — not the font, not the CSS — is the source of truth for codepoint order.
- Step 2Regenerate from the existing list to capture the baseline — Paste the current list at your fixed start (usually U+E000) and save the JSON manifest. This is your baseline lockfile for the current release.
- Step 3Append new icon names to the end — Add the new names as new lines at the **bottom** of the list. Never insert in the middle and never reorder — both renumber existing icons.
- Step 4Regenerate with the same start — Run the tool again with the same start hex. The first N codepoints are identical to the baseline; only the appended names receive new sequential codepoints.
- Step 5Diff the manifest against the baseline — Compare the new JSON manifest to the committed one. The diff should be additive only — new `mappings` entries at the end, an updated `count`, same `start_hex`. Any change to an existing entry means something was reordered.
- Step 6Ship the new CSS rules for the added icons only — Append the new `.icon-*::before` rules to your stylesheet. Existing rules are unchanged, so no released markup breaks.
Stable vs. breaking edits
Which list operations preserve existing codepoints and which silently renumber them.
| Edit to the name list | Existing codepoints | Safe? |
|---|---|---|
| Append new names at the end | Unchanged | Yes |
| Insert a name in the middle | Everything after shifts +1 | No |
| Reorder / sort alphabetically | Most codepoints move | No |
| Rename a name in place (same position) | Codepoint unchanged; class may change | Mostly — see below |
| Delete a name from the middle | Everything after shifts −1 | No |
| Change the start hex | All codepoints shift | No |
Manifest fields and what a safe diff touches
After an append-only migration, only these parts of the manifest should change.
| Manifest field | Changes on append-only? | Why |
|---|---|---|
start_hex | No | Same fixed start every release |
count | Yes (increases) | New icons added |
existing mappings[i] | No | Earlier entries are positional and unchanged |
new mappings[N..] | Yes (added) | The appended icons get fresh codepoints |
Renaming an icon: what moves
Renaming in place keeps the codepoint but can change the CSS class. Plan for the class change.
| You change | unicode / hex | cssClass | Action needed |
|---|---|---|---|
| Position in list | Stays | Stays (if name unchanged) | None — this is the goal |
| The name text, same position | Stays | Changes (re-slugified) | Update or alias the old class in CSS |
| Both name and position | Changes | Changes | Avoid — breaks stability |
Cookbook
Concrete migration scenarios showing baseline vs. next release. The invariant: existing codepoints must not move.
Append-only release — the happy path
ExampleThree icons in v1, add two in v2 at the end. v1's codepoints are untouched.
v1 list: v1 result: home home -> \e000 user user -> \e001 search search -> \e002 v2 list (appended): v2 result: home home -> \e000 (same) user user -> \e001 (same) search search -> \e002 (same) settings settings -> \e003 (new) bell bell -> \e004 (new)
The breaking mistake: alphabetical insert
ExampleInserting 'bell' alphabetically between the others shifts every codepoint after it. Every stylesheet using \e001+ now shows the wrong icon.
WRONG (inserted in the middle): bell -> \e000 home -> \e001 (was \e000!) search -> \e002 (was \e002 by luck, but user moved) settings-> \e003 user -> \e004 (was \e001!) Every hard-coded escape in shipped CSS now points at a different glyph.
Using the manifest as a lockfile diff
ExampleCommit the manifest each release and diff it. An append-only migration shows only additions.
$ diff icons.v1.json icons.v2.json
> { "name": "settings", "unicode": 57347, "hex": "U+E003", ... }
> { "name": "bell", "unicode": 57348, "hex": "U+E004", ... }
"count": 3 -> "count": 5
(no changes to existing entries = safe release)Renaming an icon while keeping its codepoint
ExampleKeep the position; change only the text. The codepoint is stable but the CSS class is re-slugified — add an alias so old class names keep working.
Before: home -> .icon-home -> \e000
After: house -> .icon-house -> \e000 (codepoint same)
Keep old markup working:
.icon-home::before,
.icon-house::before { content: "\e000"; }Watching the high-water mark before a big release
ExampleThe Range used metric tells you how much PUA headroom remains before U+F8FF. Check it before adding hundreds of icons.
After current release: Icons assigned: 5200 Range used: U+E000 – U+F457 Remaining to U+F8FF: ~1,192 codepoints. A 1,300-icon batch would overflow -> plan a split.
Edge cases and what actually happens
Every row below was probed against the live API. Some documented requirements (alphabetical axis order, numerical tuple order) are not actually enforced in practice — useful to know if you've been blaming the wrong thing for a 400.
Inserting an icon in the middle of the list
Breaking — renumbersEvery name after the insertion point shifts up one codepoint. Shipped CSS that hard-codes those escapes now renders the wrong glyphs with no error. Always append at the end.
Sorting the list alphabetically
Breaking — renumbersSorting reorders almost every name, so almost every codepoint moves. This is the single most common way teams break their own icon font. Keep the list in append order, never sorted.
Deleting a retired icon from the middle
Breaking — renumbersRemoving a line shifts everything after it down one codepoint. To retire an icon safely, leave a placeholder name in its slot (e.g. _deprecated_oldname) so following codepoints don't move.
Changing the start hex between releases
Breaking — global shiftA different start shifts every codepoint by the same offset. Pick a start once and never change it for a given font.
Renaming an icon in place
Caution — class changesThe codepoint stays put, but the slugified CSS class changes (home → house gives .icon-house). Old markup using .icon-home stops matching. Add a CSS alias mapping both classes to the same codepoint.
Two teammates regenerate from different list copies
Caution — driftDeterminism only helps if everyone starts from the same ordered list. If two copies diverge in order, the mappings diverge. Keep one canonical list in version control as the single source.
List grows past U+F8FF over many releases
Error — out of spaceEventually an append-only list can overrun the 6,400-codepoint BMP PUA. The tool throws an out-of-space error at the overflow point. Watch the Range used metric and plan a second font (or block) before you hit the ceiling.
Blank line accidentally left in the middle
Handled — but watch orderBlank lines are dropped, so they don't consume codepoints — good. But if a real name was on that line and got deleted, the following icons shift down. Verify the count after editing.
Relying on the tool to remember the last run
Misconception — no stateThe tool has no memory between runs; stability comes entirely from you keeping the list order fixed. There is no stored mapping it reconciles against — the ordered list IS the state.
Duplicate name introduced during a merge
Caution — class collisionA merge that duplicates a name gives two entries the same slugified class but different codepoints, causing a cascade collision. Diff the manifest for duplicate cssClass values after merges.
Frequently asked questions
How does this tool keep my codepoints stable?
It doesn't store anything — it assigns codepoints strictly by paste order from a fixed start. Stability comes from you keeping the name list in the same order and only appending. Same ordered list in, same codepoints out, every time.
What's the one rule I must never break?
Never reorder or insert in the middle. Append new icons to the end of the list and keep the start hex fixed. That's the whole discipline.
Can I retire an icon without shifting the rest?
Leave its slot occupied with a placeholder name (like _deprecated_home) so following positions — and therefore codepoints — don't move. Deleting the line renumbers everything after it.
How do I prove a release didn't move codepoints?
Commit the JSON manifest each release and diff it. An append-only migration shows only new mappings entries and an increased count — no changes to existing entries.
If I rename an icon, does its codepoint change?
Not if it stays in the same position — the codepoint is positional. The CSS class will be re-slugified to the new name, though, so add an alias if old markup used the old class.
Does reordering ever keep codepoints the same?
Only the icons that happen to stay in their exact original position keep their codepoint. In practice any sort or insert moves enough names to break things. Treat reordering as always unsafe.
What happens when my list outgrows the PUA?
At 6,400 icons you fill U+E000–U+F8FF and the tool throws an out-of-space error. Monitor the Range used metric and split into a second font or block before you reach the ceiling.
Can I run this in CI to enforce stability?
Yes — it's browser/JS logic with no upload, so a build or pre-commit step can regenerate from the committed list and fail if the manifest diff touches existing entries.
Why not just store codepoints in the font and read them back?
You can audit a built font's codepoints with glyph-inspector, but the authoritative order should live in your version-controlled name list. This tool regenerates the mapping from that list deterministically.
What if two icons end up with the same class after a merge?
They'll have different codepoints but a colliding .icon-* selector, causing a cascade bug. Scan the manifest for duplicate cssClass values after merging branches.
Does changing the start codepoint ever make sense?
Only when you deliberately start a brand-new font or a separate block. For an existing font, changing the start shifts every codepoint and breaks all shipped CSS.
How do I check how many glyphs a font already defines?
Use glyph-count-analyzer to count glyphs in a built font, or character-coverage-map to see which ranges are covered, then reconcile against your name list.
Privacy first
Every JAD Font tool runs entirely in your browser using opentype.js and the wawoff2 WASM Brotli encoder. Your fonts never leave your device — verified by zero outbound network requests during processing.