Docs

Theming

SwiftPieces Pro themes every SwiftUI screen from one environment value. Liquid Glass on iOS 26 falls back to a material on iOS 17 and 18.

SwiftPieces Pro targets iOS 17 and later. Liquid Glass is used on iOS 26, and the same screens fall back to a material on earlier versions and when Reduce Transparency is on.

Themed pieces read their colors, type, spacing, radii, elevation and motion from the Design System, a small set of Swift files in the SwiftUI environment. The CLI installs it with every screen and template. The reusable interactions inside screens (sheets, tab bars, cards) take their styling as parameters, so they drop into any codebase.

ContentView()
    .environment(\.spTheme, PaperTheme())

Themes

  • SystemTheme is the default. It follows iOS semantic colors, text styles and your app's AccentColor, so pieces look native until you give them a brand.
  • PaperTheme is a warm editorial theme with serif headings, a terracotta accent, tighter corners and calmer springs. Use it as-is or as the reference for your own.
  • Your own theme is a struct conforming to SPTheme. Every token struct has defaults, so override only what changes.
struct HarborTheme: SPTheme {
    var color = SPColor(accent: .spDynamic(light: Color(spHex: 0x1F4D3A), dark: Color(spHex: 0x7FC7A0)))
    var radius = SPRadius(lg: 18)
}

Brands

A brand is a whole color scheme, not a tint. Each one sets the ground, a palette of solid color blocks with readable ink, the display face, numeral style, corner scale, motion and one graphic motif. Brands come from thirteen families:

  • Studio: charcoal ground, pastel blocks, light-weight numerals, contour lines.
  • Graphic: concrete grey, flat orange, violet and lemon blocks, heavy grotesk type, dot matrices.
  • Editorial: paper ground, serif headlines, scenery drawn in code.
  • Neon: near black with lime, Geist type, soft glow.
  • Candy: cream ground, soft saturated blocks, rounded type and shapes.
  • Ember: warm dark ground, coral and amber, serif captions, glow rings.
  • Press: newsprint bone, printing inks, tabular figures, tight corners and hairline rules.
  • Velvet: aubergine night, brass and jewel blocks, serif display, thin gilded rings.
  • Frost: glacier white, steel and ice blocks, light numerals, thin concentric arcs.
  • Sol: sun-bleached sand, marigold and terracotta, chunky grotesk, sunburst shapes.
  • Pearl: warm ivory, a soft iridescent haze, SF Pro at a regular weight with light numerals, and deep jewel cover art.
  • Confetti: paper white, toy-bright blocks, SF Pro Rounded at a heavy weight for display and text, buttons that stand on a lip and press down into it, and sprinkles.
  • Prism: cool white and black ink, seven vivid blocks around the color wheel that glow into each other as luminous fields, hero figures lit on a dot matrix, and a ruler dial with one red needle.
SPBrandFonts.register()
ContentView()
    .environment(\.spTheme, SPBrandTheme(.studio))

Every template ships three presets from three different families, and every library screen previews in three families, in light and dark: switch them on the screen's page, or pass brand: to its example (WalletStackExample(brand: .graphic)). Put color on blocks with theme.color.tile(i) (use fill for the block and on for its text), and set hero figures with theme.type.numeral(_:relativeTo:). SPCoverArt(seed:) paints a block in the family's own art, and SPMotifSticker(seed:) is the same art as a round sticker (Candy's blob face in Candy).

Prism

Prism puts its color on the cards themselves. Three pieces in the Design System carry it, and each works in any family:

  • SPPrismField(seed:animated:) is a block glowing into its neighbours on the wheel under a pale haze. SPBlockFill(_:) and .spBlockBackground(_:in:) paint a block as its family does: flat everywhere, a luminous field in Prism. The lower left of a field keeps the block's own color, so its on ink reads there.
  • SPDotDisplay(_:size:) lights a short figure (a time, a temperature, a count) on a 5×7 dot matrix. Animate progress from 0 to 1 to sweep it in, and pass unlit: to show the panel's dark dots. It scales with Dynamic Type and reads its text to VoiceOver.
  • SPTickDial(value:) is a ruler dial whose scale turns under one fixed needle. Bind it to a value and it turns with a drag, a selection haptic per tick and VoiceOver adjustments.
struct Reading: View {
    @Environment(\.spTheme) private var theme
    @State private var level = 0.4

    var body: some View {
        VStack(alignment: .leading, spacing: theme.space.lg) {
            Text("Sleep").font(theme.type.headline)
            SPDotDisplay("86%", size: 48, color: theme.color.tile(0).on)
            SPTickDial(value: $level)
                .accessibilityLabel("Goal")
        }
        .foregroundStyle(theme.color.tile(0).on)
        .padding(theme.space.xl)
        .spBlockBackground(0, in: .rect(cornerRadius: theme.radius.xl, style: .continuous))
    }
}

Reading tokens in your own views

struct Summary: View {
    @Environment(\.spTheme) private var theme

    var body: some View {
        Text("This week")
            .font(theme.type.headline)
            .foregroundStyle(theme.color.textPrimary)
            .padding(theme.space.lg)
            .spSurface(.e1, in: RoundedRectangle(cornerRadius: theme.radius.lg))
    }
}

Tokens

  • color: accent, accentOn, bg, surface, surfaceElevated, fill, the three text roles, separator, success, warning, danger, info and glassTint. Build light and dark pairs with Color.spDynamic(light:dark:).
  • type: display through caption. Bundled fonts should use .custom(_:size:relativeTo:) to keep Dynamic Type.
  • space: xxs through xxxl on a 4pt grid, plus margin for screen edges.
  • radius: xs through xl and pill. SPRadius.nested(in:padding:) keeps inner corners concentric.
  • elevation and motion: shadow levels e0 to e4, and snappy, smooth, bouncy, standard and hero animations that shorten under Reduce Motion.

Modifiers

  • .spSurface(.e1, in: shape) fills with the surface color, applies the level's shadow and adds a hairline in dark mode.
  • .spShadow(.e2) applies a shadow level alone.
  • .spGlass(in: shape, interactive:) uses Liquid Glass on iOS 26, a material below, and an opaque fill when Reduce Transparency is on.