Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TweakIt

Adjust anything at runtime. Ship nothing to production.

TweakIt is a spiritual successor to SwiftTweaks — the beloved library that let you fine-tune your app without recompiling. TweakIt brings that same magic to modern SwiftUI with a declarative DSL, real-time editing, and zero production overhead.

TweakIt category browser with custom tabs   Real-time shader tweaking with TweakIt   TweakIt sliders with modification indicators

Why?

Because recompiling to change an animation duration by 0.05 seconds is a crime against your time.

TweakIt lets you define tweakable parameters once and get a full debug panel for free. Drag sliders, flip toggles, pick options — see changes instantly without a rebuild.

Features

  • Declarative DSL — Define tweaks with result builders. Types infer the controls automatically.
  • Real-time editing — Sliders, toggles, text fields, pickers, steppers, and action buttons.
  • Swipe to reset — Changed a value? Swipe any row to snap it back to its default.
  • Modification tracking — Orange dots show what you've changed at a glance.
  • Custom tabs — Add your own SwiftUI views alongside the built-in tweaks browser.
  • Floating button + gesture — Tap the button or two-finger double-tap anywhere to open.
  • Section master toggles — Enable/disable entire feature flag groups with one switch.
  • Release-safe by default — When disabled, all APIs no-op and TweakRef returns defaults directly. Active in DEBUG builds automatically, or opt-in for any build config with one line: TweakIt.isEnabled = true.

Quick Start

1. Define your tweaks

import TweakIt

enum AppTweaks {
    static let store = TweakStore {
        TweakCategory("Animations", icon: "sparkles") {
            TweakSection("Spring") {
                TweakDefinition("duration", default: 0.46, range: 0.1...2.0)
                TweakDefinition("damping", default: 0.8, range: 0.1...1.0)
            }
        }
        TweakCategory("Debug", icon: "ladybug") {
            TweakSection("Network") {
                TweakDefinition("mockMode", default: false)
                TweakDefinition("endpoint", default: "production",
                                options: ["production", "staging", "local"])
            }
        }
    }
}

2. Install the panel

#if DEBUG
TweakPanel.install(store: AppTweaks.store)
#endif

Internal/TestFlight builds: Set TweakIt.isEnabled = true before calling install() to enable tweaks in any build config. This works regardless of SPM limitations — no special compiler flags needed on the package itself.

3. Read values

let duration: CGFloat = AppTweaks.store["Animations.Spring.duration"]

That's it. The panel appears via a floating button or two-finger double-tap.

Control Types

The control is inferred from your default value and parameters:

Definition Control
TweakDefinition("flag", default: true) Toggle
TweakDefinition("speed", default: 0.5, range: 0.0...1.0) Slider
TweakDefinition("columns", default: 3) Stepper
TweakDefinition("columns", default: 3, range: 1...10) Integer slider
TweakDefinition("name", default: "hello") Text field
TweakDefinition("env", default: "prod", options: ["prod", "staging"]) Picker
TweakDefinition("reset", action: { ... }) Action button

Action buttons don't store a value — they fire a closure on tap. Great for debug shortcuts like resetting state or clearing caches.

TweakRef — Typed Handles

For ergonomic access, TweakRef gives you a typed handle with modification tracking:

static let duration: TweakRef<CGFloat> = store.ref("Animations.Spring.duration")

// Read/write:
AppTweaks.duration.value        // 0.46
AppTweaks.duration.value = 0.5
AppTweaks.duration.isModified   // true
AppTweaks.duration.reset()      // back to 0.46

In release builds, .value returns the compile-time default directly — zero overhead.

Custom Tabs

Add your own panels alongside the built-in tweaks browser:

TweakPanel.install(
    store: AppTweaks.store,
    tabs: [
        TweakTab("Actions", icon: "bolt") { ActionsView() },
        TweakTab("Stats", icon: "chart.bar") { StatsView() },
    ]
)

Shake to Toggle

By default, shaking the device toggles the floating button's visibility. This uses method swizzling on UIWindow.motionEnded(_:with:) (scoped to UIWindow only, debug builds only).

If you prefer to avoid swizzling, disable it and trigger the button yourself:

TweakPanel.install(store: AppTweaks.store, shakeToToggleButton: false)

You can then toggle the button programmatically via TweakPanel.buttonState:

// In your own shake handler or gesture recognizer:
TweakPanel.buttonState?.toggle()

Installation

Swift Package Manager:

https://github.com/warpling/TweakIt.git

iOS 16+ · Swift 5.9+ · Zero dependencies

Acknowledgments

TweakIt is a spiritual successor to SwiftTweaks by Bryan Clark, which pioneered the idea of runtime-tweakable parameters for iOS. SwiftTweaks was a joy to use and a huge inspiration — TweakIt aims to carry that torch forward with a modern Swift DSL and SwiftUI.

License

MIT. See LICENSE for details.

About

Runtime debug tweaks for iOS — zero-dependency SwiftUI panel with result builder DSL, UserDefaults persistence, and custom tabs

Resources

Stars

8 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages