Back to articles
Apple DevelopmentUpdated 7 min read

Programmatic image generation with Apple’s Image Playground

Image Playground brings Apple’s image generation models into apps. Its ImageCreator API enabled custom, on-device generation without a system UI, but that path ends with iOS 27.

AppleApple IntelligenceImage PlaygroundImageCreatorSwiftUILocal AI

Image Playground is Apple’s framework for adding generative image creation to an app.

Apple announced Image Playground alongside Apple Intelligence in 2024 and made the feature publicly available with iOS 18.2 in December 2024. The programmatic ImageCreator API followed with iOS 18.4.

An app supplies concepts such as a short description, a longer piece of text, an image, or a drawing. Apple’s model turns those concepts into an image in a supported visual style. The app does not need to bundle a model, operate a server, or connect to a third-party image API.

There are three ways to integrate the framework:

The first two approaches give the user Apple’s complete creation interface. The third gives the app control over the interface and generation flow. This article focuses on that programmatic API, how it works on iOS 26, and why Apple is discontinuing it with iOS 27.

The status matters before looking at the code: Apple’s June 11, 2026 announcement says that ImageCreator is discontinued and no longer works on iOS 27, iPadOS 27, macOS 27, or visionOS 27. The implementation below is therefore an explanation and an iOS 26 reference, not the starting point for a new iOS 27 feature.

What programmatic creation changes

The standard Image Playground sheet owns the experience. It lets the user describe an image, choose a style, review variations, and accept a result. Your app can provide starting concepts, but the person remains inside a system-managed interface until they finish or cancel.

ImageCreator removes that interface from the flow. Your app collects the prompt, chooses the style, starts generation, and decides how to display the returned images. Apple presented it as the direct image-generation API in its overview of machine learning frameworks at WWDC 2025. It remained available through iOS 26.

That distinction is useful when the image feature needs to feel like part of the app rather than a separate tool. A drawing app might put generation behind its own canvas controls. A journaling app might turn an entry into an illustration. A game could create a small set of visual options from choices the player has already made.

The API is programmatic, but it is not a general background image service. Generation depends on a supported Apple Intelligence device and configuration, and it can fail when the app is hidden or in the background. The app also remains responsible for showing progress, handling cancellation and errors, and making it clear that generated content may be inaccurate.

The basic ImageCreator flow

The programmatic API has a small shape:

  1. Import ImagePlayground.
  2. Create an ImageCreator asynchronously.
  3. Describe the requested image with one or more ImagePlaygroundConcept values.
  4. Choose one of the creator’s available styles.
  5. Call images(for:style:limit:).
  6. Consume the results as they arrive from an asynchronous sequence.

At its simplest, the implementation looks like this:

swift
import ImagePlayground
 
let creator = try await ImageCreator()
 
guard let style = creator.availableStyles.first else {
    return
}
 
let images = creator.images(
    for: [.text("A small cabin beside a mountain lake at sunrise")],
    style: style,
    limit: 2
)
 
for try await image in images {
    let cgImage = image.cgImage
    // Add the image to your app’s state or save it.
}

Creating the ImageCreator is itself an availability check. Its asynchronous initializer throws when image generation is unsupported or temporarily unavailable. Once generation starts, the returned sequence can yield each result independently, so the interface can show the first image without waiting for every requested variation.

Understanding the parameters

Most of the behavior is expressed through the three arguments passed to images(for:style:limit:).

Concepts

The concepts array describes what the model should create. ImagePlaygroundConcept supports several kinds of input:

  • .text(...) wraps a word or brief description and passes short text directly to the model.
  • .extracted(from:title:) takes longer text and lets the system identify the ideas that matter for the image.
  • .image(...) uses a CGImage or an image file as visual input.
  • .drawing(...) turns a PencilKit drawing into a visual suggestion.

These are concepts, not a command language. They describe the intended content, while the model still decides composition and details. For a direct prompt such as “a red fox reading under an oak tree,” .text is the clearest choice. For a journal entry, story, or message, .extracted is more appropriate because the complete text may contain much more information than the image needs.

You can combine concepts when one input is not enough:

swift
let concepts: [ImagePlaygroundConcept] = [
    .text("A quiet birthday celebration"),
    .extracted(from: journalEntry, title: "Today’s memory"),
]

The system interprets the collection together. More concepts do not automatically produce a better image; each one should add useful context.

Style

ImagePlaygroundStyle controls the visual treatment. The original programmatic API includes Apple’s system styles such as animation, illustration, and sketch.

Do not assume that every style is available in every environment. ImageCreator.availableStyles is the source of truth, and passing a style that is not in that collection is a programmer error. A production interface should build its style picker from the available values or validate a preferred style before generation.

swift
guard creator.availableStyles.contains(.illustration) else {
    return
}
 
let style: ImagePlaygroundStyle = .illustration

Limit

limit is the maximum number of variations to generate for one request. The API accepts up to four.

Requesting several images gives the user a choice, but each additional result takes time and resources. A focused feature often needs only one or two. Because results arrive as a stream, the app should update its state inside the for try await loop rather than treating the request as a single array response.

A concrete SwiftUI implementation

My Localframe project is a small iOS 26 reference implementation of this flow. It uses a SwiftUI view model to keep generation logic separate from the interface.

The HomeViewModel implementation creates one ImageCreator, exposes animation, illustration, and sketch as selectable styles, and stores generated CGImage values in observable state. When the user submits a prompt, it clears the previous output, starts a request for two variations, and appends each result as it arrives:

