Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions ModernAppExtension/App/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -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)
}
}
69 changes: 69 additions & 0 deletions ModernAppExtension/App/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSUIElement</key>
<true/>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>glTF Document</string>
<key>UTTypeIdentifier</key>
<string>org.khronos.gltf</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>gltf</string>
</array>
<key>public.mime-type</key>
<array>
<string>model/gltf+json</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>glTF Binary Document</string>
<key>UTTypeIdentifier</key>
<string>org.khronos.glb</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>glb</string>
</array>
<key>public.mime-type</key>
<array>
<string>model/gltf-binary</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
41 changes: 41 additions & 0 deletions ModernAppExtension/PreviewExtension/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>GLTF Preview</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>QLSupportedContentTypes</key>
<array>
<string>org.khronos.gltf</string>
<string>org.khronos.glb</string>
</array>
<key>QLSupportsSearchableItems</key>
<true/>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.quicklook.preview</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).PreviewViewController</string>
</dict>
</dict>
</plist>
36 changes: 36 additions & 0 deletions ModernAppExtension/PreviewExtension/PreviewViewController.swift
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
}
}
29 changes: 29 additions & 0 deletions ModernAppExtension/README.md
Original file line number Diff line number Diff line change
@@ -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`.
41 changes: 41 additions & 0 deletions ModernAppExtension/ThumbnailExtension/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>GLTF Thumbnail</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>QLSupportedContentTypes</key>
<array>
<string>org.khronos.gltf</string>
<string>org.khronos.glb</string>
</array>
<key>QLThumbnailMinimumDimension</key>
<integer>0</integer>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.quicklook.thumbnail</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).ThumbnailProvider</string>
</dict>
</dict>
</plist>
37 changes: 37 additions & 0 deletions ModernAppExtension/ThumbnailExtension/ThumbnailProvider.swift
Original file line number Diff line number Diff line change
@@ -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)
}
}
83 changes: 83 additions & 0 deletions ModernAppExtension/project.yml
Original file line number Diff line number Diff line change
@@ -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
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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
Expand Down