Documentation

Native exports

One command turns glyphfox icons into real vector assets for Android, Jetpack Compose, iOS, SwiftUI and Flutter. Weight, corners, duotone, modifiers and fusions export as plain paths, and strokes stay strokes.

Overview

terminal
npx glyphfox export android home search file+check --out app/src/main/res
npx glyphfox export compose --from icons.txt --package com.acme.icons --out app/src/main/java
npx glyphfox export ios home search --out MyApp/Assets.xcassets
npx glyphfox export swiftui home search --out MyApp
npx glyphfox export flutter home search --out .
npx glyphfox export android --all --weight 1.5 --corners sharp --out app/src/main/res

Pass icon names or any spec of the name syntax, a list file with --from (one name per line, # starts a comment) or --all for the whole set. The geometry is the one the web packages draw, so the same specs look the same everywhere:

heart
bell/duotone
file+check
cloud&lock
user+plus@tl
TargetWrites under --outUse it as
androiddrawable/gf_NAME.xml@drawable/gf_home, R.drawable.gf_home
composePACKAGE/GlyphFox.kt and PACKAGE/NAME.ktIcon(GlyphFox.Home, null)
iosGlyphFox.xcassets/gf-NAME.imagesetUIImage(named: "gf-home")
swiftuiGlyphFox.swift and the catalogImage(glyphfox: .home)
flutterassets/glyphfox/NAME.svg and lib/glyphfox.dartGlyphFoxIcon(GlyphFoxIcons.home)

Android

One VectorDrawable per icon in drawable/, so point --out at app/src/main/res. Strokes keep their width in viewport units, their round or square caps and joins, and never get a fill, so they scale with the drawable exactly like the SVG. The color is a tint: ?attr/colorControlNormal by default, so the icons follow the theme like the Material icons do.

res/drawable/gf_heart.xml
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24"
    android:tint="?attr/colorControlNormal">
    <path
        android:pathData="M12,19.89 L4.41,12.3 A4.8,4.8,0,1,1,12,6.58 A4.8,4.8,0,1,1,19.59,12.3 Z"
        android:strokeColor="@android:color/white"
        android:strokeWidth="2"
        android:strokeLineCap="round"
        android:strokeLineJoin="round" />
</vector>
layout.xml
<ImageView
    android:layout_width="24dp"
    android:layout_height="24dp"
    android:src="@drawable/gf_heart"
    android:contentDescription="@string/favorite" />

Pass a theme attribute or a color resource as --color (?attr/colorPrimary, @color/brand) to tint with it, or a hex color (#ff7a1a) to bake the color into the paths without a tint. Duotone layers are filled paths with fillAlpha, --mirror-rtl sets android:autoMirrored, and rotate and flips become a group around the center.

Jetpack Compose

GlyphFox.kt declares the GlyphFox object and every icon is an ImageVector extension property on it, built on first use and cached, in its own file. The files go to the package folder under --out, so point it at the Kotlin source root.

com/acme/icons/Heart.kt
package com.acme.icons

val GlyphFox.Heart: ImageVector
    get() {
        if (_heart != null) {
            return _heart!!
        }
        _heart = ImageVector.Builder(
            name = "GlyphFox.Heart",
            defaultWidth = 24.dp,
            defaultHeight = 24.dp,
            viewportWidth = 24f,
            viewportHeight = 24f,
        ).apply {
            path(
                stroke = SolidColor(Color.Black),
                strokeLineWidth = 2f,
                strokeLineCap = StrokeCap.Round,
                strokeLineJoin = StrokeJoin.Round,
            ) {
                moveTo(12f, 19.89f)
                lineTo(4.41f, 12.3f)
                arcTo(4.8f, 4.8f, 0f, true, true, 12f, 6.58f)
                arcTo(4.8f, 4.8f, 0f, true, true, 19.59f, 12.3f)
                close()
            }
        }.build()
        return _heart!!
    }

private var _heart: ImageVector? = null
Screen.kt
import com.acme.icons.GlyphFox
import com.acme.icons.Heart

Icon(GlyphFox.Heart, contentDescription = "Favorite")
Icon(GlyphFox.Heart, contentDescription = null, tint = MaterialTheme.colorScheme.primary)
Image(GlyphFox.Heart, contentDescription = null) // keeps the exported color

GlyphFox.all.forEach { (name, vector) -> Icon(vector, contentDescription = name) }

Each property is imported by name, like the Material icons. GlyphFox.all maps every exported name to its vector for pickers and previews. With code shrinking on, R8 removes the icons an app never uses, unless it reads GlyphFox.all.

iOS asset catalog

One image set per icon with the SVG, Preserve Vector Data and Render As Template Image, so the icons stay sharp at any size and take the tint color. Point --out at an existing catalog such as MyApp/Assets.xcassets to add the image sets to it (its own Contents.json is kept), or at a folder to get GlyphFox.xcassets.

gf-heart.imageset/Contents.json
{
  "images" : [
    {
      "filename" : "gf-heart.svg",
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  },
  "properties" : {
    "preserves-vector-representation" : true,
    "template-rendering-intent" : "template"
  }
}
ViewController.swift
let heart = UIImageView(image: UIImage(named: "gf-heart"))
heart.tintColor = .systemOrange

The SVG files carry concrete colors (black by default), which template rendering replaces with the tint. With a hex --color the catalog switches to original rendering so the color shows; --rendering template or original picks one explicitly, and --mirror-rtl marks the image sets to flip in right to left layouts.

SwiftUI

glyphfox export swiftui writes the same asset catalog plus GlyphFox.swift: an enum with one case per image set, Image(glyphfox:) and UIImage.glyphfox(_:) for UIKit.

GlyphFox.swift
public enum GlyphFox: String, CaseIterable, Sendable {
    case heart = "gf-heart"
    case `repeat` = "gf-repeat"
}

public extension Image {
    init(glyphfox icon: GlyphFox, bundle: Bundle? = nil) {
        self = Image(icon.rawValue, bundle: bundle).renderingMode(.template)
    }
}
ContentView.swift
Label { Text("Favorites") } icon: { Image(glyphfox: .heart) }

Image(glyphfox: .heart)
    .resizable()
    .frame(width: 32, height: 32)
    .foregroundStyle(.orange)
    .accessibilityLabel("Favorite")

ForEach(GlyphFox.allCases, id: \.self) { Image(glyphfox: $0) }

Pass bundle: .module when the catalog lives in a Swift package.

Flutter

SVG files in assets/glyphfox/ and lib/glyphfox.dart with one constant per icon and a small GlyphFoxIcon widget on top of flutter_svg. Point --out at the app folder, then add the package and the assets to pubspec.yaml:

pubspec.yaml
dependencies:
  flutter_svg: ^2.0.0

flutter:
  assets:
    - assets/glyphfox/
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'glyphfox.dart';

Row(children: [
  const GlyphFoxIcon(GlyphFoxIcons.heart),
  GlyphFoxIcon(GlyphFoxIcons.heart, size: 32, color: Colors.orange, semanticLabel: 'Favorite'),
  SvgPicture.asset(GlyphFoxIcons.heart), // the exported colors, no tint
])

GlyphFoxIcon follows the surrounding IconTheme for size and color like Icon does, tints the whole drawing (the duotone layer keeps its opacity) and is decorative unless it gets a semanticLabel. GlyphFoxIcons.values lists every exported path, and --assets moves the SVG folder.

Options

OptionTargetsDefaultDescription
specsallNames or specs such as file+check@tr, cloud&lock:side or heart/duotone.
--fromallA list file: one name per line or separated by commas, # starts a comment.
--allallEvery icon of the set.
--outall.The project folder: res for android, the Kotlin source root for compose, a folder or an .xcassets catalog for ios and swiftui, the app folder for flutter.
--sizeall24Size in dp, points or logical pixels. Below 24 the stroke is optically compensated, as on the web.
--weightall2Stroke width from 1 to 3 on the 24 grid.
--absolute-weightallKeeps the stroke at weight units at the export size.
--cornersallroundround or sharp (square caps and miter joins).
--variantalloutlineoutline or duotone. The solid style cuts lines out with masks, which VectorDrawable and ImageVector cannot draw, so it is refused.
--coloralltintA hex color baked into the files. Android also takes a theme attribute or a color resource, used as the tint.
--secondary-color, --secondary-opacityallcolor, 0.3Color and opacity of the duotone layer.
--rotate, --flip-x, --flip-yallA transform around the center of the grid.
--mirror-rtlallFlips the icon in right to left layouts (autoMirrored, autoMirror, the image set direction).
--modifier, --modifier-cornerallThe same badge on every icon, like file+check.
--prefixandroid, ios, swiftuigf_, gf-Prefix of the drawable or image set names.
--packagecomposeglyphfoxKotlin package, also the folder under --out.
--renderingios, swiftuitemplatetemplate or original; original is the default with a hex --color.
--assetsflutterassets/glyphfoxFolder of the SVG files and of the paths in the constants.

Names and colors

A spec becomes a name on each platform: file+check@tr is gf_file_check_tr on Android, GlyphFox.FileCheckTr in Compose, gf-file-check-tr in the catalog and fileCheckTr in Swift and Dart. Two specs that end up with the same name are refused, and keywords are escaped (repeat becomes `repeat` in Swift).

Without --color every target follows the platform tint: colorControlNormal, LocalContentColor, the SwiftUI foreground style or IconTheme. With a hex color the color is baked in and stays: Android drops the tint, the catalog renders the original and GlyphFoxIcon keeps the exported colors unless it gets a color. Compose Icon() always tints, so use Image() or tint = Color.Unspecified to see the baked color.