-
Notifications
You must be signed in to change notification settings - Fork 2
Library Usage Fonts
Goshot provides comprehensive font management capabilities through the fonts
package. This guide covers how to use and customize fonts in your code screenshots.
import (
"github.com/watzon/goshot/pkg/fonts"
"github.com/watzon/goshot/pkg/chrome"
)
// Get a font by name (uses system fonts)
font, err := fonts.GetFont("Arial", nil)
if err != nil {
// Falls back to Monaspace Argon (sans) or Neon (mono) if the font is not found
font, err = fonts.GetFallback(fonts.FallbackSans)
if err != nil {
log.Fatal(err)
}
}
// Use the font in chrome configuration
theme := chrome.Theme{
TitleFont: font.Name,
// ... other theme settings
}
Goshot supports various font styles and weights:
style := &fonts.FontStyle{
Weight: fonts.WeightBold,
Italic: true,
Condensed: false,
Mono: false,
}
// Get a specific font variant
boldItalicFont, err := fonts.GetFont("Roboto", style)
const (
WeightThin FontWeight = iota + 1 // Thinnest
WeightExtraLight // Extra Light
WeightLight // Light
WeightRegular // Regular (Normal)
WeightMedium // Medium
WeightSemiBold // Semi-bold
WeightBold // Bold
WeightExtraBold // Extra Bold
WeightBlack // Black
WeightHeavy // Heaviest
)
Note
Support for variable fonts will be coming in the future, but requires a new font library that's capable of parsing OpenType font tables.
Goshot supports variable fonts with the following common axes:
const (
AxisWeight = "wght" // Weight axis
AxisWidth = "wdth" // Width axis
AxisSlant = "slnt" // Slant axis
AxisItalic = "ital" // Italic axis
AxisOpticalSize = "opsz" // Optical size axis
AxisTexture = "TXTR" // Texture healing
AxisLigatures = "liga" // Ligatures
)
For Monaspace fonts specifically, these ranges are supported:
const (
MonaspaceWeightMin = 200
MonaspaceWeightMax = 800
MonaspaceWidthMin = 100
MonaspaceWidthMax = 125
MonaspaceSlantMin = -11
MonaspaceSlantMax = 1
)
Goshot can use fonts installed on your system:
// List all available system fonts
availableFonts := fonts.ListFonts()
for _, fontName := range availableFonts {
fmt.Printf("Found font: %s\n", fontName)
}
Goshot searches for fonts in these standard locations:
- Linux:
~/.fonts
~/.local/share/fonts
/usr/share/fonts
/usr/local/share/fonts
- macOS:
/System/Library/Fonts
/Library/Fonts
~/Library/Fonts
- Windows:
C:\Windows\Fonts
You can work with different variants of the same font family:
// Get all variants of a font
variants, err := fonts.GetFontVariants("Roboto")
if err != nil {
log.Fatal(err)
}
for _, font := range variants {
fmt.Printf("Variant: Weight=%d, Italic=%v, Condensed=%v\n",
font.Style.Weight, font.Style.Italic, font.Style.Condensed)
}
Create font faces for rendering:
// Create a font face with specific size
face, err := font.GetFontFace(14.0) // 14pt size
if err != nil {
log.Fatal(err)
}
// Use the face for rendering
// The face implements font.Face interface
Goshot includes Monaspace fonts (Argon and Neon) as fallback fonts:
// Get the fallback font (sans-serif variant)
fallback, err := fonts.GetFallback(fonts.FallbackSans)
if err != nil {
log.Fatal(err)
}
// Get the monospace fallback variant
monoFallback, err := fonts.GetFallback(fonts.FallbackMono)
if err != nil {
log.Fatal(err)
}
// Clear the font cache if needed
fonts.ClearCache()
type FontLoader struct {
cache map[string]*fonts.Font
}
func (l *FontLoader) LoadFont(name string, style *fonts.FontStyle) (*fonts.Font, error) {
// Try cache first
cacheKey := fmt.Sprintf("%s-%v", name, style)
if cached, ok := l.cache[cacheKey]; ok {
return cached, nil
}
// Try to load from system
font, err := fonts.GetFont(name, style)
if err != nil {
// Try fallback
font, err = fonts.GetFallback(fonts.FallbackSans)
if err != nil {
return nil, err
}
}
// Cache the result
l.cache[cacheKey] = font
return font, nil
}
-
Font Selection
- Use system fonts when available for consistent appearance
- Provide fallbacks for missing fonts
- Consider font licensing when bundling fonts
-
Performance
// Cache fonts for repeated use type FontManager struct { fonts map[string]*fonts.Font mu sync.RWMutex } func (m *FontManager) GetFont(name string) (*fonts.Font, error) { m.mu.RLock() if font, ok := m.fonts[name]; ok { m.mu.RUnlock() return font, nil } m.mu.RUnlock() font, err := fonts.GetFont(name, nil) if err != nil { return nil, err } m.mu.Lock() m.fonts[name] = font m.mu.Unlock() return font, nil }
-
Error Handling
func getFontWithFallback(name string, style *fonts.FontStyle) (*fonts.Font, error) { font, err := fonts.GetFont(name, style) if err != nil { // Log the error but don't fail log.Printf("Failed to load font %s: %v", name, err) // Try without style font, err = fonts.GetFont(name, nil) if err != nil { // Try fallback return fonts.GetFallback(fonts.FallbackSans) } } return font, nil }
func findClosestStyle(available []*fonts.Font, desired fonts.FontStyle) *fonts.Font {
var best *fonts.Font
var bestScore int
for _, font := range available {
score := 0
// Weight match
weightDiff := abs(int(font.Style.Weight) - int(desired.Weight))
score += 100 - (weightDiff * 10)
// Style matches
if font.Style.Italic == desired.Italic {
score += 50
}
if font.Style.Condensed == desired.Condensed {
score += 50
}
if score > bestScore {
best = font
bestScore = score
}
}
return best
}
- 📥 Installation
- 🚀 CLI Usage (coming soon)
-
🤝 Contributing
- Code of Conduct
- Development Workflow
- Project Structure
- Guidelines
- Testing
- Documentation