View in English

  • Global Nav Open Menu Global Nav Close Menu
  • Apple Developer
Search
Cancel
  • Apple Developer
  • News
  • Discover
  • Design
  • Develop
  • Distribute
  • Support
  • Account
Only search within “”

Quick Links

5 Quick Links

Videos

Open Menu Close Menu
  • Collections
  • Topics
  • All Videos
  • About

More Videos

Streaming is available in most browsers,
and in the Developer app.

  • About
  • Summary
  • Transcript
  • Code
  • Meet PaperKit

    Discover how to bring PaperKit to your iOS, iPadOS, macOS, and visionOS apps. We'll cover how to seamlessly integrate PencilKit drawing with markup features like shapes and images, and how to customize the user interface. Learn best practices for forward compatibility, and discover advanced customization options to create truly unique markup experiences in your apps.

    Chapters

    • 0:00 - Introduction
    • 1:36 - Getting to know PaperKit
    • 3:35 - Getting started 
with PaperKit
    • 8:37 - Customizing the 
feature set

    Resources

    • PaperKit
      • HD Video
      • SD Video

    Related Videos

    WWDC24

    • Squeeze the most out of Apple Pencil

    WWDC20

    • What's new in PencilKit
    • What's new in SwiftUI
  • Search this video…

    Welcome, I’m Andreea, an engineer on the Pencil & Paper team, and I’m delighted to introduce you to PaperKit. PaperKit is the framework that powers Apple’s unique markup experience system-wide. It’s used in apps like Notes, Screenshots, QuickLook, and the Journal app. It’s the easiest way to get rich markup in any app. PaperKit provides a canvas that you can both draw on and add a variety of markup elements to, including shapes, images, textboxes, and much more. Supporting both drawing and markup elements is what makes PaperKit an amazing addition to any app for a comprehensive markup experience.

    And new to macOS Tahoe, PaperKit provides the same rich markup experience, so drawing and markup elements on any macOS app work great as well, just like the new Journal app shown here.

    First, I’ll talk more about PaperKit’s key features and explain the core components behind it. Next, I’ll show how to integrate PaperKit markup to your app in a few steps. Finally, I’ll explain how to customize the PaperKit markup experience to best match your app’s requirements.

    I’ll start by highlighting the features available with a demo. I created an app to keep track of all my recipes and use markup to update them as I make changes. I’ve already written out a recipe for my favorite traditional Romanian cookies I’ve been making since I was 7 and rated them with some star shapes. To complete the recipe, I’ll add an image of the cookies. I can just open up the Files app and drag an image to my recipe.

    I'll reposition it to make sure it looks good! I’ll also highlight the ground walnuts since they’re the key ingredient.

    Now that I’ve gone through what PaperKit can do, I’ll break down its three main components. The first is the markup controller called PaperMarkupViewController that interactively creates and displays PaperKit markup and drawing.

    The second is the data model container, called PaperMarkup. It handles saving and loading both the PaperKit markup and PencilKit drawing data, and it handles rendering the markup.

    The third is a new insertion menu that allows annotation with markup elements into the canvas. On iOS, iPadOS and visionOS 26, this is called a MarkupEditViewController.

    On macOS, an alternative option is a new toolbar called MarkupToolbarViewController, complete with drawing tools and buttons for annotating.

    Getting started with PaperKit in your app is easy. I'll begin by going over how I integrated it into my recipes app on iOS, and then cover the steps for macOS.

    I began by subclassing UIViewController. Within the viewDidLoad method, I initialized a markup data model container, configuring it to match the view’s bounds to ensure proper layout and rendering context. Next, I created a markup controller configured with the complete set of the latest features provided by PaperKit.

    I added it to the view hierarchy using the standard view controller embedding process.

    To create a tool picker, I initialized a PencilKit tool picker and registered the markup controller as an observer, allowing it to respond dynamically to changes in the tool picker's state.

    To display the tool picker in my app, I assigned it to the activeToolPicker property on the PencilKit responder state. This is a new API available on UIResponder that controls the tool picker visibility for the current responder. By configuring the toolPickerVisibility property, I can keep the tool picker active while explicitly managing its on-screen visibility. This enables the tool picker to remain hidden yet fully functional — still responding to interactions like double-tap and squeeze gestures — and allows any app to support the mini tool picker experience. To learn more about setting up your tool picker, check out Introducing PencilKit from WWDC19 and Squeeze the most out of Apple Pencil from WWDC24. After setting up the tool picker, I configured the accessory item as a button. When tapped, it will trigger a function to present the insertion menu.

    Inside the method, I initialized the insertion controller using the same feature set as the markup controller.

    I then set the controller’s delegate to the markup view controller, configured it to display as a popover, and anchored the popover to the bar button item I added to the tool picker for proper placement.

    Finally, I presented the insertion menu controller modally. Getting things working on macOS is just as straightforward.

    Setting up the markup model and markup controller are essentially the same.

    The only difference on macOS is that a toolbar can be created to present the insertion UI. From there, set the toolbar’s delegate to the markup controller and add it to the view hierarchy using the standard NSViewController embedding process.

    With the basic setup complete, it's worth pausing to consider a few key factors that are essential when refining the app experience.

    PaperKit can be seamlessly integrated into a SwiftUI environment. The components are encapsulated within a UIViewControllerRepresentable, which is then incorporated directly into a SwiftUI view’s body. This allows UIKit-based components to be used within a SwiftUI layout, preserving compatibility across both frameworks. For more information on how to integrate view controllers into a SwiftUI environment, check out What’s New in SwiftUI from WWDC20.

    The markup controller includes a delegate that allows for custom handling of callbacks. For instance, I can implement the markup change delegate method to automatically save any modifications to the markup model. Additionally, the markup controller conforms to Observable, providing an alternative to using a delegate for managing state and updates.

    When loading data from disk, it is essential to always verify the content version for forwards compatibility. There are two common approaches for handling version mismatches: presenting an alert to inform of the need to upgrade or showing a pre-rendered thumbnail of the markup.

    PaperKit provides tools to make forwards compatibility extremely straightforward. First, create a CGContext to render the thumbnail into. Then, generate a thumbnail image of the model using the markup model’s draw function, and finally, save it alongside the markup. Displaying this thumbnail in the case of a version mismatch is considered the best practice, and it is exactly what apps like Notes are using.

    Now that I’ve covered getting started with PaperKit for both iOS and macOS, I’ll dive into how you can customize your app to deliver the exact markup experience that you envision. The set of all available markup functionality in PaperKit is called a FeatureSet. It defines the capabilities and tools exposed to both the markup and the insertion controllers.

    FeatureSet.latest gives you the full set of markup features supported by PaperKit. It’s a great starting point as it ensures you stay up to date with new features added to the framework.

    To customize your markup experience, you can use the remove and insert functions. This gives you full control over what tools and interactions are available in your app.

    HDR support can be enabled in your markup by setting the colorMaximumLinearExposure property on the feature set to a number greater than 1. For SDR markup, use 1. Set this property on the tool picker as well for HDR inks. For my app, 4 gave me the HDR effect I was looking for.

    The value you set for colorMaximumLinearExposure will tone-map down to the supported HDR headroom for your device’s screen. Or just use the screen’s supported value, which you can grab from UIScreen or NSScreen.

    By using the latest feature set and enabling HDR in your app, you’ll get all the new features and experiences. For example, a new tool for calligraphy, called the Reed tool, introduced in PencilKit, which looks great in HDR.

    Once the feature set is configured to your requirements, assign the customized feature set to both the markup controller and the insertion controller to ensure consistency across the app’s markup and insertion functionality.

    Another customizable property is the markup controller’s contentView, which can be set to any UIView. For example, I can use the template as a fixture in my app. All markup and drawing will be rendered on top of it. By customizing the FeatureSet, configuring the background view, and applying the refinement steps outlined earlier, your app can deliver the same powerful, system-wide markup experience, tailored in a robust and creative way.

    So what’s next? Adopt Apple’s powerful markup experience, customize your FeatureSet with your own selection of tools and inks, set your own content background, and add HDR Support to your markup.

    Whether you're whipping up a lightweight note tool or baking a rich creative canvas, PaperKit gives you the ingredients to create the perfect experience. I can’t wait to see what you cook up with PaperKit.

    Thanks for watching!

    • 3:47 - Adopt PaperKit in iOS

      // Adopt PaperKit in iOS
      
      override func viewDidLoad() {
          super.viewDidLoad()
          
          let markupModel = PaperMarkup(bounds: view.bounds)
          let paperViewController = PaperMarkupViewController(markup: markupModel, supportedFeatureSet: .latest)
          view.addSubview(paperViewController.view)
          addChild(paperViewController)
          paperViewController.didMove(toParent: self)
          becomeFirstResponder()    
      
          let toolPicker = PKToolPicker()
          toolPicker.addObserver(paperViewController)
          
          pencilKitResponderState.activeToolPicker = toolPicker
          pencilKitResponderState.toolPickerVisibility = .visible
          
          toolPicker.accessoryItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(plusButtonPressed(_:)))
      }
      
      @objc func plusButtonPressed(_ button: UIBarButtonItem) {
          let markupEditViewController = MarkupEditViewController(supportedFeatureSet: .latest)    
          markupEditViewController.delegate = paperViewController
          markupEditViewController.modalPresentationStyle = .popover
          markupEditViewController.popoverPresentationController?.barButtonItem = button
          present(markupEditViewController, animated: true)
      }
    • 6:11 - Adopt PaperKit in macOS

      // Adopt PaperKit in macOS
      
      override func viewDidLoad() {
          super.viewDidLoad()
          
          let markupModel = PaperMarkup(bounds: view.bounds)
          let paperViewController = PaperMarkupViewController(markup: markupModel, supportedFeatureSet: .latest)
          view.addSubview(paperViewController.view)
          addChild(paperViewController)
      
          // Create toolbar for macOS
          let toolbarViewController = MarkupToolbarViewController(supportedFeatureSet: .latest)
          toolbarViewController.delegate = paperViewController
          view.addSubview(toolbarViewController.view)
          
          // Set layout
          setupLayoutConstraints()
      }
    • 7:18 - Auto-save markup changes

      // Auto-save markup changes
          
      func paperMarkupViewControllerDidChangeMarkup(_ paperMarkupViewController: PaperMarkupViewController) {
          let markupModel = paperMarkupViewController.markup
          Task {
              // Create a data blob and save it
              let data = try await markupModel.dataRepresentation()
              try data.write(toFile: paperKitDataURL)
          }
      }
    • 8:02 - Thumbnail for forward compatibility

      // Thumbnail for forward compatibility
      
      func updateThumbnail(_ markupModel: PaperMarkup) async throws {
          // Set up CGContext to render thumbnail in
          let thumbnailSize = CGSize(width: 200, height: 200)
          let context = makeCGContext(size: thumbnailSize)
          context.setFillColor(gray: 1, alpha: 1)
          context.fill(renderer.format.bounds)            
      
          // Render the PaperKit markup
          await markupModel.draw(in: context, frame: CGRect(origin: .zero, size: thumbnailSize))
          
          thumbnail = context.makeImage()
      }
    • 9:02 - Customized markup FeatureSet

      // Customized markup FeatureSet
          
      var featureSet: FeatureSet = .latest
      
      featureSet.remove(.text)
      featureSet.insert(.stickers)
      
      // HDR support
      featureSet.colorMaximumLinearExposure = 4
      toolPicker.colorMaximumLinearExposure = 4
      
      let paperViewController = PaperMarkupViewController(supportedFeatureSet: featureSet)
      let markupEditViewController = MarkupEditViewController(supportedFeatureSet: featureSet)
    • 10:50 - Custom background on markup controller

      // Custom background on markup controller
      
      let template = UIImage(named: "MyTemplate.jpg")
      let templateView = UIImageView(image: template)
      paperViewController.contentView = templateView
    • 0:00 - Introduction
    • With PaperKit, you can create rich markup experiences across various iOS and macOS apps, including Notes, Screenshots, QuickLook, and the Journal app. The framework provides a canvas for drawing and adding shapes, images, text input fields, and more. PaperKit simplifies the integration of markup functionality into any app, offering a seamless user experience.

    • 1:36 - Getting to know PaperKit
    • The example app is a recipe management tool that allows people to create, update, and annotate recipes using markup. The app includes a markup controller, a data model container, and an insertion menu or toolbar (depending on the operating system) for easy annotation. The demo showcases these features by adding an image, highlighting ingredients, and rating a recipe for traditional Romanian cookies.

    • 3:35 - Getting started 
