Image Outpainting Brush Tool UI in SwiftUI
The brush paints a mask, not the photo. Soft edges are the single biggest quality lever in the whole tool.
TL;DR
An image outpainting brush tool splits cleanly: the model generates pixels, the app builds the spec, the original image, a mask of which region is new, the canvas dimensions, and an optional prompt. The brush exists to paint that mask, best done as a separate PencilKit PKCanvasView producing a grayscale mask with feathered edges (the single biggest quality lever, since hard masks leave seams) and an eraser as half the interaction. Generation is slow and metered, so the UI shows cost before the tap, a real progress state, and 2-4 pickable results, with non-destructive history at the generation level. Be honest about synthetic pixels and cloud uploads. A free VP0 design supplies the canvas and result screens.
What is outpainting, and what is the app’s actual job?
Outpainting extends an image beyond its original borders: the user pushes the canvas edge outward and a model invents plausible pixels to fill the new space, the same generative-fill idea as the desktop photo editors, on a phone. The build splits cleanly in two, and confusing the halves is where these apps go wrong: the model does the generating; the app does everything else, and everything else is most of the work.
The app’s actual job is a precise spec for the model: the original image, a mask marking exactly which region is new versus original, the canvas dimensions, and an optional text prompt for what should appear. The brush tool exists to paint that mask. So the interesting UI question is not “how do I generate pixels” (that is an API call), it is “how do I let a finger draw a clean, editable mask that a model can act on.”
How does the brush-painted mask actually work?
As a separate drawing layer composited over the image, never strokes baked into the photo. PencilKit is the fast path on Apple platforms: a PKCanvasView over the image captures finger or Apple Pencil strokes with pressure and smoothing already solved, and you read its drawing as the mask. The alternative is a hand-rolled Canvas-plus-gesture layer when you need full control of the brush behavior.
Either way, the mask is a grayscale image the same size as the canvas: white where the model should generate, black where the original is preserved (or the inverse, matching your API’s contract). Compositing that mask over the photo for the live preview is a Core Image blend, kept separate from the export pipeline. The brush mechanics that make it usable:
- Soft edges by default. A hard-edged mask produces a visible seam where generated meets original; a feathered brush (a soft alpha falloff) lets the model blend, which is the single biggest quality lever in the whole tool.
- Adjustable size, and an eraser. Masking is iterative: paint too much, erase back. The eraser is not optional, it is half the interaction.
- A visible mask overlay. Render the painted region as a semi-transparent tint so the user sees exactly what they have selected before spending a generation on it.
For outpainting specifically, the common gesture is not just brushing but dragging the canvas edge outward: the new transparent border auto-becomes the masked region, and the brush refines from there. Both paths feed the same mask.
Where does the generation honesty live?
In the wait, the cost, and the result handling. Generation is slow (seconds, sometimes many) and usually metered: a hosted image-generation API bills per image and commonly returns squares around 1,024 pixels you then place on the canvas. The UI owes three honesties:
| Reality | What the UI must do |
|---|---|
| Generation takes real time | A genuine progress state, not a fake spinner that finishes early |
| Each generation costs money/credits | Show the cost before the tap; never silently burn credits |
| Models return variations | Offer 2-4 results to pick from, with one-tap regenerate |
The result is never final on arrival: outpainting is iterative, so the new pixels become the new canvas, and the user masks again to extend further. That means non-destructive history (undo the last generation, not just the last brush stroke) is core, the same compare-and-revert discipline as any AI photo editing tool where the user must trust they can get back. And the cost-before-action rule is the same honest-metering pattern as the AdMob monetization genre: the user always knows what an action will spend.
What completes the tool?
Export discipline and content honesty. Outpainting changes aspect ratio (a square photo becoming a landscape), so the export flow shows the new dimensions and offers the obvious targets (the original ratio, a story at 1,080 by 1,920, a square). Keep the original untouched and exportable alongside the edited version, because users want both.
Two content-honesty points the genre cannot skip. Generated regions are invented, not photographed, so an app used for anything documentary (real estate, journalism, marketplace listings) should be clear that outpainted areas are synthetic; quietly extending a property photo is a real problem. And on-device versus cloud is a privacy decision worth surfacing: cloud generation means the user’s photo leaves the device, which the permission and upload moment should state plainly rather than bury.
The screens, the canvas, the brush controls, the result picker, the export sheet, come as free VP0 designs an agent generates the brush-and-mask layer onto, so the PencilKit canvas sits in a UI built for the iterate-and-extend loop instead of a single-shot editor.
Key takeaways: an outpainting brush tool
- The model generates; the app builds the spec: image, mask, dimensions, prompt, and the brush exists to paint the mask.
- Mask the right way: a separate PencilKit layer, grayscale output, soft feathered edges (the biggest quality lever), with an eraser as half the tool.
- Show the cost before the tap and a real progress state: generation is slow and metered.
- Non-destructive history at the generation level: each result becomes the new canvas; undo must reach back.
- Be honest about synthetic pixels and cloud uploads: outpainted regions are invented and may leave the device.
Frequently asked questions
How do I build an image outpainting brush tool in SwiftUI? Put a PencilKit PKCanvasView over the image to capture brush strokes as a grayscale mask (white where the model generates, black where the original stays), feather the brush edges for seamless blends, and send the image, mask, canvas size, and optional prompt to your generation API. A free VP0 design supplies the canvas, brush controls, and result-picker screens.
What does the brush actually do in an outpainting app? It paints the mask, not the photo. The mask is a separate grayscale layer marking which pixels the model should generate versus preserve, so the brush, its size, soft edges, and eraser, is the tool for authoring that selection precisely before any generation runs.
Why is my outpainting result seamy at the edges? Almost always a hard-edged mask. A feathered brush with a soft alpha falloff gives the model a blend zone where generated meets original, and it is the single biggest quality lever in the tool; hard masks produce a visible seam no model fully hides.
Does the app generate the new pixels itself? No: generation is a model API call, on-device or cloud. The app’s job is authoring the spec (image, mask, dimensions, prompt), handling the slow metered wait honestly, and managing iterative non-destructive results. Confusing the two halves is the common design mistake.
Should outpainted images be labeled as edited? For any documentary use, yes: real estate, journalism, and marketplace listings need the synthetic regions disclosed, since outpainting invents pixels rather than capturing them. Quietly extending a real photo is a genuine integrity problem, and the export flow is the place to make the distinction clear.
More questions from VP0 vibe coders
How do I build an image outpainting brush tool in SwiftUI?
Put a PencilKit PKCanvasView over the image to capture brush strokes as a grayscale mask (white where the model generates, black where the original stays), feather the brush for seamless blends, and send the image, mask, canvas size, and optional prompt to your generation API. A free VP0 design supplies the canvas, brush, and result-picker screens.
What does the brush actually do in an outpainting app?
It paints the mask, not the photo. The mask is a separate grayscale layer marking which pixels the model should generate versus preserve, so the brush, with its size, soft edges, and eraser, is the tool for authoring that selection precisely before any generation runs.
Why is my outpainting result seamy at the edges?
Almost always a hard-edged mask. A feathered brush with a soft alpha falloff gives the model a blend zone where generated meets original, and it is the biggest quality lever in the tool; hard masks produce a visible seam no model fully hides.
Does an outpainting app generate the new pixels itself?
No: generation is a model API call, on-device or cloud. The app authors the spec (image, mask, dimensions, prompt), handles the slow metered wait honestly, and manages iterative non-destructive results. Confusing the generation and authoring halves is the common mistake.
Should outpainted images be labeled as edited?
For documentary use, yes: real estate, journalism, and marketplace listings need synthetic regions disclosed, since outpainting invents pixels rather than capturing them. Quietly extending a real photo is an integrity problem, and the export flow is where to make the distinction clear.
Part of the Native Apple & SwiftUI: The iOS Ecosystem hub. Browse all VP0 topics →
Keep reading
Midjourney-Style Image Grid Selector UI in SwiftUI
The grid is the decision screen: each cell a state machine, tap-to-focus selection, first-class re-roll, and honesty about cost, wait, and failures.
Pet Breed Identifier Camera AI UI in SwiftUI
The model classifies; the app presents uncertainty honestly. On-device Core ML, top-three confidences, capture coaching, and a fun estimate, not a pedigree.
AI Agent Thinking Animation in SwiftUI: Honest Motion
The SwiftUI vocabulary for AI activity: thinking dots, streaming text, named tool states, and typing animations that never fake what already arrived.
AI Essay Grader Feedback Highlight UI: Teacher in the Loop
Design an AI essay grading UI: span-anchored highlights, rubric-mapped feedback categories, the teacher approval pass, and student views built for revision.
SwiftUI Audio Transcription Template: Whisper On-Device
Build a SwiftUI transcription app with Whisper on-device via WhisperKit or Apple's Speech framework: live partials, model size trade-offs, and privacy honesty.
Build a Stock Market Heat Map Grid UI in SwiftUI
A market heat map colors and sizes tiles by gain and market cap. Here is how to build the stock market heat map grid in SwiftUI, with an accessible color scale.