Skip to content

roberthein/Kinetics

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

6 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

tinyAPI logo

Tunable, physics-driven motion primitives for SwiftUI.

Kinetics brings the natural feel of real-world physics to your SwiftUI animations. Built on Swift 6 with strict concurrency compliance, it provides a modern, safe foundation for creating motion that responds to user input, respects boundaries, and feels alive.

โœจ Features

๐ŸŽฏ Retargeting

Change animation targets mid-flight and watch your UI smoothly redirect. Perfect for interactive elements that need to respond to user input in real-time.

@State private var target = CGPoint(x: 100, y: 100)
@State private var current = CGPoint.zero

var body: some View {
    Circle()
        .fill(.blue)
        .frame(width: 50, height: 50)
        .position(current)
        .kinetics(
            target: $target,
            current: $current,
            spring: .playful
        )
        .onTapGesture {
            // Retarget anywhere - animation smoothly redirects!
            target = CGPoint(x: .random(in: 0...300), y: .random(in: 0...300))
        }
}

๐Ÿš€ Tossing & Momentum

Capture the energy of user gestures and let it carry through your animations. Natural momentum that feels responsive and delightful.

@State private var dragState = KineticsDragState()

var body: some View {
    Rectangle()
        .fill(.green)
        .frame(width: 100, height: 100)
        .kineticsDragGesture(state: $dragState)
        .onChange(of: dragState.isActive) { _, isActive in
            if !isActive {
                // Toss with captured momentum
                target = dragState.projectedTranslation
            }
        }
}

๐Ÿฆพ Rubber-Banding

iOS-native resistance when content exceeds boundaries. Smooth, natural feel that guides users back to valid ranges.

let rubberConfig = RubberBandConfig(
    constant: 0.55,  // Classic UIScrollView feel
    dimension: 300,
    mode: .outside(bounds: 0...200, freeOvershoot: 20)
)

var body: some View {
    Rectangle()
        .kinetics(
            target: $target,
            current: $current,
            spring: .snappy,
            boundary: .rubber(perComponent: [0: rubberConfig, 1: rubberConfig])
        )
}

๐Ÿงฒ Snapping

Intelligent snapping to meaningful positions. Perfect for dials, sliders, and any interface that needs to align with discrete values.

let snapConfig = RubberBandConfig(
    constant: 0.8,
    dimension: 100,
    mode: .inside(anchor: 0, bandUntil: 25, snapBackInside: true)
)

var body: some View {
    DialView()
        .kinetics(
            target: $target,
            current: $current,
            spring: .rigid,
            boundary: .rubber(perComponent: [0: snapConfig])
        )
}

๐Ÿ€ Bouncing

Realistic collision response with configurable energy loss. Create interfaces that feel solid and responsive.

let bounceBoundary = BounceBoundary(
    xr: 0...300,
    yr: 0...500,
    restitution: 0.6,  // Bouncy but not too energetic
    friction: 0.1      // Smooth sliding along boundaries
)

var body: some View {
    BallView()
        .kinetics(
            target: $target,
            current: $current,
            spring: .bouncy,
            boundary: .bounce(bounceBoundary)
        )
}

๐Ÿ”ฎ Projection

Predict where motion will end and update your UI accordingly. Responsive interfaces that anticipate user intent.

@State private var rotationState = KineticsRotationState()

var body: some View {
    KnobView()
        .kineticsRotationGesture(
            state: $rotationState,
            velocityScale: 1.2,
            projectionFallbackTime: 0.4
        )
        .onChange(of: rotationState.projectedRotation) { _, projected in
            // Update UI based on where rotation will end
            updateKnobValue(projected)
        }
}

๐ŸŽจ Spring Presets

Kinetics comes with carefully tuned spring configurations for every use case:

  • .playful - Bouncy with clear overshoot (ฮถ=0.4, response=0.6s)
  • .elastic - Springy with moderate bounce (ฮถ=0.5, response=0.5s)
  • .bouncy - Responsive with light overshoot (ฮถ=0.6, response=0.4s)
  • .snappy - Quick response with light overshoot (ฮถ=0.9, response=0.3s)
  • .ultraSnappy - Lightning-fast response (ฮถ=0.9, response=0.15s)
  • .rigid - Precise, no overshoot (ฮถ=1.2, response=0.3s)
  • .gentle - Smooth and relaxed (ฮถ=1.0, response=0.8s)

Or create your own with precise control over damping ratio (ฮถ) and response time for exactly the feel you want.

๐Ÿš€ Getting Started

Installation

Add Kinetics to your Swift Package Manager dependencies:

dependencies: [
    .package(url: "https://github.com/your-username/Kinetics.git", from: "1.0.0")
]

Basic Usage

import Kinetics

struct ContentView: View {
    @State private var target = CGPoint(x: 200, y: 200)
    @State private var current = CGPoint.zero
    
    var body: some View {
        Circle()
            .fill(.blue)
            .frame(width: 50, height: 50)
            .position(current)
            .kinetics(
                target: $target,
                current: $current,
                spring: .playful
            )
            .onTapGesture {
                target = CGPoint(x: .random(in: 0...400), y: .random(in: 0...400))
            }
    }
}

๐ŸŽญ Why Kinetics?

Traditional animations feel robotic and disconnected from user input. Kinetics creates motion that:

  • Responds naturally to user gestures and input
  • Respects boundaries with intelligent collision handling
  • Maintains momentum for fluid, continuous motion
  • Adapts in real-time to changing targets and constraints
  • Feels alive with physics-based spring dynamics

๐Ÿ”ง Architecture

Kinetics is built on a robust, modern foundation:

  • Swift 6 & strict concurrency for safety and performance
  • Spring-mass-damper physics for natural motion
  • Frame-based clock for consistent timing
  • Generic value system supporting any geometric type
  • Boundary abstraction for flexible constraint handling
  • SwiftUI integration with automatic lifecycle management

๐Ÿ“ฑ Requirements

  • iOS 15.0+ / macOS 12.0+ / tvOS 15.0+ / watchOS 8.0+
  • Swift 6.0+
  • Xcode 15.0+

๐Ÿค Contributing

We love contributions! Whether it's bug reports, feature requests, or pull requests, your input helps make Kinetics better for everyone.

๐Ÿ“„ License

Kinetics is available under the MIT license. See the LICENSE file for more info.

About

Tunable, physics-driven motion primitives for SwiftUI.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages