View in English

  • Apple Developer
    • Get Started

    Explore Get Started

    • Overview
    • Learn
    • Apple Developer Program

    Stay Updated

    • Latest News
    • Hello Developer
    • Platforms

    Explore Platforms

    • Apple Platforms
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    Featured

    • Design
    • Distribution
    • Games
    • Accessories
    • Web
    • Home
    • CarPlay
    • Technologies

    Explore Technologies

    • Overview
    • Xcode
    • Swift
    • SwiftUI

    Featured

    • Accessibility
    • App Intents
    • Apple Intelligence
    • Games
    • Machine Learning & AI
    • Security
    • Xcode Cloud
    • Community

    Explore Community

    • Overview
    • Meet with Apple events
    • Community-driven events
    • Developer Forums
    • Open Source

    Featured

    • WWDC
    • Swift Student Challenge
    • Developer Stories
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Centers
    • Documentation

    Explore Documentation

    • Documentation Library
    • Technology Overviews
    • Sample Code
    • Human Interface Guidelines
    • Videos

    Release Notes

    • Featured Updates
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • Downloads

    Explore Downloads

    • All Downloads
    • Operating Systems
    • Applications
    • Design Resources

    Featured

    • Xcode
    • TestFlight
    • Fonts
    • SF Symbols
    • Icon Composer
    • Support

    Explore Support

    • Overview
    • Help Guides
    • Developer Forums
    • Feedback Assistant
    • Contact Us

    Featured

    • Account Help
    • App Review Guidelines
    • App Store Connect Help
    • Upcoming Requirements
    • Agreements and Guidelines
    • System Status
  • Quick Links

    • Events
    • News
    • Forums
    • Sample Code
    • Videos
 

Videos

Open Menu Close Menu
  • Collections
  • All Videos
  • About

Back to WWDC26

  • About
  • Summary
  • Transcript
  • Code
  • 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

    • PaperKit
      • HD Video
      • SD Video

    Related Videos

    WWDC26

    • Create high-quality images using Image Playground
    • Read between the strokes with PencilKit

    WWDC25

    • Meet PaperKit
  • Search this video…

    Hi, I'm Matt, an engineer on the Pencil and Paper team. Apps that give users a canvas to create whatever they want, have been some of the most iconic and empowering experiences on Apple platforms. And PaperKit is what powers the canvas experience across many of Apple's own applications. When you sketch an idea, drop in an image, or mark up a document in Notes, that's PaperKit. It's the full canvas experience, pencil, shapes, text, images, all working together. When you open a PDF in Preview and add a signature, highlight a passage, or circle something important, that's PaperKit too.

    And when you're ideating in Freeform on macOS, that's also PaperKit.

    And in iOS, macOS and visionOS 27, PaperKit opens up. Today I'll show you how to unwrap PaperKit, so you can take full control over your canvas experience. I'll start with the data model, which gives you access to everything on the canvas.

    Then, I'll show you how to work with elements like shapes and images.

    And I'll finish with adornments, which let you add interactive overlays and controls.

    Let's get going with the data model. I've been building a comic book editor powered by PaperKit. I've already set up some basic templates. But that's as far as I got. Now I need to turn those templates into PaperMarkup. PaperMarkup has a new subelements property. It gives you access to every element on the canvas as a MarkupOrderedSet, which is an ordered collection you can read from and write to. This code snippet creates a shape element for each panel.

    And then update's the markup.

    That's it. Let's try this on the iPad.

    I'll add a three-page panel to my comic. Great. It's showing up exactly how I wanted. The canvas is fully interactive, which is a problem for my comic book editor. I can select the panels, drag them around and even delete them.

    That's not what I want. The template elements should not be editable. To fix this, I need to change how those shape elements behave. Every element on the canvas conforms to the Markup protocol.

    This gives you common properties like frame and rotation. There is also a new allowedInteractions property, which is a MarkupInteractions option set. It gives you fine-grained control over what can be modified on each element. Markup interactions lets you control moving, resizing and rotating, deleting, styling, and selecting, individually or in any combination. And if you want to lock down everything at once, read-only combines them all into a single flag, which is perfect for the comic template.

    To limit interactions with panels in the comic book editor, I need to set .allowedInteractions to .readOnly. I'll give it a try. Now when I tap a panel border, nothing happens. The template shapes are read-only. I can add a speech bubble, move that around, and stylize it, but the panels stay fixed. Perfect. The app is starting to take shape, but the panels need to really pop, so I've added a color picker in the toolbar for styling our template.

    To implement styling, I'm going to dive into elements. Every element in PaperMarkup has a concrete type.

    Shapes, images, links, loupes, and pencil strokes. They are all part of the same Markup ordered set, and conform to the Markup protocol. But each of these types have their own custom properties. Let's take a deeper look at shapes. PaperKit supports many shape types and each type has its own properties, like corner radius for rounded rectangles, or control points for curved lines.

    I used rectangles for the comic panels. They have a stroke color and that's what we're looking for. To apply a color to our panels, I need to iterate over the subelements.

    Then set their stroke and fill colors.

    To give it that extra pop, I'm going to use the same color for the markup background. And lastly I update the markup on the paperMarkupViewController. Let me check the result on the iPad.

    And just like that, the canvas transforms. The page is styled with the color I chose, and it's starting to unwrap into something more personal. PaperKit is built on top of PencilKit, so I can use the Apple Pencil to draw.

    Each stroke becomes a markup element and I can use all of the PencilKit model APIs. Those APIs now support character recognition and Bézier path conversion. For all the details, check out "Reading Between the strokes with PencilKit".

    Now let's look at how to add custom controls with adornments. I want to add a button to each panel that lets users create artwork. But I don't want those controls to become part of the document. They shouldn't be saved, printed, or exported. I want them to exist on top of the canvas, only when I'm editing. That's exactly what Markup adornments are, a visual overlay anchored to canvas coordinates. This makes adornments ideal for buttons, annotations, and collaboration UI. They automatically track zoom and scroll, and they're completely separate from the persisted markup. For each panel, I create a MarkupAdornment. I anchor it to the center of the panel, and I give it an SF Symbol icon through the imageConfiguration.

    Then I assign the array to the controller's adornments property.

    To handle taps, I implement the delegate method didTapAdornmentWithID.

    When the user taps an adornment, I present the ImagePlaygroundViewController.

    When an image comes back from Image Playground, I create an ImageMarkup.

    Then, I insert it into the subelements and update the view controller's markup. Let's give it another try.

    I'll tap one of the panels to create some artwork.

    My comic is going to be about a super hero dog fighting crime in the city.

    And the generated image fills the panel.

    To learn more about generating images in your app, watch "Create high-quality images using Image Playground". And now with just a couple more images, some text and fonts, I've got the first page of my comic.

    Our super hero dog is going to save the day. Now you can build a fully interactive, canvas-based experience in your app with PaperKit. Use the data model to programmatically read and modify what's on the canvas. And add adornments to create interactive overlays tailored to your app. I can't wait to see how you will unwrap PaperKit. Thanks for watching!

    • 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.

Developer Footer

  • Videos
  • WWDC26
  • Unwrap PaperKit
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • Apple Intelligence
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Downloads
    • Sample Code
    • Videos
    Open Menu Close Menu
    • Help Guides & Articles
    • Contact Us
    • Forums
    • Feedback & Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Read the latest news.
    Get the Apple Developer app.
    Copyright © 2026 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines