-
Create high-quality images using Image Playground
Enable high-quality image creation in your app using Image Playground. With a new generative model that runs on Private Cloud Compute, users can make images in virtually any style, including photorealistic, in your app. You can also specify dimensions for use in even more places, and allow people to modify images using natural language descriptions and touch. Explore how to adopt Image Playground, generate images from descriptions and photos, and manage feature availability in your app.
Chapters
- 0:00 - Introduction
- 2:03 - Capabilities
- 5:02 - Adopt Image Playground
- 8:29 - Options
- 12:15 - Availability
Resources
Related Videos
WWDC26
- Build with the new Apple Foundation Model on Private Cloud Compute
- Read between the strokes with PencilKit
WWDC24
-
Search this video…
Hi, I'm Antonio, an Engineer on the Image Playground team.
Today, I'll show you how to bring Image Playground into your app.
People have been creating images with Image Playground in Messages, Freeform, and in your apps. They have been combining scenes, experimenting with different looks, and making things feel personal.
We are reimagining the experience with powerful image models at the core.
And now, it makes a real leap, with the ability to make high quality images in virtually any style, even photorealistic ones, that now look genuinely true to life.
The ImagePlayground framework brings that full experience, the same powerful models, the same styles, the same quality, directly into your app.
The Image Playground app is available on iOS, iPadOS, macOS, and visionOS. It runs on devices with Apple Intelligence support, bringing the full power of generative models to your app.
Just like the Image Playground app, you can leverage ImagePlayground.framework APIs on the same platforms. Let's walk through how you can add Image Playground to your app.
I'll start with capabilities, a look at what the image creation model can create.
Then I'll show you how to adopt Image Playground, how to present the sheet and seed it with context from your app.
After that, options, configuring size, aspect ratio, and style.
And finally, availability, making sure your app handles both supported and unsupported devices gracefully.
Before writing any code, let's look at what Image Playground can enable in your app. Give the model a text description, and it creates a matching image. You can be as specific or as open-ended as you like; "a birthday celebration with dogs, balloons and confetti" or just "celebration." The model handles the rest.
The model can create images with people, including multiple people in a single scene. With personalization enabled, users can bring in someone from their Photos library or simply describe an appearance using text.
The result is an image that feels personal. You have a range of styles to work with. You can ask for an image without specifying a style.
You can specify your desired style in text, such as by asking for an oil painting style.
Or use one of our presets.
Animation adds playful character.
Illustration gives a polished, editorial look.
Sketch creates a hand-drawn feel.
Genmoji is a style tuned for expressive, emoji-scale characters you can embed directly in text.
Image Playground supports multiple sizes and aspect ratios. You can request a landscape image for a banner.
A portrait image for full screen on iPhone. Or square for a thumbnail.
The model picks the closest supported resolution to the size you ask for. All of this runs on Private Cloud Compute, Apple's privacy-preserving cloud infrastructure. Your data is never stored or shared, even with Apple.
For a deeper look at how it works, check out "Build with the new Apple Foundation Model on Private Cloud Compute".
Image Playground has a usage limit because it relies on powerful server models. Increased access is available with most iCloud+ subscription plans. And as the developer, none of this is your problem to solve. There's no server to provision, no infrastructure to maintain.
The system manages usage limits on behalf of your users, you never need to build any usage-related UI.
You call the framework. Apple handles the rest. Moving the models to Private Cloud Compute also meant rethinking the API. ImageCreator, the non-UI API for generating images directly in your code, is deprecated.
Everything is now available through a new API with greater image quality, built-in privacy, and a full experience people already know how to use.
If your app uses ImageCreator today, keep watching. So now let us look at how to add Image Playground to your app.
To show you how this comes together in code, I've been building Postcards, a greeting card creator.
With Postcards, you can design custom cards, write a personal message, and choose a layout.
The last piece is custom artwork for the front of each card. That's where Image Playground comes in. Adopting Image Playground starts with one view modifier. No SDK initialization, no API keys, no server endpoints, just the modifier. I add .imagePlaygroundSheet to my button with a binding to a @State boolean.
When the binding flips to true, the sheet appears. Image Playground handles everything, the UI, the model interaction, the style picker.
When someone accepts an image, the completion closure receives a URL to the generated file. That URL points to a temporary location inside your app container, save it elsewhere before the session ends.
The sheet drops into your app as a fully-formed, consistent experience. The user can type a description, browse style options, include people from their library, and preview results before confirming. Your app gets the final URL, ready to display.
The sheet can open with an empty prompt or can be seeded with context from your app for a richer initial experience.
ImagePlaygroundConcept has two factory methods here: text wraps a direct description, I'm passing the card's theme, like cherry blossoms; extracted takes longer text and lets the system pull out the most relevant ideas, I'm passing the card's message, so the model picks up on what the card is about.
With concepts in place, the sheet opens already primed for this specific card. The user doesn't have to start from scratch. You can also seed the sheet with an image. Pass any SwiftUI Image to the sourceImage parameter, a photo the person picked from their library, or an image the card already has.
Image Playground uses it as visual inspiration alongside the concepts. The user can replace or refine it inside the sheet, it's a starting point, not a constraint. On iPad, Postcards shows a small canvas below the card front. ImagePlaygroundConcept.drawing takes a PKDrawing from PencilKit and adds it as a concept alongside the text. The model treats the strokes as a visual suggestion, they guide the composition without locking it in. To know more about drawings in PencilKit, check out "Read between the strokes with PencilKit".
If you're building a UIKit or AppKit app, ImagePlaygroundViewController gives you the same experience as a view controller. Set concepts and options as properties before presentation, then implement imagePlaygroundViewController, didCreateImageAt on the delegate to receive the result. The API mirrors SwiftUI.
Now, let's configure the sheet to fit Postcards, configuring options like size, style, and personalization.
ImagePlaygroundOptions and ImagePlaygroundStyle allow you to manage the configuration of the playground, size and aspect ratio, available and preselected styles, and personalization. Whether you're generating card artwork, a lock screen wallpaper, a banner, or a Genmoji icon, the same API adapts to fit. Postcards supports three card formats: landscape, portrait, and square. Each format stores a CGSize I pass it directly to .closest(to: , and the system maps it to the closest supported aspect ratio and resolution.
Because format is a property of the card, the size request adapts automatically. A landscape card requests a wide image, a portrait card requests a tall one.
I pass the options to the sheet using .imagePlaygroundOptions.
ImagePlaygroundStyle has several values, like: illustration, sketch, animation, and emoji.
imagePlaygroundGenerationStyle takes two arguments: a default style that the picker opens on, and an allowed list that limits which styles appear. If you pass a single style in the allowed list, the picker locks to that style.
In Postcards, each card carries a StylePreset that maps directly to these values. A classic card defaults to illustration, and allows only illustration and sketch. While an expressive card defaults to animation and also allows illustration and emoji. The style picker automatically reflects whichever card is open.
externalProvider is an opt-in style that surfaces whatever third-party provider the person has configured in Settings, ChatGPT, for example. To offer it, append it to your .allowedStyles list.
If the user has a provider configured, the tab appears in the picker.
If they haven't, the system handles its setup, no check required on your side. You can also pass it as the default style if your app has a context where that makes sense.
Either way, the picker adapts to what's actually available. ImagePlaygroundStyle.emoji is tuned for expressive, emoji-scale characters. When it's active, the sheet fires a separate completion, onAdaptiveImageGlyphCreation, and hands you an NSAdaptiveImageGlyph instead of a URL. An adaptive image glyph is special - it can be embedded directly inline with text, just like an emoji, which is exactly what you want for a card thumbnail that appears next to the recipient's name.
For everything you can do with adaptive image glyphs in text, rendering, storing, custom text engines, check out "Bring expression to your app with Genmoji".
Personalization is enabled by default. It lets people include someone from their Photos library, a powerful way to make a greeting card feel genuinely personal.
If your app context doesn't call for it, say, you're building a product image generator, you can set options.personalization to disabled.
The people picker and name detection disappear from the sheet entirely. Last up: making sure Postcards handles every device gracefully. Image Playground is available on devices that support Apple Intelligence, across a growing set of languages and regions, and when the user has image generation enabled in Settings. The supportsImageGeneration environment value is all you need. It returns true when image generation is fully available, the device has the capability, the current language and region are supported, and the user has it enabled.
When it's true, I navigate to CardEditorView, the full Image Playground experience. When it's false, I navigate to CardPickerView, a simple Photos picker fallback.
No entitlement, no extra capability check, no setup step, just the environment value and a conditional. That's all it takes to support both paths cleanly.
With Image Playground, it's easy to provide a high-quality image creation experience in your app.
Consider where images live in your design. A card someone sends to a friend.
A profile that represents them.
A message they've been trying to put into words.
The right shape and feel changes everything.
And then think about what only your app knows. What relationships, what memories, what context can you bring into the picture to make the result feel like it was made for that specific person? That's the real opportunity. Image Playground brings the models, you bring the story. Thanks for watching, now go build something that earns a spot on someone's refrigerator.
-
-
5:28 - Adopt Image Playground in SwiftUI
// Adopt Image Playground in SwiftUI func imagePlaygroundSheet( isPresented: Binding<Bool>, concepts: [ImagePlaygroundConcept] = [], sourceImage: Image? = nil, onCompletion: @escaping (URL) -> Void, onCancellation: (() -> Void)? = nil ) -> some View -
5:39 - Add Image Playground sheet with binding to @State
// Adopt Image Playground @State private var showingPlayground = false var body: some View { Button("Create image") { showingPlayground = true } .imagePlaygroundSheet( isPresented: $showingPlayground, onCompletion: { url in var updated = currentCard store.saveImage(url, for: &updated) } ) } -
6:29 - Seeding the sheet with context from your card
// Seeding the sheet with context from your card var concepts: [ImagePlaygroundConcept] { [ .text(card.theme), .extracted(from: card.message, title: card.theme), ] } var body: some View { Button("Create image") { showingPlayground = true } .imagePlaygroundSheet( isPresented: $showingPlayground, concepts: concepts, onCompletion: { url in var updated = card store.saveImage(url, for: &updated) } ) } -
7:11 - Starting from a reference photo
// Starting from a reference photo @State private var sourceImage: Image? var body: some View { Button("Create image") { showingPlayground = true } .imagePlaygroundSheet( isPresented: $showingPlayground, concepts: concepts, sourceImage: sourceImage, onCompletion: { url in var updated = card store.saveImage(url, for: &updated) } ) } -
7:42 - Providing a visual suggestion using a drawing
// Providing a visual suggestion using a drawing @State private var drawing = PKDrawing() var concepts: [ImagePlaygroundConcept] { var result: [ImagePlaygroundConcept] = [ .text(card.theme), .extracted(from: card.message) ] if !drawing.strokes.isEmpty { result.append(.drawing(drawing)) } return result } -
8:06 - Adopt Image Playground in UIKit or AppKit
// Adopt Image Playground in UIKit or AppKit func presentViewController() { let viewController = ImagePlaygroundViewController() viewController.concepts = [ .text(card.theme), .extracted(from: card.message) ] viewController.delegate = self present(viewController, animated: true) } func imagePlaygroundViewController( _ viewController: ImagePlaygroundViewController, didCreateImageAt url: URL ) { var updated = card store.saveImage(url, for: &updated) dismiss(animated: true) } -
9:02 - Size Specification
// Size Specification var options: ImagePlaygroundOptions { var options = ImagePlaygroundOptions() options.sizeSpecification = .closest(to: card.format.size) return options } var body: some View { Button("Create image") { showingPlayground = true } .imagePlaygroundSheet( isPresented: $showingPlayground, concepts: concepts, onCompletion: { url in var updated = card store.saveImage(url, for: &updated) } ) .imagePlaygroundOptions(options) } -
9:39 - Styles
// Styles var options: ImagePlaygroundOptions { var options = ImagePlaygroundOptions() options.sizeSpecification = .closest(to: card.format.size) return options } var body: some View { Button("Create image") { showingPlayground = true } .imagePlaygroundSheet( isPresented: $showingPlayground, concepts: concepts, onCompletion: { url in var updated = card store.saveImage(url, for: &updated) } ) .imagePlaygroundOptions(options) .imagePlaygroundGenerationStyle( pendingStylePreset.defaultStyle, in: pendingStylePreset.allowedStyles ) } -
10:27 - External Provider Style
// External Provider Style var options: ImagePlaygroundOptions { var options = ImagePlaygroundOptions() options.sizeSpecification = .closest(to: card.format.size) return options } var body: some View { Button("Create image") { showingPlayground = true } .imagePlaygroundSheet( isPresented: $showingPlayground, concepts: concepts, onCompletion: { url in var updated = card store.saveImage(url, for: &updated) } ) .imagePlaygroundOptions(options) .imagePlaygroundGenerationStyle( pendingStylePreset.defaultStyle, in: pendingStylePreset.allowedStyles + [.externalProvider] ) } -
11:02 - Generating an expressive icon for the card thumbnail
// Generating an expressive icon for the card thumbnail @State private var showingIconPlayground = false var body: some View { Button("Create icon") { showingIconPlayground = true } Color.clear .imagePlaygroundSheet( isPresented: $showingIconPlayground, concepts: concepts, onCompletion: { _ in } , onAdaptiveImageGlyphCreation: { glyph in var updatedCard = card store.saveIcon(glyph, for: &updatedCard) } ) .imagePlaygroundGenerationStyle(.emoji, in: [.emoji]) } -
12:01 - Disabling personalization when it doesn't fit your context
// Disabling personalization when it doesn't fit your context var options: ImagePlaygroundOptions { var options = ImagePlaygroundOptions() options.sizeSpecification = .closest(to: card.format.size) options.personalization = .disabled return options } -
12:32 - Supports image generation
// Supports image generation @Environment(\.supportsImageGeneration) private var supportsImageGeneration var body: some View { NavigationLink(card.recipient) { if supportsImageGeneration { CardEditorView(card: card) }γelse { CardPickerView(card: card) } } }
-
-
- 0:00 - Introduction
The ImagePlayground framework brings high-quality, true-to-life image creation into your app, on devices with Apple Intelligence support.
- 2:03 - Capabilities
Image Playground enables the creation of high-quality images with people, styles, and different aspect ratios.
- 5:02 - Adopt Image Playground
Present the Image Playground sheet and seed it with context from your app.
- 8:29 - Options
Configure the Image Playground sheet with options like size, style, and personalization.
- 12:15 - Availability
Ensure your app gracefully handles both supported and unsupported devices, presenting the full Image Playground experience when available.