diff --git a/ModernAppExtension/App/AppDelegate.swift b/ModernAppExtension/App/AppDelegate.swift
new file mode 100644
index 0000000..5dd36c6
--- /dev/null
+++ b/ModernAppExtension/App/AppDelegate.swift
@@ -0,0 +1,10 @@
+import Cocoa
+
+@main
+class AppDelegate: NSObject, NSApplicationDelegate {
+ func applicationDidFinishLaunching(_ aNotification: Notification) {
+ // Just print and exit gracefully, we just need Finder to register UTIs and Extensions.
+ print("GLTFQuickLook App registered. You can close this app.")
+ NSApplication.shared.terminate(nil)
+ }
+}
diff --git a/ModernAppExtension/App/Info.plist b/ModernAppExtension/App/Info.plist
new file mode 100644
index 0000000..6c192aa
--- /dev/null
+++ b/ModernAppExtension/App/Info.plist
@@ -0,0 +1,69 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ LSUIElement
+
+ UTExportedTypeDeclarations
+
+
+ UTTypeConformsTo
+
+ public.data
+
+ UTTypeDescription
+ glTF Document
+ UTTypeIdentifier
+ org.khronos.gltf
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ gltf
+
+ public.mime-type
+
+ model/gltf+json
+
+
+
+
+ UTTypeConformsTo
+
+ public.data
+
+ UTTypeDescription
+ glTF Binary Document
+ UTTypeIdentifier
+ org.khronos.glb
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ glb
+
+ public.mime-type
+
+ model/gltf-binary
+
+
+
+
+
+
diff --git a/ModernAppExtension/PreviewExtension/Info.plist b/ModernAppExtension/PreviewExtension/Info.plist
new file mode 100644
index 0000000..351d880
--- /dev/null
+++ b/ModernAppExtension/PreviewExtension/Info.plist
@@ -0,0 +1,41 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ GLTF Preview
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ XPC!
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ NSExtension
+
+ NSExtensionAttributes
+
+ QLSupportedContentTypes
+
+ org.khronos.gltf
+ org.khronos.glb
+
+ QLSupportsSearchableItems
+
+
+ NSExtensionPointIdentifier
+ com.apple.quicklook.preview
+ NSExtensionPrincipalClass
+ $(PRODUCT_MODULE_NAME).PreviewViewController
+
+
+
diff --git a/ModernAppExtension/PreviewExtension/PreviewViewController.swift b/ModernAppExtension/PreviewExtension/PreviewViewController.swift
new file mode 100644
index 0000000..fd2ab4e
--- /dev/null
+++ b/ModernAppExtension/PreviewExtension/PreviewViewController.swift
@@ -0,0 +1,36 @@
+import Cocoa
+import Quartz
+import SceneKit
+import GLTFSceneKit
+
+class PreviewViewController: NSViewController, QLPreviewingController {
+
+ var sceneView: SCNView!
+
+ override func loadView() {
+ self.sceneView = SCNView(frame: NSRect(x: 0, y: 0, width: 800, height: 600))
+ self.sceneView.autoresizingMask = [.width, .height]
+ self.sceneView.backgroundColor = NSColor.windowBackgroundColor
+ self.sceneView.allowsCameraControl = true
+ self.sceneView.autoenablesDefaultLighting = true
+ self.view = self.sceneView
+ }
+
+ func preparePreviewOfFile(at url: URL, completionHandler handler: @escaping (Error?) -> Void) {
+ DispatchQueue.global(qos: .userInitiated).async {
+ do {
+ let source = try GLTFSceneSource(url: url)
+ let scene = try source.scene()
+
+ DispatchQueue.main.async {
+ self.sceneView.scene = scene
+ handler(nil)
+ }
+ } catch {
+ DispatchQueue.main.async {
+ handler(error)
+ }
+ }
+ }
+ }
+}
diff --git a/ModernAppExtension/README.md b/ModernAppExtension/README.md
new file mode 100644
index 0000000..3a71aad
--- /dev/null
+++ b/ModernAppExtension/README.md
@@ -0,0 +1,29 @@
+# GLTFQuickLook Modern App Extension
+
+This folder contains the modern macOS App Extension implementation of GLTFQuickLook for macOS 10.15 (Catalina) and newer, including full support for Apple Silicon (M1/M2/M3) and upcoming macOS versions like Sequoia.
+
+Apple deprecated `.qlgenerator` plugins and requires QuickLook extensions to be embedded inside a macOS application bag (`.app`).
+
+## Installation
+
+1. Download the latest `GLTFQuickLook.app` release.
+2. Drag and drop `GLTFQuickLook.app` into your `/Applications` folder.
+3. Open the app once (it will launch and exit immediately, registering the QuickLook extensions with macOS).
+4. Select any `.gltf` or `.glb` file in Finder and press `Space` to preview.
+
+## Build Setup
+
+To build this modern extension from source, you need [XcodeGen](https://github.com/yonaskolb/XcodeGen) and macOS 12.0+ with Xcode.
+
+```bash
+# Install XcodeGen
+brew install xcodegen
+
+# Generate the Xcode Project
+xcodegen
+
+# Open the project
+open GLTFQuickLook.xcodeproj
+```
+
+You can then build the `GLTFQuickLook` scheme directly from Xcode. Swift Package Manager will automatically fetch `GLTFSceneKit`.
diff --git a/ModernAppExtension/ThumbnailExtension/Info.plist b/ModernAppExtension/ThumbnailExtension/Info.plist
new file mode 100644
index 0000000..e304708
--- /dev/null
+++ b/ModernAppExtension/ThumbnailExtension/Info.plist
@@ -0,0 +1,41 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ GLTF Thumbnail
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ XPC!
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ NSExtension
+
+ NSExtensionAttributes
+
+ QLSupportedContentTypes
+
+ org.khronos.gltf
+ org.khronos.glb
+
+ QLThumbnailMinimumDimension
+ 0
+
+ NSExtensionPointIdentifier
+ com.apple.quicklook.thumbnail
+ NSExtensionPrincipalClass
+ $(PRODUCT_MODULE_NAME).ThumbnailProvider
+
+
+
diff --git a/ModernAppExtension/ThumbnailExtension/ThumbnailProvider.swift b/ModernAppExtension/ThumbnailExtension/ThumbnailProvider.swift
new file mode 100644
index 0000000..f1c9780
--- /dev/null
+++ b/ModernAppExtension/ThumbnailExtension/ThumbnailProvider.swift
@@ -0,0 +1,37 @@
+import Cocoa
+import QuickLookThumbnailing
+import SceneKit
+import GLTFSceneKit
+
+class ThumbnailProvider: QLThumbnailProvider {
+
+ override func provideThumbnail(for request: QLFileThumbnailRequest, _ handler: @escaping (QLThumbnailReply?, Error?) -> Void) {
+ let size = request.maximumSize
+
+ // Use a QLThumbnailReply with drawing context to correctly handle scaling
+ let reply = QLThumbnailReply(contextSize: size) { () -> Bool in
+ guard let context = NSGraphicsContext.current?.cgContext else { return false }
+
+ do {
+ let source = try GLTFSceneSource(url: request.fileURL)
+ let scene = try source.scene()
+
+ let renderer = SCNRenderer(device: nil, options: nil)
+ renderer.scene = scene
+ renderer.autoenablesDefaultLighting = true
+
+ let image = renderer.snapshot(atTime: 0.0, with: size, antialiasingMode: .multisampling4X)
+
+ if let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) {
+ context.draw(cgImage, in: CGRect(origin: .zero, size: size))
+ return true
+ }
+ } catch {
+ print("Error generating thumbnail: \(error)")
+ }
+ return false
+ }
+
+ handler(reply, nil)
+ }
+}
diff --git a/ModernAppExtension/project.yml b/ModernAppExtension/project.yml
new file mode 100644
index 0000000..a4ca89d
--- /dev/null
+++ b/ModernAppExtension/project.yml
@@ -0,0 +1,83 @@
+name: GLTFQuickLook
+options:
+ bundleIdPrefix: com.hectorlizard
+settings:
+ CODE_SIGN_IDENTITY: "-"
+ MARKETING_VERSION: "1.0"
+ CURRENT_PROJECT_VERSION: "1"
+packages:
+ GLTFSceneKit:
+ url: https://github.com/magicien/GLTFSceneKit.git
+ branch: master
+targets:
+ GLTFQuickLook:
+ type: application
+ platform: macOS
+ deploymentTarget: "12.0"
+ sources: App
+ settings:
+ PRODUCT_BUNDLE_IDENTIFIER: com.hectorlizard.GLTFQuickLook
+ info:
+ path: App/Info.plist
+ properties:
+ LSUIElement: true
+ UTExportedTypeDeclarations:
+ - UTTypeIdentifier: org.khronos.gltf
+ UTTypeConformsTo: [public.data]
+ UTTypeDescription: glTF Document
+ UTTypeTagSpecification:
+ public.filename-extension: [gltf]
+ public.mime-type: [model/gltf+json]
+ - UTTypeIdentifier: org.khronos.glb
+ UTTypeConformsTo: [public.data]
+ UTTypeDescription: glTF Binary Document
+ UTTypeTagSpecification:
+ public.filename-extension: [glb]
+ public.mime-type: [model/gltf-binary]
+ dependencies:
+ - target: GLTFPreview
+ - target: GLTFThumbnail
+
+ GLTFPreview:
+ type: app-extension
+ platform: macOS
+ deploymentTarget: "12.0"
+ sources: PreviewExtension
+ settings:
+ PRODUCT_BUNDLE_IDENTIFIER: com.hectorlizard.GLTFQuickLook.GLTFPreview
+ ENABLE_HARDENED_RUNTIME: YES
+ ENABLE_APP_SANDBOX: YES
+ info:
+ path: PreviewExtension/Info.plist
+ properties:
+ CFBundleDisplayName: GLTF Preview
+ NSExtension:
+ NSExtensionAttributes:
+ QLSupportedContentTypes: [org.khronos.gltf, org.khronos.glb]
+ QLSupportsSearchableItems: true
+ NSExtensionPointIdentifier: com.apple.quicklook.preview
+ NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).PreviewViewController
+ dependencies:
+ - package: GLTFSceneKit
+
+ GLTFThumbnail:
+ type: app-extension
+ platform: macOS
+ deploymentTarget: "12.0"
+ sources: ThumbnailExtension
+ settings:
+ PRODUCT_BUNDLE_IDENTIFIER: com.hectorlizard.GLTFQuickLook.GLTFThumbnail
+ ENABLE_HARDENED_RUNTIME: YES
+ ENABLE_APP_SANDBOX: YES
+ info:
+ path: ThumbnailExtension/Info.plist
+ properties:
+ CFBundleDisplayName: GLTF Thumbnail
+ NSExtension:
+ NSExtensionAttributes:
+ QLSupportedContentTypes: [org.khronos.gltf, org.khronos.glb]
+ QLThumbnailMinimumDimension: 0
+ NSExtensionPointIdentifier: com.apple.quicklook.thumbnail
+ NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).ThumbnailProvider
+ dependencies:
+ - package: GLTFSceneKit
diff --git a/README.md b/README.md
index 0b0f5d2..bc1d05b 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,18 @@ macOS QuickLook plugin for glTF files. (.gltf/.glb)
- macOS 10.13 (High Sierra) or later
-## Install
+> **Note for macOS 10.15+ and Apple Silicon**: Apple has deprecated `.qlgenerator` plugins and they are fully unsupported in macOS 15 (Sequoia). There are now two versions of this project available:
+> - **Legacy** (`.qlgenerator`): For macOS 10.13 and 10.14 (see instructions below).
+> - **Modern** (App Extension): For macOS 10.15+, including native Apple Silicon support. See the [ModernAppExtension folder](ModernAppExtension/) for details.
+
+## Install (Modern - macOS 10.15+)
+
+1. Download the latest `GLTFQuickLook.app` release from [Releases](https://github.com/magicien/GLTFQuickLook/releases/latest).
+2. Drag and drop `GLTFQuickLook.app` into your `/Applications` folder.
+3. Open the app **once** (it will casually launch and exit, registering the extension with macOS).
+4. Run `qlmanage -r` to reload QuickLook plugins.
+
+## Install (Legacy - macOS 10.13, 10.14)
### Using [Homebrew Cask](https://github.com/phinze/homebrew-cask)
@@ -25,6 +36,10 @@ macOS QuickLook plugin for glTF files. (.gltf/.glb)
## Build
+### Modern App Extension (Recommended for macOS 12+)
+See the [ModernAppExtension/README.md](ModernAppExtension/README.md) for build instructions using `xcodegen` and Swift Package Manager.
+
+### Legacy (.qlgenerator)
It needs to install [Carthage](https://github.com/Carthage/Carthage) to get frameworks.
```
$ git clone https://github.com/magicien/GLTFQuickLook.git