-
Unwrap PaperKit
Craft a canvas-based application with PaperKit. Explore the new data model APIs that let you access, create, and modify markup elements. Learn how to add custom controls and annotations, and discover best practices for integrating these features into your app to build a fully featured creative canvas.
Chapters
- 0:00 - Introduction
- 1:22 - Data model
- 3:41 - Elements
- 5:17 - Adornments
- 7:11 - Next steps
Resources
Related Videos
WWDC26
WWDC25
-
Search this video…
-
-
1:36 - Creating markup subelements
import PaperKit func generateMarkup(pageSize: CGSize, panelFrames: [CGRect], configuration: ShapeConfiguration) -> PaperMarkup { var markup = PaperMarkup(bounds: CGRect(origin: .zero, size: pageSize)) var subelements: MarkupOrderedSet = markup.subelements for panelFrame: CGRect in panelFrames { let shape = ShapeMarkup(frame: panelFrame, configuration: configuration) subelements.append(shape) } markup.subelements = subelements return markup } -
3:03 - Making template elements read-only
import PaperKit func generateMarkup(pageSize: CGSize, panelFrames: [CGRect], configuration: ShapeConfiguration) -> PaperMarkup { var markup = PaperMarkup(bounds: CGRect(origin: .zero, size: pageSize)) var subelements: MarkupOrderedSet = markup.subelements for panelFrame: CGRect in panelFrames { var shape = ShapeMarkup(frame: panelFrame, configuration: configuration) shape.allowedInteractions = .readOnly subelements.append(shape) } markup.subelements = subelements return markup } -
4:22 - Apply style to template elements
import PaperKit func updatePanelColor(_ selectedColor: CGColor) { guard var markup: PaperMarkup = paperMarkupViewController.markup else { return } var subelements: MarkupOrderedSet = markup.subelements for element in subelements { guard var shape = element as? ShapeMarkup else { continue } shape.strokeColor = selectedColor shape.fillColor = selectedColor.copy(alpha: 0.15) subelements.updateOrAppend(shape) } markup.subelements = subelements markup.backgroundColor = selectedColor.copy(alpha: 0.15) paperMarkupViewController.markup = markup } -
5:53 - Add adornments to each panel
import PaperKit func addPanelAdornments(for page: Page) { var adornments: [MarkupAdornment] = [] for (panelIndex, panel) in page.panels.enumerated() { let adornmentID = UUID() adornmentPanelMapping[adornmentID] = panelIndex let center = CGPoint(x: panel.midX, y: panel.midY) let adornment = MarkupAdornment( id: adornmentID, anchor: .canvas(location: center), imageConfiguration: .systemImage("photo.badge.plus"), dragRegion: .fixed, scalesWithZoom: false ) adornments.append(adornment) } paperMarkupViewController.adornments = adornments } -
6:08 - Handle adornment taps
import ImagePlayground import PaperKit func paperMarkupViewController(_ paperMarkupViewController: PaperMarkupViewController, didTapAdornmentWithID id: UUID) { guard let panelIndex = adornmentPanelMapping[id] else { return } activeImageGenerationPanelIndex = panelIndex let imagePlaygroundViewController = ImagePlaygroundViewController() imagePlaygroundViewController.delegate = self present(imagePlaygroundViewController, animated: true) } -
6:20 - Place the generated image
import ImagePlayground import PaperKit func imageViewController(_ imageViewController: ImagePlaygroundViewController, didCreateImageAt imageURL: URL) { guard let panelFrame = activeGenerationPanelFrame, let paperMarkupViewController = pageViewController.paperViewController, var markup = paperMarkupViewController.markup, let image = UIImage(contentsOfFile: imageURL.path) else { return } let imageMarkup = ImageMarkup(frame: panelFrame, image: image) markup.subelements.append(imageMarkup) paperMarkupViewController.markup = markup }
-
-
- 0:00 - Introduction
Meet PaperKit, the canvas behind Notes, Preview, and Freeform, now open to your apps in iOS, macOS, and visionOS 27 — covering the data model, elements, and adornments.
- 1:22 - Data model
PaperMarkup's new subelements property exposes every canvas element as a readable, writable ordered set, and allowedInteractions gives fine-grained control over what each element permits.
- 3:41 - Elements
Each element has a concrete type — shapes, images, links, loupes, and pencil strokes — with its own properties, and PaperKit builds on PencilKit so Apple Pencil strokes become markup elements.
- 5:17 - Adornments
Markup adornments are visual overlays anchored to canvas coordinates — ideal for buttons, annotations, and collaboration UI — that track zoom and scroll and stay separate from persisted markup.
- 7:11 - Next steps
Building a fully interactive canvas experience with PaperKit — using the data model to read and modify canvas contents, and adding adornments for interactive overlays tailored to your app.