How to inspect the fvar table: axes, ranges, and named instances
- Step 1Upload the variable font — Drop a TTF, OTF, WOFF, or WOFF2. Compressed web formats are decompressed in-page to a flat sfnt before the table directory is walked, so you can inspect the exact file you ship.
- Step 2The tool locates fvar in the table directory — It reads the sfnt header's table count, then scans the 16-byte directory entries for the `fvar` tag (and `name`, for label resolution). If there is no fvar entry, you get the no-variable-axes error rather than a crash.
- Step 3Read each VariationAxisRecord — For every axis the reader reports the tag, the resolved name, min/default/max (Fixed 16.16 decoded), and the raw flags. Use the flags to detect a hidden axis; use the tag to know whether it is registered (lowercase) or custom (uppercase).
- Step 4Read each InstanceRecord and its coordinates — Every named instance is decoded with its subfamily name and a coordinates object keyed by axis tag. This shows precisely which design-space point each instance pins — including any axis the instance leaves at its default.
- Step 5Cross-check the css_examples output — The reader also emits a font-variation-settings block per named instance, built from that instance's coordinates. Use it to confirm that the instance you think exists actually resolves to the settings you expect in CSS.
- Step 6Export the decoded fvar as JSON — Download `<fontname>.axes.json` containing axis_count, axes, instance_count, instances, and css_examples. This is your machine-readable record of the font's design space for diffing across builds.
fvar axis record fields, as decoded
Every value the reader pulls from each VariationAxisRecord. min/default/max are decoded from Fixed 16.16 fixed-point.
| fvar field | Reported as | Notes |
|---|---|---|
| axisTag | tag | 4 ASCII characters; lowercase = registered, uppercase = custom |
| minValue | min | Raw Fixed 16.16 divided by 65536 (can be fractional) |
| defaultValue | default | Resting point used when no font-variation-settings is set |
| maxValue | max | Upper bound; browser clamps anything above this |
| flags | flags | Raw 16-bit flags word; bit 0 marks a hidden axis |
| axisNameID | name | Resolved against the name table (Windows-English); tag if unresolved |
How names resolve, and what you see when they don't
The reader resolves name IDs only against Windows-English (platform 3, encoding 1, language 0x409) records. Anything else falls back.
| Situation | What the reader shows | Why |
|---|---|---|
| Axis has a Windows-English name record | The friendly name, e.g. Optical size | Direct lookup by axisNameID |
| Axis name only on Macintosh platform | The 4-character tag, e.g. opsz | Non-Windows records are ignored during resolution |
| Axis name in a non-English language only | The 4-character tag | Only language 0x409 is consulted |
| Instance has a Windows-English subfamily name | The style name, e.g. Condensed Medium | Resolved by subfamilyNameID |
| Instance subfamily name unresolved | Instance N (1-based) | Generic fallback so the row is still usable |
Cookbook
Concrete reads of fvar data and what they tell you. Use these to interpret the report against the file's actual bytes.
Confirm an axis range before blaming the browser
ExampleA weight that refuses to go past 600 usually means the file ships wght max 600, not 900. The decoded axis record settles it instantly.
axes:
tag: wght name: Weight
min: 100 default: 400 max: 600 <-- not 900
Conclusion: CSS "wght" 700 clamps to 600. The file, not the browser.Spot a hidden axis via the flags value
ExampleDesign tools hide axes flagged with bit 0, but CSS can still set them. If a 'phantom' axis affects rendering, check flags.
axes: tag: GRAD name: Grade flags: 1 <-- hidden bit set Meaning: not shown in UI, but font-variation-settings: "GRAD" N still works.
Read an instance's full coordinate set
ExampleAn instance pins one point in the whole design space. The coordinates map shows every axis it sets — including ones left at default that you might otherwise forget to write.
instances:
name: Condensed Bold
coordinates: { wght: 700, wdth: 75, opsz: 14 }
To reproduce in CSS you must set all three, not just wght.Catch a fractional parametric default
ExampleParametric axes (XOPQ, YOPQ, XTRA, ...) routinely carry non-integer defaults stored in Fixed 16.16. The reader decodes them exactly.
axes:
tag: XTRA name: XTRA
min: 323 default: 468 max: 603
tag: YOPQ name: YOPQ
min: 25 default: 79 max: 135 <-- use these verbatimDiff two builds to catch a regression
ExampleExport the JSON for an old and a new build and compare. A dropped instance or a narrowed range is a regression you want to catch before deploy.
build A: axis_count 2, instance_count 9 build B: axis_count 2, instance_count 5 <-- 4 named instances lost Action: ask the foundry why SemiBold/Medium instances disappeared.
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.
File has no fvar table
Error — not a variable fontWithout an fvar table there is nothing to inspect; the reader throws "This font has no variable axes (no fvar table or empty axis list)." That is the definitive signal a file is static. Inspect its other tables with the Font Metadata Extractor.
fvar exists but declares zero axes
Error — empty axis listA malformed or stripped fvar with an axis count of zero is treated the same as a missing table — the same no-variable-axes error fires. There is no design space to decode, so the tool refuses rather than emit an empty report.
Custom axis with an uppercase tag
Listed — custom axisRegistered axes use lowercase tags; foundry-defined axes use uppercase (e.g. GRAD, YOPQ, MONO). The reader lists them identically — they have the same record shape. Only font-variation-settings can target them; there is no CSS shorthand for custom axes.
Axis name resolves to its tag
Expected — Windows-English onlyName resolution consults only Windows-English (platform 3 / encoding 1 / language 0x409) records. A font that names axes only on the Mac platform, or only in another language, shows the bare tag. This is a name-table observation, not an error.
Instance shows as Instance 3
Expected — name fallbackWhen an instance's subfamilyNameID has no matching Windows-English record, the reader labels it Instance N (1-based). The coordinates are fully decoded, so you can still identify the instance by its values.
A WOFF2 with malformed Brotli payload
Error — decode failsWOFF2 is decompressed in-browser before the table directory is read. A corrupt or truncated WOFF2 fails during decompression and you get a decode error rather than a parsed report. Re-export the file or try the original TTF/OTF.
TrueType Collection uploaded
Error — unsupported formatOnly a single face is supported (TTF/OTF/WOFF/WOFF2). A .ttc container hits "Unsupported font format: ttc." Split out the face you need first; the Font Format Identifier tells you what you are holding.
Two axes share a tag (broken font)
Listed — coordinate collisionThe instance coordinates object is keyed by axis tag. If a malformed font declares two axes with the same tag, the later one wins in each instance's coordinate map. The axes array still lists both records, so you can see the duplication and reject the file.
You wanted the avar (non-linear mapping) too
Not covered — fvar onlyThis reader decodes fvar (axes and named instances). It does not decode the avar table's non-linear axis mappings. The reported min/default/max are the user-space endpoints; if a font uses avar, the perceived progression between them may be non-linear in the rendered glyphs.
Frequently asked questions
What exactly does this tool read?
It decodes the OpenType fvar table: the axis records (tag, name, min/default/max, flags) and the named-instance records (subfamily name plus per-axis coordinates). Names are resolved against the name table. It is a focused fvar reader.
Does it decode avar non-linear mappings?
No. It reads fvar only. The min/default/max it reports are the user-space axis endpoints. If a font ships an avar table, the rendered progression between endpoints can be non-linear, which fvar alone does not describe.
Why does an axis show its tag instead of a name?
Axis and instance names are resolved only against Windows-English name records (platform 3, encoding 1, language 0x409). Fonts that store names on the Mac platform or in another language fall back to the 4-character tag or to Instance N.
What does the flags number mean?
It is the raw 16-bit fvar axis flags word. Bit 0 marks the axis as hidden from user interfaces. Hidden axes are still settable via font-variation-settings, which is why the reader surfaces the value.
Why is a default value not a whole number?
fvar stores values in Fixed 16.16 fixed-point. The reader divides the raw integer by 65536 to recover the true value, so fractional defaults — common on parametric axes — appear exactly as stored.
How are instance coordinates presented?
As an object keyed by axis tag, e.g. { wght: 700, wdth: 75 }. Every axis in the font is present for each instance, including ones the instance leaves at its default value.
Can it write or fix the fvar table?
No. This is a read-only inspector. To produce a static font from one instance, use the Variable Font Freezer. To turn axis data into CSS, use the Font Face Generator or CSS Variable Generator.
What happens with a corrupt WOFF2?
WOFF2 is Brotli-decompressed in the browser before parsing. A truncated or corrupt payload fails during decompression, and you get a decode error rather than a partial report. Try the original uncompressed TTF/OTF.
Does it support TrueType Collections?
No. Only a single face (TTF, OTF, WOFF, WOFF2) is supported. A .ttc raises an unsupported-format error. Extract the face you need before inspecting.
Is the font sent anywhere?
No. The sfnt table directory and fvar/name tables are parsed in your browser from the file's bytes. Nothing is uploaded, so proprietary or unreleased fonts stay on your machine.
How do I tell a registered axis from a custom one?
Registered axes (wght, wdth, slnt, ital, opsz) use lowercase tags; custom foundry axes use uppercase tags (e.g. GRAD, YOPQ). The reader lists both the same way — the casing of the tag is the distinguisher.
What is the largest font I can inspect?
5 MB on Free, 50 MB on Pro, 1 GB on Developer per job. The reader only touches fvar and name, so even large families decode quickly within those limits.
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.