You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A working page exists in the reference host — specs-testing/workspaces/de-library/storybook/pages/Typography.mdx with typography.ts, branch feat/storybook-init. It reads the library's declared text styles, groups them by the first level of each name, renders a Typeset block per group, and lists every style beneath with weight, size, line height, letter spacing and case.
The specimen question that originally blocked this issue is answered: Typeset plus a per-style table. The block alone is not a specimen, because it labels rows by size and cannot carry style names.
How the data is read
Text styles are a join, and both halves live in the fetched file:
root.json carries the style map — style id to name, key and description, for every style the file declares.
The per-page node payloads carry the resolved type properties, keyed by the same style id. One sampled usage per style is enough; every node bound to a style reports the same properties.
The prototype does the join in Node, through a Vite virtual module, because the page payloads total tens of megabytes and cannot be shipped to a browser. That is the shape of the remaining work: the join belongs in an emitted artifact, not in a host plugin. A generator writing a text-styles artifact would make the page a plain read, the same as the colour page.
What the join buys over parsing the stylesheet: letter spacing, line-height unit, text case and decoration, style descriptions, and the identity of each style — none of which survive the CSS font shorthand.
What it surfaces
Two things the stylesheet version could not show, both real library state rather than page defects:
25 of 65 declared text styles have no resolved properties, because no node in the file uses them. They are listed as unresolved rather than omitted.
Styles sharing a name appear more than once, because the file declares them under separate ids. This is distinct from the duplicate-naming defect recorded below, and the page shows both rather than reconciling either.
Current state is good enough for now
The prototype is accepted as the shape for this page. The work below is what makes it generic, not what makes it usable.
Closed by the generator, not deferred
Decided 2026-10-01: the gaps below are in scope for #642's first pass rather than follow-up work against shipped pages. The prototype is the shape; the generator is expected to arrive without these holes.
Read from the data rather than parsing the shorthand. The CSS font shorthand carries weight, size, line height and family and nothing else. Letter spacing survives only because a sibling token happens to be named for it. The source data carries more — see decision 1.
Sample text is hardcoded. It should be settable, and a library with non-Latin coverage needs it to be.
Font families are listed, not shown. The page names the families and never renders a specimen of one.
Decisions needed to make this generic
1. The page must read the data, not the stylesheet. Settled on #609: foundations pages read the source artifact. The typography prototype still parses the emitted stylesheet, which is the main thing left to change.
The data exists, in two places that have to be joined:
data/cache/styles.yaml indexes every style — name, key, type, source file — and carries the library's text styles, not only the plugin's.
data/library.file/page-*.json carries full type properties on nodes: fontFamily, fontWeight, fontSize, letterSpacing, lineHeightPx, lineHeightUnit, alignment. Richer than the CSS font shorthand, which drops letter spacing and the line-height unit.
The join is the open detail. The index keys styles by Figma style key; nodes reference style ids, and the stored pages carry no global style map. So reading a style's properties means resolving that correspondence and sampling a node that uses the style, rather than reading a style definition directly. The transforms already do this to emit CSS, so the mechanism exists — the question is whether the page reuses it or an artifact is written that makes the join unnecessary.
2. Grouping must come from declared structure, not name segments. Settled on #609: collection, then the first level of the name hierarchy. The typography prototype still groups by first name segment, because parsing the stylesheet is all it has — which is the same upstream gap as decision 1, showing up a second way.
3. Styles that share a value must not be merged. The prototype briefly merged them, which read well and was unsound — two genuinely distinct styles that happen to share a value would collapse into one, and the page would assert a relationship the library never declared. Removed.
The case that prompted it is worth recording, because it is the page working correctly. The library to hand carries two parallel sets of text styles under different names with identical values, both referenced across components — 58 uses of one body-medium name against 3 of the other, 43 against 4 for body-small, and so on through body, title and eyebrow. That is a library authoring defect, not a generator defect: the source file has two naming conventions live at once and the stylesheet emits exactly what it is given. Being fixed at source.
The page's job is to show what the library contains, including this. Identity comes from the source; value equality is evidence of a problem, never grounds for merging.
4. Names are shown whole. Settled on #609: a design system has at most one namespace, and it is part of the name. The heuristic that derived and stripped it is removed.
5. What a group is, when the library has more than one family of styles. The library to hand emits several prefixes alongside each other. The prototype shows each as its own group, which is honest but makes no statement about whether they are peers, a migration in progress, or one set shadowing another. The page should either say which is current or stay out of it deliberately.
Acceptance criteria
Every text style appears, grouped by its declared structure.
Each style shows its full property set, not only what the font shorthand carries.
Two styles are merged only when the source says they are one.
Sample text is configurable.
Generated from emitted artifacts with no per-workspace authoring.
Subissue of #574. Wave 2.
State
A working page exists in the reference host —
specs-testing/workspaces/de-library/storybook/pages/Typography.mdxwithtypography.ts, branchfeat/storybook-init. It reads the library's declared text styles, groups them by the first level of each name, renders aTypesetblock per group, and lists every style beneath with weight, size, line height, letter spacing and case.The specimen question that originally blocked this issue is answered:
Typesetplus a per-style table. The block alone is not a specimen, because it labels rows by size and cannot carry style names.How the data is read
Text styles are a join, and both halves live in the fetched file:
root.jsoncarries the style map — style id to name, key and description, for every style the file declares.The prototype does the join in Node, through a Vite virtual module, because the page payloads total tens of megabytes and cannot be shipped to a browser. That is the shape of the remaining work: the join belongs in an emitted artifact, not in a host plugin. A generator writing a text-styles artifact would make the page a plain read, the same as the colour page.
What the join buys over parsing the stylesheet: letter spacing, line-height unit, text case and decoration, style descriptions, and the identity of each style — none of which survive the CSS
fontshorthand.What it surfaces
Two things the stylesheet version could not show, both real library state rather than page defects:
Current state is good enough for now
The prototype is accepted as the shape for this page. The work below is what makes it generic, not what makes it usable.
Closed by the generator, not deferred
Decided 2026-10-01: the gaps below are in scope for #642's first pass rather than follow-up work against shipped pages. The prototype is the shape; the generator is expected to arrive without these holes.
Remaining work
fontshorthand carries weight, size, line height and family and nothing else. Letter spacing survives only because a sibling token happens to be named for it. The source data carries more — see decision 1.Decisions needed to make this generic
1. The page must read the data, not the stylesheet. Settled on #609: foundations pages read the source artifact. The typography prototype still parses the emitted stylesheet, which is the main thing left to change.
The data exists, in two places that have to be joined:
data/cache/styles.yamlindexes every style — name, key, type, source file — and carries the library's text styles, not only the plugin's.data/library.file/page-*.jsoncarries full type properties on nodes:fontFamily,fontWeight,fontSize,letterSpacing,lineHeightPx,lineHeightUnit, alignment. Richer than the CSSfontshorthand, which drops letter spacing and the line-height unit.The join is the open detail. The index keys styles by Figma style key; nodes reference style ids, and the stored pages carry no global style map. So reading a style's properties means resolving that correspondence and sampling a node that uses the style, rather than reading a style definition directly. The transforms already do this to emit CSS, so the mechanism exists — the question is whether the page reuses it or an artifact is written that makes the join unnecessary.
2. Grouping must come from declared structure, not name segments. Settled on #609: collection, then the first level of the name hierarchy. The typography prototype still groups by first name segment, because parsing the stylesheet is all it has — which is the same upstream gap as decision 1, showing up a second way.
3. Styles that share a value must not be merged. The prototype briefly merged them, which read well and was unsound — two genuinely distinct styles that happen to share a value would collapse into one, and the page would assert a relationship the library never declared. Removed.
The case that prompted it is worth recording, because it is the page working correctly. The library to hand carries two parallel sets of text styles under different names with identical values, both referenced across components — 58 uses of one body-medium name against 3 of the other, 43 against 4 for body-small, and so on through body, title and eyebrow. That is a library authoring defect, not a generator defect: the source file has two naming conventions live at once and the stylesheet emits exactly what it is given. Being fixed at source.
The page's job is to show what the library contains, including this. Identity comes from the source; value equality is evidence of a problem, never grounds for merging.
4. Names are shown whole. Settled on #609: a design system has at most one namespace, and it is part of the name. The heuristic that derived and stripped it is removed.
5. What a group is, when the library has more than one family of styles. The library to hand emits several prefixes alongside each other. The prototype shows each as its own group, which is honest but makes no statement about whether they are peers, a migration in progress, or one set shadowing another. The page should either say which is current or stay out of it deliberately.
Acceptance criteria
fontshorthand carries.Case data