swift
@Observable
@MainActor
final class HomeViewModel {
    var generatedImages: [CGImage] = []
    var inputPrompt = ""
    var error: ImageCreator.Error?
    var selectedStyle: ImagePlaygroundStyle = .animation
 
    private var imageCreator: ImageCreator?
 
    init() {
        Task {
            await loadCreator()
        }
    }
 
    private func loadCreator() async {
        do {
            imageCreator = try await ImageCreator()
        } catch {
            self.error = error as? ImageCreator.Error
        }
    }
 
    func generateImages(limit: Int = 2) async {
        guard let imageCreator else { return }
 
        do {
            generatedImages.removeAll(keepingCapacity: true)
 
            let images = imageCreator.images(
                for: [.text(inputPrompt)],
                style: selectedStyle,
                limit: limit
            )
 
            for try await image in images {
                generatedImages.append(image.cgImage)
            }
        } catch {
            self.error = error as? ImageCreator.Error
        }
    }
}

The full repository also models idle, generating, completed, and error states so SwiftUI can switch between a prompt view, progress view, results, and an error screen. Generated images remain in memory; Localframe does not persist them. That keeps the project narrow: it demonstrates the ImageCreator lifecycle and asynchronous result collection rather than presenting itself as a production image editor.

Availability and failure are part of the feature

Image Playground is a system capability, not a guarantee.

For Localframe’s iOS 26 implementation, generation requires a real Apple Intelligence-compatible iPhone, Apple Intelligence enabled on the device, and a supported device and Siri language. The iOS Simulator is not a supported runtime for generation and can return ImageCreator.Error.notSupported.

The framework’s ImageCreator.Error cases cover temporary unavailability, cancellation, unsupported input images or languages, failed creation, and attempts to generate while the app is in the background. Those states should become understandable product behavior: disable controls while the creator is loading, show progress during generation, preserve the prompt after a recoverable failure, and provide a useful fallback when the feature is unavailable.

This is the practical difference between a code sample and a shippable feature. Calling the model is short. Designing around its availability is most of the work.

What changes with iOS 27

Apple has not merely marked ImageCreator as an API to avoid in new code. The class is being discontinued.

According to Apple’s discontinuation announcement, the transition behaves differently during the beta period and after the public releases:

  • On beta OS releases, existing code can still compile with Xcode warnings, but apps using ImageCreator do not work in TestFlight and cause a runtime error.
  • With the public iOS 27, iPadOS 27, macOS 27, and visionOS 27 SDKs, code that depends on ImageCreator no longer compiles.

This is stronger than a normal deprecation. An availability branch around the old call is not a long-term migration strategy because the public SDK removes the ability to build that code.

The recommended replacement is the system Image Playground interface:

swift
@State private var showingPlayground = false
 
var body: some View {
    Button("Create image") {
        showingPlayground = true
    }
    .imagePlaygroundSheet(
        isPresented: $showingPlayground,
        concepts: [.text(inputPrompt)],
        onCompletion: { temporaryURL in
            saveGeneratedImage(from: temporaryURL)
        }
    )
}

The app can still seed the experience with concepts and a source image. With ImagePlaygroundOptions, it can also request a size and aspect ratio and configure personalization; a separate SwiftUI modifier selects and limits the styles shown in the sheet. The user then works through Apple’s interface, reviews the output, and explicitly accepts an image. The completion closure receives a temporary file URL, which the app must copy if it wants to keep the result.

Before presenting the sheet, a SwiftUI app should read supportsImagePlayground from the environment. It accounts for requirements such as device capability and the current language, allowing the app to disable the feature or present a fallback when generation is unavailable.

What disappears is direct, UI-free generation. An app can no longer call Apple’s model silently and place the returned CGImage into its own flow. If that level of control is essential, Apple’s alternative recommendation is to integrate another image-generation service.

Why Apple changed the API

The technical boundary moved with the model.

The iOS 26 ImageCreator path uses Apple’s on-device image generation model. For iOS 27, Apple describes a new, higher-quality model that runs on Private Cloud Compute. It supports broader styles, including photorealistic output, as well as different sizes and aspect ratios.

Apple now manages that server-backed experience end to end: privacy protections, interaction, previews, usage limits, and the final handoff to the app. As explained in the WWDC 2026 session Create high-quality images using Image Playground, the system handles usage limits, with increased access available through most iCloud+ plans. Developers do not operate the service or build quota UI themselves.

That is a meaningful tradeoff. The new framework path offers more capable image generation without an app-specific backend, but it also gives Apple control over the creation interface. For features designed around explicit user creation, the sheet is a natural fit. For automatic illustration or a completely custom generator, it changes what the app can be.

When Image Playground makes sense

Image Playground is most useful when generated images are part of a user-driven creative task:

  • artwork for a card, note, or journal entry
  • an avatar or profile image
  • visual variations based on an existing photo or drawing
  • a banner, thumbnail, or expressive icon
  • illustrations created from context the app already has

The framework’s value is not only that it generates an image. It provides a native route to Apple’s models without API keys, model packaging, or image-generation infrastructure.

For iOS 26, ImageCreator showed how compact a fully custom, on-device implementation could be. Localframe’s source code preserves that API as a focused reference. For iOS 27 and later, the same concepts continue to guide generation, but the user completes the task inside Apple’s system-managed Image Playground experience.