Skip to content

Real-time liquid glass effects for SwiftUI — frosted blur, refraction, rim lighting, and cursor/gaze-reactive highlights. Powered by Metal.

License

Notifications You must be signed in to change notification settings

omnideaco/CrystalKit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CrystalKit

A Swift package that renders real-time liquid glass effects using Metal shaders. Drop it onto any SwiftUI view to get frosted glass with refraction, chromatic dispersion, rim lighting, and cursor/gaze-reactive highlights.

CrystalKit glass effect demo

Runs on macOS 14+, iOS 17+, and visionOS 1+.

Installation

Add CrystalKit to your project via Swift Package Manager:

dependencies: [
    .package(url: "https://github.com/omnideaco/CrystalKit.git", from: "0.1.1")
]

Or in Xcode: File > Add Package Dependencies, paste the repo URL, and pick the version.

Quick Start

import SwiftUI
import CrystalKit

struct ContentView: View {
    var body: some View {
        Text("Hello, Glass")
            .padding()
            .crystalGlass()
    }
}

That's it. The modifier captures the backdrop behind the view, blurs it, and composites a glass material with refraction, rim lighting, and edge effects.

Styles

CrystalKit ships with four presets:

.crystalGlass(.regular)  // Default everyday glass
.crystalGlass(.clear)    // Transparent, subtle refraction
.crystalGlass(.subtle)   // Barely-there frosting
.crystalGlass(.frosted)  // Heavy blur, strong refraction

Or build your own:

.crystalGlass(CrystalGlassStyle(
    frost: 0.7,           // 0 = clear, 1 = fully frosted
    refraction: 0.4,      // Edge warping strength
    dispersion: 0.2,      // Chromatic color separation
    lightIntensity: 0.8   // Rim light brightness
))

Style Properties

Property Range Default Description
frost 0–1 0.5 Background blur intensity. 0 = clear, 1 = fully frosted.
refraction 0–1 0.35 How much background content bends at the glass edges.
dispersion 0–1 0.15 Chromatic color separation (rainbow fringing) at edges.
depth 0–1 0.0 Magnification zoom through the glass lens.
splay 0–1 0.25 Radial barrel distortion of the background.
lightIntensity 0–1 0.6 Rim light brightness and edge extent.
lightBanding 0–1 0.5 Rim light gradient falloff. 0 = sharp cutoff, 1 = soft fade.
lightRotation 0–1 0.6 Light source angle. 0 = top, 0.25 = right, 0.5 = bottom, 0.75 = left.
edgeWidth 0–1 0.05 How far refraction extends inward from shape edges.
resonance Bool false Adaptive tinting — dark backgrounds tint lighter, light backgrounds tint darker.
tintColor Color? nil Optional color overlay on the glass surface.
tintOpacity 0–1 0.0 Tint blend amount. Only applies when tintColor is set.
variant .regular / .clear .regular Glass material variant. Clear reduces light intensity to 70%.
cornerRadius CGFloat? nil Override corner radius. nil = inferred from clipping shape.
lightSource .fixed / .cursor(...) .fixed Light tracking mode. See Cursor-Reactive Lighting.

Shapes

Glass clips to standard SwiftUI shapes, built-in descriptors, or any custom path via SDF textures:

// SwiftUI shapes
.crystalGlass(.regular, in: Capsule())
.crystalGlass(.regular, in: Circle())
.crystalGlass(.regular, in: RoundedRectangle(cornerRadius: 16))

// Polygons and stars
.crystalGlass(.regular, shape: .polygon(sides: 6, cornerRadius: 4))
.crystalGlass(.regular, shape: .star(points: 5, innerRadius: 0.4))

// Custom paths — provide a pre-computed SDF texture for any arbitrary shape
.crystalGlass(.regular, shape: .custom(sdfTexture: mySdfTexture, padding: 8))

The .custom case accepts a Metal SDF (signed distance field) texture, so you can render glass on any shape you can rasterize — bezier paths, boolean operations, hand-drawn outlines, anything.

Cursor-Reactive Lighting

On macOS, glass can track the mouse. On iOS, it tracks where the user is looking via ARKit face tracking.

// Follows cursor/pointer automatically
var cursorStyle: CrystalGlassStyle {
    var style = CrystalGlassStyle.regular
    style.lightSource = .cursor()
    return style
}

Text("Hover me")
    .crystalGlass(cursorStyle)

The .cursor() case accepts two optional parameters:

Parameter Default Description
falloffRadius 300 Distance in points where light fades to baseIntensity. nil = angle-only (no distance falloff).
baseIntensity 0.3 Minimum light intensity when cursor/gaze is far away (0–1).
// Wider reach, brighter at rest
style.lightSource = .cursor(falloffRadius: 600, baseIntensity: 0.5)

// Angle-only — light direction follows cursor, intensity stays constant
style.lightSource = .cursor(falloffRadius: nil)

Eye Tracking (iOS)

On iPhone/iPad with TrueDepth or Neural Engine, CrystalGazeTracker projects the user's gaze direction to screen coordinates via ARKit face tracking.

@StateObject private var gaze = CrystalGazeTracker()

var body: some View {
    MyContent()
        .crystalGazePoint(gaze.gazeScreenPoint)
        .onAppear { gaze.startCalibration() }
}

The guided calibration shows three target dots the user looks at, then computes accurate per-axis scale factors. Observe gaze.calibration to build a calibration overlay UI:

switch gaze.calibration {
case .idle:                    // Not calibrating
case .lookingAt(let point, let step, let totalSteps, let progress):
    // Show target dot at `point`, progress bar at `progress`
case .complete:                // Ready to use
}

You can tune the tracker after calibration:

Property Default Description
smoothing 0.4 Gaze interpolation (0 = raw, 1 = heavy smoothing).
horizontalScale 8.0 Horizontal projection multiplier. Set by calibration.
verticalScale 8.0 Vertical projection multiplier. Set by calibration.
samplesPerTarget 40 Frames collected per calibration target point.

Requires NSCameraUsageDescription in Info.plist.

Background Luminance

CrystalKit samples the backdrop luminance and automatically sets the child view's foreground style to white (dark backgrounds) or black (light backgrounds). Read the value yourself via the environment:

@Environment(\.crystalGlassLuminance) var luminance

Custom Backdrop Provider

By default, CrystalKit captures the screen behind the view using CGWindowListCreateImage (macOS) or UIView snapshotting (iOS). If you're already rendering with Metal (like a canvas app), you can supply the backdrop texture directly to avoid screen capture permissions and flicker:

class MyProvider: CrystalBackdropProvider {
    func backdropTexture(for rect: CGRect, scale: CGFloat) -> MTLTexture? {
        // Return your Metal texture cropped to rect
    }
}

MyView()
    .crystalBackdrop(myProvider)

Requirements

Platform Minimum
macOS 14.0
iOS 17.0
visionOS 1.0
Swift 6.2

Requires a Metal-capable GPU (all supported platforms have one).

License

MIT. See LICENSE for details.

About

Real-time liquid glass effects for SwiftUI — frosted blur, refraction, rim lighting, and cursor/gaze-reactive highlights. Powered by Metal.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages