# Sticker: a holographic foil effect for SwiftUI views

> Sticker is a Swift package that renders a Pokemon-style foil effect over any SwiftUI view using Metal shaders, with ten parameters for the pattern, the noise, the light and the blend, three motion modes driven by the pointer, a drag gesture or the accelerometer, and a protocol you can implement to write your own. On recent operating systems the shaders can also be compiled at launch instead of on first use.

**bpisano/Sticker** — Holographic sticker effects for SwiftUI views.

- Repository: https://github.com/bpisano/Sticker
- Stars: 803 · Forks: 40
- Language: Swift
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/bpisano-sticker

## One view modifier for the whole effect

Sticker is a Swift Package that uses Metal shaders to apply a Pokemon-style foil effect to a view, and the demonstration in the README is a cursor moving over a sticker.

The effect is a shader rather than a stack of SwiftUI effects, which is what makes it look like foil. A holographic surface has several moving parts, the rainbow interference colours that shift with the viewing angle, a bright reflection that catches the light, a fine noise texture over the top and a checkered base pattern, and a foil effect is all of those at once. Doing that with compositing and gradients would be a large amount of view modifier stacking, and the result would be a bundle of drawing code you had to maintain.

The usage is a single modifier, .stickerEffect(), which can be applied to any view. The example in the README is an image from the asset catalogue with the modifier attached:

```swift
import Sticker

struct ContentView: View {
    var body: some View {
        Image(.stickerIcon)
            .stickerEffect()
    }
}
```

One detail is stated plainly and is worth knowing before you try it: by default, the effect is not animated. The static version is a foil finish, and the movement, the part where the shine tracks something, is a separate modifier that the next section covers.

The project is Swift, MIT licensed, on the main branch, with the last push on 2026-07-23. The releases are 1.2.1 in November 2024, 1.3.0 in December 2024 and 1.4.0 in January 2025.

## Adding it to a project

It is a Swift package, so adding it is a Package.swift entry:

```swift
dependencies: [
    .package(url: "https://github.com/bpisano/sticker", .upToNextMajor(from: "1.3.0"))
]
```

The upToNextMajor requirement means the range starts at 1.3.0 and stops before 2.0.0, so the package manager will pick up 1.4.0 when that is the newest release, and will not take a 2.0.0 if one appears.

That said, the version in the snippet is behind the newest release. The releases are 1.2.1, 1.3.0 and 1.4.0, and the README's example still starts from 1.3.0. It is not wrong, since 1.4.0 satisfies the range, but if you are pinning deliberately, read the changelog between 1.3.0 and 1.4.0 first, because a 1.x package can still change its defaults.

The repository is small in the way a Swift package usually is: a Package.swift, a Sources/ directory, a LICENSE, the README and a .github/ directory. There is no example application in the tree, which is worth noting, because it means the quickest way to see the effect is to build a small view yourself and attach the modifier.

## Ten parameters, and what each one moves

The parameter table is the part of the documentation that makes the effect tunable without touching a shader, and every entry has a default and a plain description.

The scale, .stickerScale(_:) at 3.0, controls the overall scale of the effect pattern. .stickerColorIntensity(_:) at 0.8 adjusts the strength of the holographic effect, which is the rainbow part. .stickerContrast(_:) at 0.9 modifies the contrast between light and dark areas, and .stickerBlend(_:) at 0.4 controls how much the effect blends with the original content, which is the knob that decides whether the view underneath still reads as itself.

Then there are the texture parameters. .stickerCheckerScale(_:) at 5.0 adjusts the scale of the checker pattern and .stickerCheckerIntensity(_:) at 1.2 controls the intensity of the checker effect. .stickerNoiseScale(_:) at 100.0 adjusts the scale of the noise pattern and .stickerNoiseIntensity(_:) at 1.2 controls the intensity of the noise effect. .stickerLightIntensity(_:) at 0.3 adjusts the intensity of the light reflection, the bright specular highlight.

And .stickerPattern(_:) defaults to diamond and modifies the checker pattern, so the base texture is not fixed to the shape in the screenshot.

The way these are used is by chaining after the effect:

```swift
Image(.stickerIcon)
    .stickerEffect()
    .stickerColorIntensity(0.5)
    .stickerNoiseScale(200)
    .stickerLightIntensity(0.5)
```

The example is a reasonable starting point for a different look, since it halves the colour intensity, doubles the noise scale and raises the light intensity from its default of 0.3 to 0.5.

## Motion: pointer, drag and accelerometer

The animated version is a separate modifier, .stickerMotionEffect(), and there are four values it accepts.

.pointerHover(intensity:) applies a 3D transform that looks at the pointer, with the intensity parameter controlling the strength of the effect. .dragGesture(intensity:) applies a 3D transform that follows drag gestures, again with the intensity controlling the strength. .accelerometer(intensity:maxRotation:updateInterval:) applies a 3D transform based on the device's accelerometer data, where the intensity controls the strength and maxRotation defines the maximum rotation angle, applying a smooth rotation to the specified angle. And .identity removes the motion effect.

The modifier is used inside an animation block, which is how the motion is driven:

