Skip to content

Repository files navigation

ClockHandKit

ClockHandKit

Continuous, time-driven animations for iOS Home Screen widgets.

GitHub stars Latest release Swift 6.2 iOS 16 or later Xcode 26.1 or later MIT License

English · 한국어


Caution

ClockHandKit uses a private WidgetKit API. It may change without notice. Apps using it may not pass App Review.

Apple uses the same effect in its Clock widget. It doesn't expose the effect as a public API.

ClockHandKit directly accesses a private WidgetKit modifier: _ClockHandRotationEffect.

How it works

WidgetKit normally refreshes static timeline snapshots on a system-controlled schedule.

Public widget animations run when widget data changes. They are short transitions that last at most two seconds.

The standard timeline mechanism can't produce continuous frame-by-frame animation.

ClockHandRotationEffect works differently. It rotates a View inside WidgetKit according to the current time. It doesn't wait for a new timeline snapshot.

Place multiple animation frames around a circular wheel. Keep a viewport fixed so that it reveals only one frame. As the wheel rotates, the frames appear in sequence and look like an animation.

Frame animation created with a rotating wheel

ClockHandKit applies this rotation effect to third-party widgets. Your app builds the frame wheel and fixed viewport.

Usage and examples

The GIF above uses eight slots. Frames 1 through 4 appear twice.

The following code rotates an app-defined frame wheel once every eight seconds:

import SwiftUI
import ClockHandKit

// A frame wheel built by your app with eight slots
frameWheel
    .clockHandRotationEffect(period: .custom(8))

Eight slots complete one rotation in eight seconds. The next slot appears once per second. The four-frame sequence repeats every four seconds.

period is not the duration of a single frame. It is the time required for one full 360° rotation.

period = total frame slots / target FPS

For one copy of a 120-frame sequence:

Target rate period
12 FPS 10 seconds
24 FPS 5 seconds
30 FPS 4 seconds
60 FPS 2 seconds

Use .hourHand, .minuteHand, or .secondHand for clock hands. Use .custom(seconds) for frame animation.

Set the time zone with in. Set the rotation anchor with anchor.

The table shows target timing. WidgetKit and the device determine the actual rendering cadence.

Why ClockHandKit exists

Apps using ClockHandRotationKit worked when built with Xcode 26.0.1. Those builds also worked in the tested iOS 26.1+ environments.

The rotation effect wasn't applied when a third-party app built with Xcode 26.1 or later ran on iOS 26.1 or later. The app still compiled and linked successfully.

Investigation showed that WidgetKit added a runtime gate. The gate checks the linked SDK and the app's bundle identifier. For affected third-party apps, the private entry point returns the original View. It doesn't apply the modifier.

This is a WidgetKit runtime restriction. It isn't a Swift-version mismatch or a change to the JSON payload format.

ClockHandKit avoids the restricted entry point. It constructs and applies the underlying modifier directly.

Validation

  • ClockHandKit package builds
    • Xcode 26.1, 26.4, and 26.5
  • Example app and both Widget Extensions
    • Xcode 26.5
  • Runtime modifier bridge
    • iOS 26.1 and iOS 26.5 Simulators
  • Original entry-point cross-check
    • SDK 26.0 → iOS 26.1: works
    • SDK 26.1 → iOS 26.0: works
    • SDK 26.1 → iOS 26.1, third-party app: fails
  • ClockHandRotationKit compile/link matrix
    • Releases: 1.0.0, 1.0.1, and 1.1.0
    • Xcode: 26.0.1, 26.1.1, and 26.5
    • Targets: iOS arm64, Simulator arm64, and Simulator x86_64
    • Configurations: Debug and Release
    • Result: all 54 combinations compiled and linked

All 54 combinations built successfully. This isolates the regression to runtime behavior. It wasn't a compilation or linking failure.

Further reading:

Migrating from ClockHandRotationKit

Replace the import:

-import ClockHandRotationKit
+import ClockHandKit

ClockHandKit provides a TimeInterval overload for source-compatible migration:

.clockHandRotationEffect(period: 60)

The typed API is recommended for new code:

.clockHandRotationEffect(period: .secondHand)

ClockHandRotationKit declares iOS 14. ClockHandKit requires iOS 16 or later.

Do not import both modules into the same target. Their extension methods may conflict.

Acknowledgements ❤️

ClockHandKit was inspired by octree/ClockHandRotationKit. I contributed to that project as a collaborator.

My heartfelt thanks to octree for open-sourcing the original implementation and API. This work began there. ❤️

License

ClockHandKit is available under the MIT License.

About

WidgetKit clock hand rotation effect — works on Xcode 26.1+

Resources

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages