feat: extract typography (font families + heading/body styles) - #17
Open
AnandSundar wants to merge 5 commits into
Open
feat: extract typography (font families + heading/body styles)#17AnandSundar wants to merge 5 commits into
AnandSundar wants to merge 5 commits into
Conversation
Implements U1 and U2 from the typography extraction plan: - Add FontSource, FontAsset, HeadingStyle, BodyStyle, TypographyAsset types (src/types.ts) - Make typography non-optional on BrandExtractionResult - Re-export extractTypography and new types from src/index.ts - Implement extractTypography($, html, baseUrl) in src/scraper.ts: * Collects CSS from inline <style> + allowlisted external stylesheets (Google Fonts, Typekit, same-origin) via parallel fetch with 5s timeout * Parses with brace-counting CSS extractor (strips /* */ comments, splits top-level blocks) * Builds FontAsset[] from @font-face rules, classifies source by URL (google-fonts/typekit/self-hosted/system), filters generic family names, dedupes case-insensitively with weights-merge * Extracts h1/h2/body styles from CSS rules + inline style override
Implements U3 from the typography extraction plan:
- Add extractTypography call to parseHtml; include typography in return type
- Add typography to the explicit result construction in the API route
- Normalize legacy cache entries (pre-typography) so cache hits always return the full shape with typography: { fonts: [], styles: {} } when the field is missing
Implements U4 from the typography extraction plan: - Create components/typography-display.tsx with: * Font list with family, weights, url (if single), and color-coded source badge (Google Fonts / Typekit / Self-hosted / System) * Heading (h1, h2) and body samples rendered in the actual font with computed font-size/weight * Empty case: returns null when both fonts and styles are empty (preserves the existing rendering when a site has none) - Wire TypographyDisplay into brand-results.tsx between ColorPalette and BackdropGallery
Implements U5 from the typography extraction plan: Create integration_test/typography-shape.test.ts with 15 tests covering: - Live-site shape validation against vercel.com (fonts, styles) - Generic CSS family names (sans-serif, serif, monospace, etc.) are filtered out - Case-insensitive family dedup merges Inter/inter with weight accumulation - URL-based source classification (google-fonts / typekit / self-hosted / system) - Heading and body style extraction from CSS rules + inline style override - @font-face rules inside CSS comments are ignored - Fix splitTopLevelBlocks so each top-level block includes its selector (was previously only capturing { body }, missing @font-face / h1 / body)
Implements U6 from the typography extraction plan: - Update MCP tool description for extract_brand_assets to mention typography - Update SKILL.md frontmatter description, npm example, asset-sources table, and response-format JSON sample to include typography - Add CHANGELOG.md entry for 0.3.0 documenting the new typography field, scope of CSS sources, generic-name filter, weights-merge dedup, and 5-second fetch timeout
|
This is great |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #15
Adds font detection and typography analysis to OpenBrand. The extraction now returns a non-optional
typographyfield with font families (with source classification) and heading/body typographic styles.What's new
extractTypography()insrc/scraper.ts— collects CSS from inline<style>blocks plus allowlisted external stylesheets (Google Fonts, Typekit, same-origin), parses it with a brace-counting CSS extractor, and returns:fonts:FontAsset[]withfamily,source(google-fonts/typekit/self-hosted/system), optionalweights, optionalurlstyles:h1,h2,bodywithfontFamily,fontSize,fontWeightAPI route —
/api/extractreturnstypographyon the standard response. Legacy cache entries (pre-typography) are normalized to{ fonts: [], styles: {} }on cache hits so the shape is always complete.UI — new
TypographyDisplaycomponent renders fonts with color-coded source badges and live heading/body samples in the actual fonts. Wired intoBrandResultsbetweenColorPaletteandBackdropGallery.MCP — tool description for
extract_brand_assetsupdated to mention typography.Design notes
<style>, Google Fonts (fonts.googleapis.com,fonts.gstatic.com, regardless of origin), Typekit (use.typekit.net, regardless of origin), and same-origin first-party stylesheets. Other third-party CSS is skipped to keep the request surface narrow.@font-facerules for the same family;urlis omitted when multiple URLs exist (representative URL would be misleading).Promise.allSettledwith a 5-second timeout and the sameUSER_AGENTused for page fetches. Individual failures are silently tolerated./* */comments first, walks the string tracking{/}depth. Skips@-rules(e.g.@media) at the top level to keep the rule list flat. (Wrapped@mediaheading overrides are not in scope for v1.)Files changed
src/types.tsFontSource,FontAsset,HeadingStyle,BodyStyle,TypographyAsset.typographymade non-optional onBrandExtractionResult.src/index.tsextractTypography+ new types.src/scraper.tsextractTypography()+ parser helpers (splitTopLevelBlocks,parseDeclarations,firstNonGenericFamily, etc.).parseHtmlnow returnstypography.app/api/extract/route.tstypographyinto response; normalize legacy cache entries.components/typography-display.tsxTypographyDisplaycomponent.components/brand-results.tsxTypographyDisplaybetweenColorPaletteandBackdropGallery.integration_test/typography-shape.test.tsmcp/src/index.tsSKILL.md,CHANGELOG.mdTesting
asset-shapes.test.tstests still pass (4/4)api-keys.test.tsfailure unrelated to this change (Supabase env not configured in this sandbox)