ScatterKit

A justified image grid for SwiftUI on macOS and iOS, with an expand/contract open animation. The grid engine behind Kosmica, MIT licensed.

Click or tap a tile and it springs to the centre of the viewport while its neighbours scatter away with an exponential distance falloff and fade; click again and everything springs back. Tiles are bare Core Animation layers laid out from aspect ratios alone, and only tiles near the viewport hold pixels, so large grids stay smooth.

Watch the demo video

Installation

dependencies: [
    .package(url: "https://github.com/skcript/ScatterKit", from: "1.0.0"),
],
targets: [
    .target(name: "MyApp", dependencies: [.product(name: "ScatterKit", package: "ScatterKit")]),
]

Usage

import ScatterKit
import SwiftUI

struct Gallery: View {
    let photos: [URL]
    let grid = ScatterGridController()

    var body: some View {
        ScatterGrid(items: photos.map { ScatterItem(id: $0.path, aspect: 1.5) },
                    content: { id, maxPixel, _ in decodeImage(at: URL(fileURLWithPath: id), maxPixel: maxPixel) },
                    onOpen: { print("open:", $0 ?? "none") },
                    controller: grid)
    }
}

Reduce Motion replaces the springs with a short crossfade. Each on-screen tile is a VoiceOver button labelled with its id.

Configuration

ScatterConfig (pass as config:):

FieldDefault
item, hoverbounce 0.1 / softSprings for open, close, scatter and the macOS hover lift (ScatterConfig.springItem is an alternative item spring)
hoverScale1.02Hover lift
push, reach800, 1000Scatter offset = push · exp(−distance / reach), at a 156 pt row height
densityThreshold80Above this many on-screen tiles the push weakens
openDuration, closeDuration, scatterDuration, cornerDuration0.30, 0.30, 0.35, 0.34 sAnimation lengths
scatterFade, closeFade0.13, 0.30 sNeighbours fade out / back in
rowHeight, gap, cornerRadius150, 14, 6 ptLayout
backgrounddark greyFill behind the tiles

SpringMotion.bounce(_:response:) builds a spring from a bounce and response, like SwiftUI’s.

Demo app

swift run Demo [folder] shows the images in a folder (default ~/Pictures) on macOS.

Development

swift build && swift test
xcodebuild -scheme ScatterKit -destination 'generic/platform=iOS Simulator' build

License

MIT.