```swift
Image(.stickerIcon)
    .animation(.snappy) { view in
        view
            .stickerEffect()
            .stickerMotionEffect(.pointerHover(intensity: 0.5))
    }
```

Using the .animation view modifier allows you to control the animation of the effect, and the example uses .snappy as the animation curve.

The three built-in modes cover the three situations where a shine can follow something: the pointer, which is the desktop case, a drag gesture, which is the case where the user is moving the content itself, and the accelerometer, which is the case where the device is moving. The intensity parameter is the same in all three, so the amount of tilt is tunable in the same way regardless of the input.

## Writing your own motion effect

The motion effects are not a closed set. You can create your own by implementing the StickerMotionEffect protocol, and the README gives a worked example that rotates the content with a sine wave:

```swift
struct MyMotionEffect: StickerMotionEffect {
    let startDate: Date = .init()

    func body(content: Content) -> some View {
        // Implement your motion effect here.
        // This example applies a sine wave rotation to the content.
        TimelineView(.animation) { context in
            let elapsedTime = context.date.timeIntervalSince(startDate)
            let rotation = sin(elapsedTime * 2) * 10
            content
                .rotationEffect(.degrees(rotation))
        }
    }
}
```

The shape of the protocol is a body method that takes the content and returns a view, which means a custom effect is just a function from content to view, and the built-in ones are no more privileged than yours. The example uses TimelineView with the animation schedule, so it is driven by the display refresh rather than by a timer, and it computes the rotation from the elapsed time since a start date captured when the effect was created.

The second half of the example is the piece that makes the type usable in the modifier chain, an extension on the protocol constrained to the concrete type, which provides a static property so the effect can be written as a value:

```swift
extension StickerMotionEffect where Self == MyMotionEffect {
    static var myMotionEffect: Self { .init() }
}
```

That pattern is the one to copy, because it is what lets your own effect sit in the same position as .pointerHover in the chain.

## Compiling the shaders before the first frame

The last section of the README is a performance note that has become more important with each operating system release.

On iOS 18, macOS 15 and visionOS 2, Apple added the ability to compile Metal shaders at runtime to prevent frame delay on first use. In other words, on those systems the shader compilation is deferred, and the first time the effect appears the compilation happens then, which is a visible hitch.

The fix is to compile the Sticker shaders as soon as your app launches, by calling a function from the package:

```swift
import SwiftUI
import Sticker

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .task {
                    await ShaderLibrary.compileStickerShaders()
                }
        }
    }
}
```

The .task modifier runs the call when the view appears, and the compile function is async, so it does not block the launch path.

That is a small addition to your app entry point and it removes a first-use stutter, which is the kind of detail that separates an effect that feels native from one that feels like a demo.

The repository itself is minimal: Package.swift, a Sources/ directory, the LICENSE, the README and a .github/ directory. There is no example app, so the fastest path to seeing the effect is a single view with the modifier, and the fastest path to shipping it is the same view plus the shader precompile.

## Conclusion

Adopt Sticker if you are building a SwiftUI interface that needs the shine of a foil card or a holographic sticker, because the whole effect is one view modifier and the parameters let you tune it without touching the shaders. Do not adopt it expecting a cross-platform effect, because the motion modes that read the accelerometer are tied to the device, and the runtime shader compilation trick only exists on the newest operating systems. Before you ship, compile the shaders at launch with ShaderLibrary.compileStickerShaders() so the first frame is not delayed, and check the installation snippet, which still starts from version 1.3.0 while the newest release is 1.4.0.

## FAQ

### How do I add the Sticker effect to a SwiftUI view?

Add the package to your Package.swift file, then apply the .stickerEffect() view modifier to any view. The effect is not animated by default, and the parameters such as .stickerScale, .stickerColorIntensity, .stickerBlend and .stickerPattern let you tune the pattern, the holographic strength, the blend and the checker shape.

### Which motion effects does Sticker support?

Four values of .stickerMotionEffect(): .pointerHover(intensity:) applies a 3D transform that looks at the pointer, .dragGesture(intensity:) follows drag gestures, .accelerometer(intensity:maxRotation:updateInterval:) follows the device accelerometer, and .identity removes the motion effect. The effect is animated by placing it inside an .animation block.

### Can I write my own motion effect for Sticker?

Yes, by implementing the StickerMotionEffect protocol. The protocol takes a body method that receives the content and returns a view, so a custom effect is a function from content to view, and the README's example rotates the content with a sine wave driven by a TimelineView.

### How do I avoid a frame delay when the Sticker effect first appears?

On iOS 18, macOS 15 and visionOS 2, Apple defers Metal shader compilation to runtime to prevent frame delay on first use. You can compile the Sticker shaders at launch by awaiting ShaderLibrary.compileStickerShaders() in a .task modifier in your app's root view.

## Sources

- [bpisano/Sticker on GitHub](https://github.com/bpisano/Sticker)
- [Issues](https://github.com/bpisano/Sticker/issues)
- [License: MIT](https://github.com/bpisano/Sticker/blob/main/LICENSE)
- [README](https://github.com/bpisano/Sticker/blob/main/README.md)
- [Releases](https://github.com/bpisano/Sticker/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/bpisano-sticker
