Commit Graph
2 Commits
Author SHA1 Message Date
Xuanru LiandClaude Opus 4.8 6cc87312d4 feat(capture): extract chips/stat-cells/tabs, detect icon fonts, transparent grounds
designStyleExtractor now also extracts chip/pill/badge/tag, stat/metric cells, and
tab components — by class-substring selector plus a shape fallback (small + fully
rounded + short text) so hashed/utility class names (Tailwind, CSS-modules) are
still caught. It also emits a "transparent" sentinel for fully-transparent
(rgba(...,0)) grounds instead of collapsing them to #000000, so a transparent
chip/tab/stat on a light-ground site no longer reads as solid black.

fontMetadataExtractor now flags icon fonts (isIcon) by glyph coverage: a font is an
icon font only when it BOTH lacks a real Latin alphabet (<26 of A-Za-z) AND is
mostly (>50%) Private-Use-Area glyphs. The Latin gate matters — some text fonts pack
thousands of PUA glyphs yet are plainly text (Apple SF Pro is ~81% PUA but ships a
full alphabet; Descript's Booton ~50%); flagging by PUA ratio alone would strip a
brand's real typeface. Measured icon fonts: "hushly" 63% PUA / 7 letters, Font
Awesome 95% / 0 letters. Names alone can't identify icon fonts ("hushly",
"swiper-icons"), hence the glyph-based test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 20:55:28 -07:00
ukimsanov 5e7a7a8956 fix(capture): address review feedback on font extractor
Five fixes from Copilot's inline review + Miguel's note on PR #987:

1. inferWeightFromSubfamily — only matched concatenated forms
   ("extralight", "semibold"). Spaced ("Extra Light") and
   hyphenated ("Extra-Light") variants fell through to the 400
   default, misreporting 200-weight fonts as 400. Now normalizes
   `[\s-]+` out of the subfamily before matching.

2. meta.tool — was hardcoded to "fontkit@2.0.4" but
   `packages/cli/package.json` allows ^2.0.4, so the manifest
   string would drift on every dep bump. Now records just
   "fontkit"; the version moves with the dep and can be discovered
   from package.json at debug-time if needed.

3. FontFileMetadata.rawFamily — docstring said "nameID 16 preferred,
   then nameID 1" but the code also derives from PostScript via
   deriveFamilyFromPostscript when both name-table fields are
   missing. Doc now reflects the actual three-step precedence.

4. FontFileMetadata.weight — docstring said "100-900" but the code
   emits 0 (when identified: false) and 950 (when
   canonicalizeFamily picks ExtraBlack/UltraBlack). Doc now
   documents both edge values explicitly.

5. sharp ^0.34.5 — bumped from ^0.34.0 on this PR but font
   extraction doesn't use sharp; the bump is needed by the contact
   sheet code in PR #988. Reverted on #987; will re-bump on #988
   where it's actually consumed.

Also adds vitest coverage:
- 34 tests in fontMetadataExtractor.test.ts
- Covers inferWeightFromSubfamily for concatenated, spaced, and
  hyphenated forms (including composite styles like "Bold Italic"
  and case-insensitivity)
- Covers canonicalizeFamily for unchanged families, stripped
  weight tokens, preserved width modifiers, and the 950 emit
- Integration tests for extractFontMetadata (non-existent dir,
  empty dir) verifying the meta.tool / generatedAt shape

Exported `inferWeightFromSubfamily` and `canonicalizeFamily` for
testing. Pure functions, internal helpers, but exporting is the
clean way to pin their behavior against regressions.
2026-05-20 17:54:32 -07:00