with PaperKit
    • To integrate PaperKit into an iOS app, subclass 'UIViewController' and initialize a markup data model container and controller. Then you set up a PencilKit tool picker and configure an insertion menu controller to display as a popover when triggered by a button accessory item. You can also seamlessly integrate PaperKit into a SwiftUI environment. The markup controller includes a delegate for custom handling of callbacks and conforms to 'Observable' for state management. When you load data from disk, it's crucial to verify the content version for forward compatibility. PaperKit provides tools to generate thumbnails for prerendering, in case of version mismatches.

    • 8:37 - Customizing the 
feature set
    • PaperKit's 'FeatureSet' defines the markup functionality available in an app. You can start with 'FeatureSet.latest' to include all the latest features. To customize the app, you can remove or insert tools and interactions using the provided functions. To enable HDR support, set the 'colorMaximumLinearExposure' property to a value greater than 1, which tone-maps down to the device's supported HDR headroom. Doing so enhances the visual quality of the markup, especially when using new tools like the calligraphy reed tool introduced in PencilKit. You can also customize the markup controller's 'contentView' to display any 'UIView', such as a template, providing a consistent background for markup and drawing.

Developer Footer

  • Videos
  • WWDC25
  • Meet PaperKit
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • App Extensions
    • App Store
    • Audio & Video
    • Augmented Reality
    • Design
    • Distribution
    • Education
    • Fonts
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning
    • Open Source
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Tutorials
    • Downloads
    • Forums
    • Videos
    Open Menu Close Menu
    • Support Articles
    • Contact Us
    • 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
    • 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
    Get the Apple Developer app.
    Copyright © 2025 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines