├── .github └── FUNDING.yml ├── .gitignore ├── .swiftformat ├── Config.xcconfig ├── Examples └── HelloWorld │ ├── Package.resolved │ ├── Package.swift │ └── Sources │ └── HelloWorld │ └── HelloWorld.swift ├── LICENSE ├── Package.swift ├── Plugin ├── Extensions │ ├── CMTime+Extensions.swift │ ├── CMTimeRange+Extensions.swift │ ├── FxRect+Extensions.swift │ ├── FxTimingAPI_v4+Extensions.swift │ └── PROAPIAccessing+Extensions.swift ├── Generators │ └── SwiftUIViewGenerator.swift ├── Supporting Files │ ├── Info.plist │ └── Plugin-Bridging-Header.h ├── TileableEffect.swift └── main.swift ├── README.md ├── Sources └── SwiftUIFX │ └── EnvironmentValues+Extensions.swift ├── SwiftUIFX.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── macOS App.xcscheme └── macOS App ├── AppDelegate.swift ├── Base.lproj └── MainMenu.xib └── Supporting Files ├── Entitlements.entitlements └── Info.plist /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: finnvoor 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .build/ 3 | .swiftpm/ 4 | /Packages 5 | xcuserdata/ 6 | DerivedData/ 7 | .netrc 8 | 9 | -------------------------------------------------------------------------------- /.swiftformat: -------------------------------------------------------------------------------- 1 | --swiftversion 6.0 2 | 3 | --enable blankLineAfterImports 4 | --enable blankLinesBetweenImports 5 | --enable blockComments 6 | --enable docComments 7 | --enable isEmpty 8 | --enable markTypes 9 | --enable organizeDeclarations 10 | 11 | --disable numberFormatting 12 | --disable redundantNilInit 13 | --disable trailingCommas 14 | --disable wrapMultilineStatementBraces 15 | 16 | --ifdef no-indent 17 | --funcattributes same-line 18 | --typeattributes same-line 19 | --storedvarattrs same-line 20 | --computedvarattrs same-line 21 | --ranges no-space 22 | --header strip 23 | --selfrequired log,debug,info,notice,warning,trace,error,critical,fault 24 | -------------------------------------------------------------------------------- /Config.xcconfig: -------------------------------------------------------------------------------- 1 | MARKETING_VERSION = 0.1.0 2 | CURRENT_PROJECT_VERSION = 5 3 | -------------------------------------------------------------------------------- /Examples/HelloWorld/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "3fafc0e42390d3e32ea69b729e844a2445a1209e17f3b948fbcf0e0ef11b56e4", 3 | "pins" : [ 4 | { 5 | "identity" : "swiftuifx", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/finnvoor/SwiftUIFX.git", 8 | "state" : { 9 | "branch" : "main", 10 | "revision" : "34a88853e7ec29428d9a26262b2590467f72395e" 11 | } 12 | } 13 | ], 14 | "version" : 3 15 | } 16 | -------------------------------------------------------------------------------- /Examples/HelloWorld/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 6.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "HelloWorld", 7 | platforms: [.macOS(.v13)], 8 | products: [.library(name: "HelloWorld", type: .dynamic, targets: ["HelloWorld"])], 9 | dependencies: [.package(url: "https://github.com/finnvoor/SwiftUIFX.git", branch: "main")], 10 | targets: [.target(name: "HelloWorld", dependencies: [.product(name: "SwiftUIFX", package: "SwiftUIFX")])] 11 | ) 12 | -------------------------------------------------------------------------------- /Examples/HelloWorld/Sources/HelloWorld/HelloWorld.swift: -------------------------------------------------------------------------------- 1 | import CoreMedia 2 | import SwiftUI 3 | import SwiftUIFX 4 | 5 | @_cdecl("createView") public func createView() -> UnsafeMutableRawPointer { 6 | Unmanaged.passRetained( 7 | AnyView(HelloWorldView()) as AnyObject 8 | ).toOpaque() 9 | } 10 | 11 | // MARK: - HelloWorldView 12 | 13 | struct HelloWorldView: View { 14 | @Environment(\.timelineTime) var timelineTime: CMTime 15 | 16 | var body: some View { 17 | GeometryReader { proxy in 18 | VStack { 19 | Text("Hello World") 20 | Text(timelineTime.seconds, format: .number.precision(.fractionLength(2))) 21 | } 22 | .font(.system(size: proxy.size.width / 14)) 23 | .fontWeight(.bold) 24 | .foregroundStyle(.white) 25 | .monospaced() 26 | .frame( 27 | maxWidth: .infinity, 28 | maxHeight: .infinity, 29 | alignment: .center 30 | ) 31 | } 32 | } 33 | } 34 | 35 | #Preview { 36 | HelloWorldView() 37 | .frame(width: 1920, height: 1080) 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 6.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "SwiftUIFX", 7 | platforms: [.macOS(.v11)], 8 | products: [.library(name: "SwiftUIFX", type: .dynamic, targets: ["SwiftUIFX"])], 9 | targets: [.target(name: "SwiftUIFX")] 10 | ) 11 | -------------------------------------------------------------------------------- /Plugin/Extensions/CMTime+Extensions.swift: -------------------------------------------------------------------------------- 1 | import CoreMedia 2 | 3 | extension CMTime: Codable { 4 | public init(from decoder: Decoder) throws { 5 | let container = try decoder.container(keyedBy: CodingKeys.self) 6 | let value = try container.decode(CMTimeValue.self, forKey: .value) 7 | let timescale = try container.decode(CMTimeScale.self, forKey: .timescale) 8 | let flags = try CMTimeFlags(rawValue: container.decode(UInt32.self, forKey: .flags)) 9 | let epoch = try container.decode(CMTimeEpoch.self, forKey: .epoch) 10 | self.init(value: value, timescale: timescale, flags: flags, epoch: epoch) 11 | } 12 | 13 | public func encode(to encoder: Encoder) throws { 14 | var container = encoder.container(keyedBy: CodingKeys.self) 15 | try container.encode(value, forKey: .value) 16 | try container.encode(timescale, forKey: .timescale) 17 | try container.encode(flags.rawValue, forKey: .flags) 18 | try container.encode(epoch, forKey: .epoch) 19 | } 20 | 21 | private enum CodingKeys: CodingKey { 22 | case value 23 | case timescale 24 | case flags 25 | case epoch 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Plugin/Extensions/CMTimeRange+Extensions.swift: -------------------------------------------------------------------------------- 1 | import CoreMedia 2 | 3 | extension CMTimeRange: Codable { 4 | public init(from decoder: Decoder) throws { 5 | let container = try decoder.container(keyedBy: CodingKeys.self) 6 | let start = try container.decode(CMTime.self, forKey: .start) 7 | let duration = try container.decode(CMTime.self, forKey: .duration) 8 | self.init(start: start, duration: duration) 9 | } 10 | 11 | public func encode(to encoder: Encoder) throws { 12 | var container = encoder.container(keyedBy: CodingKeys.self) 13 | try container.encode(start, forKey: .start) 14 | try container.encode(duration, forKey: .duration) 15 | } 16 | 17 | private enum CodingKeys: CodingKey { 18 | case start 19 | case duration 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Plugin/Extensions/FxRect+Extensions.swift: -------------------------------------------------------------------------------- 1 | extension FxRect { 2 | var cgRect: CGRect { 3 | CGRect( 4 | x: CGFloat(left), 5 | y: CGFloat(bottom), 6 | width: CGFloat(right - left), 7 | height: CGFloat(top - bottom) 8 | ) 9 | } 10 | 11 | init(_ rect: CGRect) { 12 | self.init( 13 | left: Int32(rect.minX), 14 | bottom: Int32(rect.minY), 15 | right: Int32(rect.maxX), 16 | top: Int32(rect.maxY) 17 | ) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Plugin/Extensions/FxTimingAPI_v4+Extensions.swift: -------------------------------------------------------------------------------- 1 | import CoreMedia 2 | 3 | extension FxTimingAPI_v4 { 4 | func timelineTime(fromInputTime inputTime: CMTime) -> CMTime { 5 | var timelineTime: CMTime = .zero 6 | self.timelineTime(&timelineTime, fromInputTime: inputTime) 7 | return timelineTime 8 | } 9 | 10 | var inPointTimeOfTimeline: CMTime { 11 | var inPointTime: CMTime = .zero 12 | self.inPointTimeOfTimeline(forEffect: &inPointTime) 13 | return inPointTime 14 | } 15 | 16 | var outPointTimeOfTimeline: CMTime { 17 | var outPointTime: CMTime = .zero 18 | self.outPointTimeOfTimeline(forEffect: &outPointTime) 19 | return outPointTime 20 | } 21 | 22 | var startTime: CMTime { 23 | var startTime: CMTime = .zero 24 | self.startTime(forEffect: &startTime) 25 | return startTime 26 | } 27 | 28 | var duration: CMTime { 29 | var duration: CMTime = .zero 30 | durationTime(forEffect: &duration) 31 | return duration 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Plugin/Extensions/PROAPIAccessing+Extensions.swift: -------------------------------------------------------------------------------- 1 | extension PROAPIAccessing { 2 | var parameterCreationAPI: FxParameterCreationAPI_v5 { 3 | api(for: FxParameterCreationAPI_v5.self) as! FxParameterCreationAPI_v5 4 | } 5 | 6 | var parameterRetrievalAPI: FxParameterRetrievalAPI_v6 { 7 | api(for: FxParameterRetrievalAPI_v6.self) as! FxParameterRetrievalAPI_v6 8 | } 9 | 10 | var parameterSettingAPI: FxParameterSettingAPI_v6 { 11 | api(for: FxParameterSettingAPI_v6.self) as! FxParameterSettingAPI_v6 12 | } 13 | 14 | var timingAPI: FxTimingAPI_v4 { 15 | api(for: FxTimingAPI_v4.self) as! FxTimingAPI_v4 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Plugin/Generators/SwiftUIViewGenerator.swift: -------------------------------------------------------------------------------- 1 | import OSLog 2 | import SwiftUI 3 | import SwiftUIFX 4 | 5 | // MARK: - SwiftUIViewGenerator 6 | 7 | @objc(SwiftUIViewGenerator) class SwiftUIViewGenerator: TileableEffect { 8 | // MARK: Internal 9 | 10 | override var properties: [String: Any] { 11 | [ 12 | kFxPropertyKey_MayRemapTime: false, 13 | kFxPropertyKey_VariesWhenParamsAreStatic: true 14 | ] 15 | } 16 | 17 | override func addParameters() throws { 18 | logger.debug("Adding parameters") 19 | apiManager.parameterCreationAPI.addStringParameter( 20 | withName: "Package Path (Drag & Drop)", 21 | parameterID: 1, 22 | defaultValue: "", 23 | parameterFlags: FxParameterFlags(kFxParameterFlag_DEFAULT) 24 | ) 25 | 26 | apiManager.parameterCreationAPI.addPushButton( 27 | withName: "Compile", 28 | parameterID: 2, 29 | selector: #selector(SwiftUIViewGenerator.updateAndCompile), 30 | parameterFlags: FxParameterFlags(kFxParameterFlag_DEFAULT) 31 | ) 32 | 33 | apiManager.parameterCreationAPI.addIntSlider( 34 | withName: "Update", 35 | parameterID: 3, 36 | defaultValue: 0, 37 | parameterMin: Int32.min, 38 | parameterMax: Int32.max, 39 | sliderMin: Int32.min, 40 | sliderMax: Int32.max, 41 | delta: 1, 42 | parameterFlags: FxParameterFlags(kFxParameterFlag_DEFAULT) 43 | ) 44 | } 45 | 46 | override func pluginInstanceAddedToDocument() { 47 | logger.debug("Plugin instance added to document") 48 | compile() 49 | } 50 | 51 | override func pluginState( 52 | at renderTime: CMTime, 53 | quality _: UInt 54 | ) throws -> Data? { 55 | try JSONEncoder().encode(State( 56 | timelineTime: apiManager.timingAPI.timelineTime(fromInputTime: renderTime), 57 | timelineTimeRange: .init( 58 | start: apiManager.timingAPI.inPointTimeOfTimeline, 59 | end: apiManager.timingAPI.outPointTimeOfTimeline 60 | ), 61 | generatorTimeRange: .init( 62 | start: apiManager.timingAPI.timelineTime(fromInputTime: apiManager.timingAPI.startTime), 63 | duration: apiManager.timingAPI.timelineTime(fromInputTime: apiManager.timingAPI.duration) 64 | ) 65 | )) 66 | } 67 | 68 | override func renderDestinationImage( 69 | sourceImages: [CIImage], 70 | pluginState: Data?, 71 | at _: CMTime 72 | ) throws -> CIImage { 73 | try compileQueue.sync { 74 | guard let view else { return .clear } 75 | 76 | let state = try JSONDecoder().decode(State.self, from: pluginState ?? Data()) 77 | 78 | return DispatchQueue.main.sync { 79 | let renderer = ImageRenderer( 80 | content: view 81 | .environment(\.timelineTime, state.timelineTime) 82 | .environment(\.timelineTimeRange, state.timelineTimeRange) 83 | .environment(\.generatorTimeRange, state.generatorTimeRange) 84 | .frame(width: sourceImages[0].extent.width, height: sourceImages[0].extent.height) 85 | ) 86 | renderer.proposedSize = .init(sourceImages[0].extent.size) 87 | return CIImage(cgImage: renderer.cgImage!, options: [.applyOrientationProperty: true]) 88 | } 89 | } 90 | } 91 | 92 | // MARK: Private 93 | 94 | private let compileQueue = DispatchQueue(label: "SwiftUIViewGenerator.compile") 95 | private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "SwiftUIViewGenerator") 96 | private var view: AnyView? 97 | } 98 | 99 | // MARK: SwiftUIViewGenerator.State 100 | 101 | extension SwiftUIViewGenerator { 102 | struct State: Codable { 103 | let timelineTime: CMTime 104 | let timelineTimeRange: CMTimeRange 105 | let generatorTimeRange: CMTimeRange 106 | } 107 | } 108 | 109 | extension SwiftUIViewGenerator { 110 | @objc func updateAndCompile() { 111 | apiManager.parameterSettingAPI.setIntValue( 112 | Int32.random(in: Int32.min...Int32.max), 113 | toParameter: 3, 114 | at: .zero 115 | ) 116 | compile() 117 | } 118 | 119 | func compile() { 120 | compileQueue.sync { 121 | logger.debug("Compiling") 122 | var packagePath: NSString = "" 123 | apiManager.parameterRetrievalAPI.getStringParameterValue(&packagePath, fromParameter: 1) 124 | let package = URL(filePath: packagePath as String) 125 | 126 | guard !(packagePath as String).isEmpty else { return } 127 | 128 | do { 129 | let dylib = try swiftBuild(package: package) 130 | view = try loadView(from: dylib) 131 | } catch { 132 | logger.error("\(error.localizedDescription, privacy: .public)") 133 | Task { await showAlert(message: error.localizedDescription) } 134 | } 135 | } 136 | } 137 | 138 | private func swiftBuild(package: URL) throws -> URL { 139 | let dylib = package.appendingPathComponent(".build/release/lib\(package.lastPathComponent).dylib") 140 | try? FileManager.default.removeItem(at: dylib) 141 | 142 | let process = Process() 143 | process.executableURL = URL(filePath: "/usr/bin/swift") 144 | process.arguments = ["build", "-c", "release", "--package-path", package.path()] 145 | 146 | let standardError = Pipe() 147 | process.standardError = standardError 148 | 149 | let semaphore = DispatchSemaphore(value: 0) 150 | var error: Error? 151 | process.terminationHandler = { terminatedProcess in 152 | if terminatedProcess.terminationStatus != 0 { 153 | error = Error.swiftError( 154 | message: (try? standardError.fileHandleForReading.readToEnd()) 155 | .map { String(decoding: $0, as: UTF8.self) } ?? "Unknown Error" 156 | ) 157 | } 158 | semaphore.signal() 159 | } 160 | try process.run() 161 | semaphore.wait() 162 | if let error { throw error } 163 | return dylib 164 | } 165 | 166 | private func loadView(from dylib: URL) throws -> AnyView { 167 | guard let handle = dlopen(dylib.path, RTLD_NOW | RTLD_LOCAL) else { 168 | throw Error.dlopenFailed(error: String(cString: dlerror())) 169 | } 170 | defer { dlclose(handle) } 171 | guard let symbol = dlsym(handle, "createView") else { 172 | throw Error.missingSymbol 173 | } 174 | let pointer = unsafeBitCast(symbol, to: (@convention(c) () -> UnsafeMutableRawPointer).self)() 175 | let view = Unmanaged.fromOpaque(pointer).takeRetainedValue() 176 | return view as! AnyView 177 | } 178 | 179 | private func showAlert(message: String) async { 180 | CFUserNotificationDisplayNotice( 181 | 0, 182 | kCFUserNotificationCautionAlertLevel, 183 | nil, 184 | nil, 185 | nil, 186 | "SwiftUIFX" as CFString, 187 | message as CFString, 188 | "Ok" as CFString 189 | ) 190 | } 191 | } 192 | 193 | // MARK: - Error 194 | 195 | enum Error: Swift.Error, LocalizedError { 196 | case swiftError(message: String) 197 | case dlopenFailed(error: String) 198 | case missingSymbol 199 | 200 | // MARK: Internal 201 | 202 | var errorDescription: String? { 203 | switch self { 204 | case let .swiftError(message): message 205 | case let .dlopenFailed(error): error 206 | case .missingSymbol: 207 | """ 208 | Failed to load view from dylib. Make sure you include a createView function that returns a pointer to your view. Example: 209 | 210 | @_cdecl("createView") public func createView() -> UnsafeMutableRawPointer { 211 | return Unmanaged.passRetained( 212 | AnyView(MyView()) as AnyObject 213 | ).toOpaque() 214 | } 215 | """ 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /Plugin/Supporting Files/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | $(PRODUCT_NAME) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | 25 | PlugInKit 26 | 27 | Attributes 28 | 29 | com.apple.protocol 30 | FxPlug 31 | com.apple.version 32 | 1.1 33 | 34 | PrincipalClass 35 | FxPrincipal 36 | Protocol 37 | PROXPCProtocol 38 | Subsystems 39 | 40 | NSViewService_PKSubsystem 41 | 42 | 43 | ProPlugDictionaryVersion 44 | 1.0 45 | ProPlugDynamicRegistration 46 | 47 | ProPlugPlugInGroupList 48 | 49 | 50 | groupName 51 | SwiftUIFX 52 | uuid 53 | f3b088b3-6989-40ad-980c-080c82670c76 54 | 55 | 56 | ProPlugPlugInList 57 | 58 | 59 | className 60 | SwiftUIViewGenerator 61 | displayName 62 | SwiftUI View 63 | group 64 | f3b088b3-6989-40ad-980c-080c82670c76 65 | infoString 66 | A generator that renders a SwiftUI view. 67 | protocolNames 68 | 69 | FxFilter 70 | 71 | uuid 72 | 3BE439C5-D15E-45FA-A077-A82D837E77B0 73 | version 74 | 1.0 75 | 76 | 77 | XPCService 78 | 79 | JoinExistingSession 80 | 81 | RunLoopType 82 | _NSApplicationMain 83 | ServiceType 84 | Application 85 | _AdditionalSubServices 86 | 87 | viewbridge 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /Plugin/Supporting Files/Plugin-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import 2 | -------------------------------------------------------------------------------- /Plugin/TileableEffect.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // MARK: - TileableEffect 4 | 5 | class TileableEffect: NSObject, FxTileableEffect { 6 | // MARK: Lifecycle 7 | 8 | required init?(apiManager: any PROAPIAccessing) { 9 | self.apiManager = apiManager 10 | } 11 | 12 | // MARK: Internal 13 | 14 | let apiManager: PROAPIAccessing 15 | 16 | var properties: [String: Any] { 17 | [ 18 | kFxPropertyKey_MayRemapTime: false, 19 | kFxPropertyKey_VariesWhenParamsAreStatic: false 20 | ] 21 | } 22 | 23 | func pluginState( 24 | at _: CMTime, 25 | quality _: UInt 26 | ) throws -> Data? { 27 | nil 28 | } 29 | 30 | func destinationImageRect( 31 | sourceImage: FxImageTile, 32 | destinationImage _: FxImageTile, 33 | pluginState _: Data?, 34 | at _: CMTime 35 | ) -> CGRect { 36 | sourceImage.imagePixelBounds.cgRect 37 | } 38 | 39 | func sourceTileRect( 40 | sourceImage _: FxImageTile, 41 | destinationTileRect: CGRect, 42 | destinationImage _: FxImageTile, 43 | pluginState _: Data?, 44 | at _: CMTime 45 | ) -> CGRect { 46 | destinationTileRect 47 | } 48 | 49 | func renderDestinationImage( 50 | sourceImages: [CIImage], 51 | pluginState _: Data?, 52 | at _: CMTime 53 | ) throws -> CIImage { 54 | sourceImages.first ?? .clear 55 | } 56 | 57 | // MARK: Private 58 | 59 | private let context = CIContext() 60 | } 61 | 62 | extension TileableEffect { 63 | func pluginInstanceAddedToDocument() {} 64 | 65 | func addParameters() throws {} 66 | 67 | final func properties( 68 | _ properties: AutoreleasingUnsafeMutablePointer? 69 | ) throws { 70 | properties?.pointee = self.properties as NSDictionary 71 | } 72 | 73 | final func pluginState( 74 | _ pluginState: AutoreleasingUnsafeMutablePointer?, 75 | at renderTime: CMTime, 76 | quality qualityLevel: UInt 77 | ) throws { 78 | if let state = try self.pluginState( 79 | at: renderTime, 80 | quality: qualityLevel 81 | ) { 82 | pluginState?.pointee = state as NSData 83 | } 84 | } 85 | 86 | final func destinationImageRect( 87 | _ destinationImageRect: UnsafeMutablePointer, 88 | sourceImages: [FxImageTile], 89 | destinationImage: FxImageTile, 90 | pluginState: Data?, 91 | at renderTime: CMTime 92 | ) throws { 93 | destinationImageRect.pointee = FxRect(self.destinationImageRect( 94 | sourceImage: sourceImages[0], 95 | destinationImage: destinationImage, 96 | pluginState: pluginState, 97 | at: renderTime 98 | )) 99 | } 100 | 101 | final func sourceTileRect( 102 | _ sourceTileRect: UnsafeMutablePointer, 103 | sourceImageIndex _: UInt, 104 | sourceImages: [FxImageTile], 105 | destinationTileRect: FxRect, 106 | destinationImage: FxImageTile, 107 | pluginState: Data?, 108 | at renderTime: CMTime 109 | ) throws { 110 | sourceTileRect.pointee = FxRect(self.sourceTileRect( 111 | sourceImage: sourceImages[0], 112 | destinationTileRect: destinationTileRect.cgRect, 113 | destinationImage: destinationImage, 114 | pluginState: pluginState, 115 | at: renderTime 116 | )) 117 | } 118 | 119 | final func renderDestinationImage( 120 | _ destinationImage: FxImageTile, 121 | sourceImages: [FxImageTile], 122 | pluginState: Data?, 123 | at renderTime: CMTime 124 | ) throws { 125 | let sourceImages = sourceImages.map { 126 | CIImage( 127 | ioSurface: $0.ioSurface, 128 | options: $0.colorSpace.map { [.colorSpace: $0] } 129 | ) 130 | } 131 | 132 | var renderedImage = try renderDestinationImage( 133 | sourceImages: sourceImages, 134 | pluginState: pluginState, 135 | at: renderTime 136 | ) 137 | 138 | renderedImage = renderedImage.transformed( 139 | by: .identity 140 | .scaledBy(x: 1, y: -1) 141 | .translatedBy(x: 0, y: -renderedImage.extent.height) 142 | ) 143 | 144 | context.render( 145 | renderedImage, 146 | to: destinationImage.ioSurface, 147 | bounds: renderedImage.extent, 148 | colorSpace: destinationImage.colorSpace 149 | ) 150 | } 151 | 152 | func parameterChanged(_: UInt32, at _: CMTime) throws {} 153 | } 154 | -------------------------------------------------------------------------------- /Plugin/main.swift: -------------------------------------------------------------------------------- 1 | FxPrincipal.startServicePrincipal() 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftUIFX 2 | 3 | ![card](https://github.com/user-attachments/assets/e564f5b3-8f13-450e-a28c-b29c80f7eaa8) 4 | 5 | ### Instructions 6 | 7 | 1. Move the [SwiftUIFX app](https://github.com/finnvoor/SwiftUIFX/releases/latest/download/SwiftUIFX.app.zip) to Applications, and run `xattr -cr /Applications/SwiftUIFX.app` to un-quarantine the app (see https://github.com/finnvoor/SwiftUIFX/issues/4). Open the app at least once to allow it to run. 8 | 2. Unzip [SwiftUIFX.zip](https://github.com/finnvoor/SwiftUIFX/releases/latest/download/SwiftUIFX.zip) and place the SwiftUIFX directory into `/Applications/Final Cut Pro.app/Contents/PlugIns/MediaProviders/MotionEffect.fxp/Contents/Resources/Templates.localized/Generators.localized/`. 9 | 3. Ensure you have the Swift toolchain installed, and create a new Swift package. Ensure the package's library name matches the package name, and set the library's `type` to `.dynamic`. 10 | ```swift 11 | // swift-tools-version: 6.0 12 | 13 | import PackageDescription 14 | 15 | let package = Package( 16 | name: "MyVideoOverlay", 17 | platforms: [.macOS(.v13)], 18 | products: [.library(name: "MyVideoOverlay", type: .dynamic, targets: ["MyVideoOverlay"])], 19 | targets: [.target(name: "MyVideoOverlay")] 20 | ) 21 | ``` 22 | 4. Create a SwiftUI view in your package and expose it to the plugin by adding a `@_cdecl("createView")` function. 23 | ```swift 24 | import SwiftUI 25 | 26 | @_cdecl("createView") public func createView() -> UnsafeMutableRawPointer { 27 | return Unmanaged.passRetained( 28 | AnyView(MyView()) as AnyObject 29 | ).toOpaque() 30 | } 31 | 32 | struct MyView: View { 33 | var body: some View { 34 | Text("Hello World") 35 | } 36 | } 37 | 38 | #Preview { 39 | MyView() 40 | .frame(width: 1920, height: 1080) 41 | } 42 | ``` 43 | 5. Create or open a Final Cut Pro project and drag a "SwiftUI View" generator onto the timeline from the "Generators>SwiftUIFX" category in the library. 44 | 6. Select the generator, navigate to the generator inspector, and drag the top level directory of your Swift package into the "Package Path" text field. 45 | 7. Press the "Compile" button to compile your view. It should now be displayed in your video timeline. 46 | 8. Any time you make a change to your package you will need to press the "Compile" button again. 47 | 48 | > [!NOTE] 49 | > The SwiftUIFX mac app will not auto-update, so any updates will need to be manually downloaded from the latest release. 50 | 51 | ### Environment Values 52 | 53 | To access environment values in your SwiftUI view: 54 | 1. Add SwiftUIFX as a dependency of your package. 55 | ```swift 56 | let package = Package( 57 | name: "MyVideoOverlay", 58 | platforms: [.macOS(.v13)], 59 | products: [.library(name: "MyVideoOverlay", type: .dynamic, targets: ["MyVideoOverlay"])], 60 | dependencies: [.package(url: "https://github.com/finnvoor/SwiftUIFX.git", branch: "main")], 61 | targets: [.target(name: "MyVideoOverlay", dependencies: [.product(name: "SwiftUIFX", package: "SwiftUIFX")])] 62 | ) 63 | ``` 64 | 2. Import SwiftUIFX in your SwiftUI view. 65 | ```swift 66 | import SwiftUIFX 67 | ``` 68 | 3. Access the environment value using the `Environment` property wrapper. 69 | ```swift 70 | @Environment(\.timelineTime) var timelineTime: CMTime 71 | @Environment(\.timelineTimeRange) var timelineTimeRange: CMTimeRange 72 | @Environment(\.generatorTimeRange) var generatorTimeRange: CMTimeRange 73 | ``` 74 | 75 | > [!NOTE] 76 | > See the [Examples](Examples/) directory for example packages that can be used with SwiftUIFX. 77 | 78 | ### Development 79 | 80 | 1. Clone the repository. 81 | 2. Run `swift build -c release --arch arm64 --arch x86_64` at the top level of the repository. 82 | 3. Change the code sign identity in the build script phases of Plugin ("Copy and Code Sign FxPlug.framework" and "Copy and Code Sign PluginManager.framework"). 83 | 4. Open `SwiftUIFX.xcodeproj`. 84 | 85 | ### Acknowledgements 86 | 87 | Thanks to [Arclite/Halloween2024](https://github.com/Arclite/Halloween2024) for demonstrating how SwiftUI views can be loaded from a dylib. 88 | -------------------------------------------------------------------------------- /Sources/SwiftUIFX/EnvironmentValues+Extensions.swift: -------------------------------------------------------------------------------- 1 | import CoreMedia 2 | import SwiftUI 3 | 4 | public extension EnvironmentValues { 5 | @Entry var timelineTime: CMTime = .zero 6 | @Entry var timelineTimeRange: CMTimeRange = .zero 7 | @Entry var generatorTimeRange: CMTimeRange = .zero 8 | } 9 | -------------------------------------------------------------------------------- /SwiftUIFX.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 77; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6ED15EB72CD55F12005E38B1 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6ED15EB62CD55F12005E38B1 /* Cocoa.framework */; }; 11 | 6ED15EC32CD55F12005E38B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6ED15EC22CD55F12005E38B1 /* Foundation.framework */; }; 12 | 6ED15EC52CD55F12005E38B1 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6ED15EC42CD55F12005E38B1 /* AppKit.framework */; }; 13 | 6ED15EC72CD55F12005E38B1 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6ED15EC62CD55F12005E38B1 /* Accelerate.framework */; }; 14 | 6ED15EC92CD55F12005E38B1 /* PluginManager.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6ED15EC82CD55F12005E38B1 /* PluginManager.framework */; }; 15 | 6ED15ECB2CD55F12005E38B1 /* FxPlug.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6ED15ECA2CD55F12005E38B1 /* FxPlug.framework */; }; 16 | 6ED15F652CD59553005E38B1 /* Plugin.pluginkit in Embed PlugIns */ = {isa = PBXBuildFile; fileRef = 6ED15EBE2CD55F12005E38B1 /* Plugin.pluginkit */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 17 | 6EDFED492CE2B158003C1B4F /* libSwiftUIFX.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 6EDFED482CE2B158003C1B4F /* libSwiftUIFX.dylib */; }; 18 | 6EDFED4A2CE2B158003C1B4F /* libSwiftUIFX.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 6EDFED482CE2B158003C1B4F /* libSwiftUIFX.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | 6ED15EC02CD55F12005E38B1 /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = 6ED15EAB2CD55F12005E38B1 /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = 6ED15EBD2CD55F12005E38B1; 27 | remoteInfo = "XPC Service"; 28 | }; 29 | /* End PBXContainerItemProxy section */ 30 | 31 | /* Begin PBXCopyFilesBuildPhase section */ 32 | 6ED15EF42CD55F12005E38B1 /* Embed PlugIns */ = { 33 | isa = PBXCopyFilesBuildPhase; 34 | buildActionMask = 2147483647; 35 | dstPath = ""; 36 | dstSubfolderSpec = 13; 37 | files = ( 38 | 6ED15F652CD59553005E38B1 /* Plugin.pluginkit in Embed PlugIns */, 39 | ); 40 | name = "Embed PlugIns"; 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | 6EDFED4B2CE2B158003C1B4F /* Embed Libraries */ = { 44 | isa = PBXCopyFilesBuildPhase; 45 | buildActionMask = 2147483647; 46 | dstPath = ""; 47 | dstSubfolderSpec = 10; 48 | files = ( 49 | 6EDFED4A2CE2B158003C1B4F /* libSwiftUIFX.dylib in Embed Libraries */, 50 | ); 51 | name = "Embed Libraries"; 52 | runOnlyForDeploymentPostprocessing = 0; 53 | }; 54 | /* End PBXCopyFilesBuildPhase section */ 55 | 56 | /* Begin PBXFileReference section */ 57 | 6ED15EB32CD55F12005E38B1 /* SwiftUIFX Mac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SwiftUIFX Mac.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 6ED15EB62CD55F12005E38B1 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 59 | 6ED15EBE2CD55F12005E38B1 /* Plugin.pluginkit */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Plugin.pluginkit; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | 6ED15EC22CD55F12005E38B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 61 | 6ED15EC42CD55F12005E38B1 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 62 | 6ED15EC62CD55F12005E38B1 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 63 | 6ED15EC82CD55F12005E38B1 /* PluginManager.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PluginManager.framework; path = Library/Frameworks/../../../../../../Library/Developer/Frameworks/PluginManager.framework; sourceTree = DEVELOPER_DIR; }; 64 | 6ED15ECA2CD55F12005E38B1 /* FxPlug.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FxPlug.framework; path = Library/Frameworks/../../../../../../Library/Developer/Frameworks/FxPlug.framework; sourceTree = DEVELOPER_DIR; }; 65 | 6ED1605E2CD936FF005E38B1 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; }; 66 | 6EDFED482CE2B158003C1B4F /* libSwiftUIFX.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libSwiftUIFX.dylib; path = .build/apple/Products/Release/libSwiftUIFX.dylib; sourceTree = ""; }; 67 | /* End PBXFileReference section */ 68 | 69 | /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ 70 | 6EAB614C2CD9538D0061B077 /* Exceptions for "macOS App" folder in "macOS App" target */ = { 71 | isa = PBXFileSystemSynchronizedBuildFileExceptionSet; 72 | membershipExceptions = ( 73 | "Supporting Files/Info.plist", 74 | ); 75 | target = 6ED15EB22CD55F12005E38B1 /* macOS App */; 76 | }; 77 | 6ED15F592CD5601D005E38B1 /* Exceptions for "Plugin" folder in "macOS App" target */ = { 78 | isa = PBXFileSystemSynchronizedBuildFileExceptionSet; 79 | membershipExceptions = ( 80 | "Extensions/CMTime+Extensions.swift", 81 | "Extensions/CMTimeRange+Extensions.swift", 82 | "Extensions/FxRect+Extensions.swift", 83 | "Extensions/FxTimingAPI_v4+Extensions.swift", 84 | "Extensions/PROAPIAccessing+Extensions.swift", 85 | Generators/SwiftUIViewGenerator.swift, 86 | main.swift, 87 | "Supporting Files/Info.plist", 88 | TileableEffect.swift, 89 | ); 90 | target = 6ED15EB22CD55F12005E38B1 /* macOS App */; 91 | }; 92 | 6ED15F5C2CD56020005E38B1 /* Exceptions for "Plugin" folder in "Plugin" target */ = { 93 | isa = PBXFileSystemSynchronizedBuildFileExceptionSet; 94 | membershipExceptions = ( 95 | "Supporting Files/Info.plist", 96 | ); 97 | target = 6ED15EBD2CD55F12005E38B1 /* Plugin */; 98 | }; 99 | /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ 100 | 101 | /* Begin PBXFileSystemSynchronizedRootGroup section */ 102 | 6E722F482CD951F6006A8679 /* macOS App */ = { 103 | isa = PBXFileSystemSynchronizedRootGroup; 104 | exceptions = ( 105 | 6EAB614C2CD9538D0061B077 /* Exceptions for "macOS App" folder in "macOS App" target */, 106 | ); 107 | path = "macOS App"; 108 | sourceTree = ""; 109 | }; 110 | 6ED15F352CD55F55005E38B1 /* Plugin */ = { 111 | isa = PBXFileSystemSynchronizedRootGroup; 112 | exceptions = ( 113 | 6ED15F592CD5601D005E38B1 /* Exceptions for "Plugin" folder in "macOS App" target */, 114 | 6ED15F5C2CD56020005E38B1 /* Exceptions for "Plugin" folder in "Plugin" target */, 115 | ); 116 | path = Plugin; 117 | sourceTree = ""; 118 | }; 119 | /* End PBXFileSystemSynchronizedRootGroup section */ 120 | 121 | /* Begin PBXFrameworksBuildPhase section */ 122 | 6ED15EB02CD55F12005E38B1 /* Frameworks */ = { 123 | isa = PBXFrameworksBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | 6ED15EB72CD55F12005E38B1 /* Cocoa.framework in Frameworks */, 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | 6ED15EB92CD55F12005E38B1 /* Frameworks */ = { 131 | isa = PBXFrameworksBuildPhase; 132 | buildActionMask = 2147483647; 133 | files = ( 134 | 6ED15EC72CD55F12005E38B1 /* Accelerate.framework in Frameworks */, 135 | 6ED15EC92CD55F12005E38B1 /* PluginManager.framework in Frameworks */, 136 | 6EDFED492CE2B158003C1B4F /* libSwiftUIFX.dylib in Frameworks */, 137 | 6ED15EC32CD55F12005E38B1 /* Foundation.framework in Frameworks */, 138 | 6ED15EC52CD55F12005E38B1 /* AppKit.framework in Frameworks */, 139 | 6ED15ECB2CD55F12005E38B1 /* FxPlug.framework in Frameworks */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | /* End PBXFrameworksBuildPhase section */ 144 | 145 | /* Begin PBXGroup section */ 146 | 6ED15EAA2CD55F12005E38B1 = { 147 | isa = PBXGroup; 148 | children = ( 149 | 6E722F482CD951F6006A8679 /* macOS App */, 150 | 6ED1605E2CD936FF005E38B1 /* Config.xcconfig */, 151 | 6ED15F352CD55F55005E38B1 /* Plugin */, 152 | 6ED15EB52CD55F12005E38B1 /* Frameworks */, 153 | 6ED15EB42CD55F12005E38B1 /* Products */, 154 | ); 155 | sourceTree = ""; 156 | }; 157 | 6ED15EB42CD55F12005E38B1 /* Products */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 6ED15EB32CD55F12005E38B1 /* SwiftUIFX Mac.app */, 161 | 6ED15EBE2CD55F12005E38B1 /* Plugin.pluginkit */, 162 | ); 163 | name = Products; 164 | sourceTree = ""; 165 | }; 166 | 6ED15EB52CD55F12005E38B1 /* Frameworks */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 6EDFED482CE2B158003C1B4F /* libSwiftUIFX.dylib */, 170 | 6ED15EB62CD55F12005E38B1 /* Cocoa.framework */, 171 | 6ED15EC22CD55F12005E38B1 /* Foundation.framework */, 172 | 6ED15EC42CD55F12005E38B1 /* AppKit.framework */, 173 | 6ED15EC62CD55F12005E38B1 /* Accelerate.framework */, 174 | 6ED15EC82CD55F12005E38B1 /* PluginManager.framework */, 175 | 6ED15ECA2CD55F12005E38B1 /* FxPlug.framework */, 176 | ); 177 | name = Frameworks; 178 | sourceTree = ""; 179 | }; 180 | /* End PBXGroup section */ 181 | 182 | /* Begin PBXNativeTarget section */ 183 | 6ED15EB22CD55F12005E38B1 /* macOS App */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = 6ED15EF52CD55F12005E38B1 /* Build configuration list for PBXNativeTarget "macOS App" */; 186 | buildPhases = ( 187 | 6ED15EAF2CD55F12005E38B1 /* Sources */, 188 | 6ED15EB02CD55F12005E38B1 /* Frameworks */, 189 | 6ED15EB12CD55F12005E38B1 /* Resources */, 190 | 6ED15EF42CD55F12005E38B1 /* Embed PlugIns */, 191 | ); 192 | buildRules = ( 193 | ); 194 | dependencies = ( 195 | 6ED15EC12CD55F12005E38B1 /* PBXTargetDependency */, 196 | ); 197 | fileSystemSynchronizedGroups = ( 198 | 6E722F482CD951F6006A8679 /* macOS App */, 199 | 6ED15F352CD55F55005E38B1 /* Plugin */, 200 | ); 201 | name = "macOS App"; 202 | packageProductDependencies = ( 203 | ); 204 | productName = "Wrapper Application"; 205 | productReference = 6ED15EB32CD55F12005E38B1 /* SwiftUIFX Mac.app */; 206 | productType = "com.apple.product-type.application"; 207 | }; 208 | 6ED15EBD2CD55F12005E38B1 /* Plugin */ = { 209 | isa = PBXNativeTarget; 210 | buildConfigurationList = 6ED15EF12CD55F12005E38B1 /* Build configuration list for PBXNativeTarget "Plugin" */; 211 | buildPhases = ( 212 | 6ED15EB82CD55F12005E38B1 /* Sources */, 213 | 6ED15EB92CD55F12005E38B1 /* Frameworks */, 214 | 6ED15EBA2CD55F12005E38B1 /* Resources */, 215 | 6ED15EBB2CD55F12005E38B1 /* Copy and Code Sign FxPlug.framework */, 216 | 6ED15EBC2CD55F12005E38B1 /* Copy and Code Sign PluginManager.framework */, 217 | 6EDFED4B2CE2B158003C1B4F /* Embed Libraries */, 218 | ); 219 | buildRules = ( 220 | ); 221 | dependencies = ( 222 | 6EDFED752CE2B3A5003C1B4F /* PBXTargetDependency */, 223 | ); 224 | fileSystemSynchronizedGroups = ( 225 | 6ED15F352CD55F55005E38B1 /* Plugin */, 226 | ); 227 | name = Plugin; 228 | packageProductDependencies = ( 229 | ); 230 | productName = "XPC Service"; 231 | productReference = 6ED15EBE2CD55F12005E38B1 /* Plugin.pluginkit */; 232 | productType = "com.apple.product-type.bundle"; 233 | }; 234 | /* End PBXNativeTarget section */ 235 | 236 | /* Begin PBXProject section */ 237 | 6ED15EAB2CD55F12005E38B1 /* Project object */ = { 238 | isa = PBXProject; 239 | attributes = { 240 | BuildIndependentTargetsInParallel = 1; 241 | LastSwiftUpdateCheck = 1620; 242 | LastUpgradeCheck = 1620; 243 | TargetAttributes = { 244 | 6ED15EB22CD55F12005E38B1 = { 245 | CreatedOnToolsVersion = 16.2; 246 | }; 247 | 6ED15EBD2CD55F12005E38B1 = { 248 | CreatedOnToolsVersion = 16.2; 249 | }; 250 | }; 251 | }; 252 | buildConfigurationList = 6ED15EAE2CD55F12005E38B1 /* Build configuration list for PBXProject "SwiftUIFX" */; 253 | developmentRegion = en; 254 | hasScannedForEncodings = 0; 255 | knownRegions = ( 256 | en, 257 | Base, 258 | ); 259 | mainGroup = 6ED15EAA2CD55F12005E38B1; 260 | minimizedProjectReferenceProxies = 1; 261 | packageReferences = ( 262 | 6EAB61492CD953150061B077 /* XCLocalSwiftPackageReference "../SwiftUIFX" */, 263 | ); 264 | preferredProjectObjectVersion = 77; 265 | productRefGroup = 6ED15EB42CD55F12005E38B1 /* Products */; 266 | projectDirPath = ""; 267 | projectRoot = ""; 268 | targets = ( 269 | 6ED15EB22CD55F12005E38B1 /* macOS App */, 270 | 6ED15EBD2CD55F12005E38B1 /* Plugin */, 271 | ); 272 | }; 273 | /* End PBXProject section */ 274 | 275 | /* Begin PBXResourcesBuildPhase section */ 276 | 6ED15EB12CD55F12005E38B1 /* Resources */ = { 277 | isa = PBXResourcesBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | 6ED15EBA2CD55F12005E38B1 /* Resources */ = { 284 | isa = PBXResourcesBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | ); 288 | runOnlyForDeploymentPostprocessing = 0; 289 | }; 290 | /* End PBXResourcesBuildPhase section */ 291 | 292 | /* Begin PBXShellScriptBuildPhase section */ 293 | 6ED15EBB2CD55F12005E38B1 /* Copy and Code Sign FxPlug.framework */ = { 294 | isa = PBXShellScriptBuildPhase; 295 | alwaysOutOfDate = 1; 296 | buildActionMask = 2147483647; 297 | files = ( 298 | ); 299 | inputFileListPaths = ( 300 | ); 301 | inputPaths = ( 302 | ); 303 | name = "Copy and Code Sign FxPlug.framework"; 304 | outputFileListPaths = ( 305 | ); 306 | outputPaths = ( 307 | ); 308 | runOnlyForDeploymentPostprocessing = 0; 309 | shellPath = /bin/sh; 310 | shellScript = "mkdir -p \"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\nrsync --archive --links --whole-file --no-owner --no-group --checksum --exclude='Headers' \"/Library/Developer/Frameworks/FxPlug.framework/\" \"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FxPlug.framework/\"\nif [ \"$?\" -ne 0 ]; then echo \"error: rsync failed; couldn't embed FxPlug.framework\"; exit 1; fi\ncodesign --force --timestamp --options runtime --sign \"96AA7C23A46426BF1C63DCFBF642E02A7819FF93\" \"${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/FxPlug.framework\"\n"; 311 | showEnvVarsInLog = 0; 312 | }; 313 | 6ED15EBC2CD55F12005E38B1 /* Copy and Code Sign PluginManager.framework */ = { 314 | isa = PBXShellScriptBuildPhase; 315 | alwaysOutOfDate = 1; 316 | buildActionMask = 2147483647; 317 | files = ( 318 | ); 319 | inputFileListPaths = ( 320 | ); 321 | inputPaths = ( 322 | ); 323 | name = "Copy and Code Sign PluginManager.framework"; 324 | outputFileListPaths = ( 325 | ); 326 | outputPaths = ( 327 | ); 328 | runOnlyForDeploymentPostprocessing = 0; 329 | shellPath = /bin/sh; 330 | shellScript = "mkdir -p \"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\nrsync --archive --links --whole-file --no-owner --no-group --checksum --exclude='Headers' \"/Library/Developer/Frameworks/PluginManager.framework/\" \"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PluginManager.framework/\"\nif [ \"$?\" -ne 0 ]; then echo \"error: rsync failed; couldn't embed PluginManager.framework\"; exit 1; fi\ncodesign --force --timestamp --options runtime --sign \"96AA7C23A46426BF1C63DCFBF642E02A7819FF93\" \"${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/PluginManager.framework\"\n"; 331 | showEnvVarsInLog = 0; 332 | }; 333 | /* End PBXShellScriptBuildPhase section */ 334 | 335 | /* Begin PBXSourcesBuildPhase section */ 336 | 6ED15EAF2CD55F12005E38B1 /* Sources */ = { 337 | isa = PBXSourcesBuildPhase; 338 | buildActionMask = 2147483647; 339 | files = ( 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | 6ED15EB82CD55F12005E38B1 /* Sources */ = { 344 | isa = PBXSourcesBuildPhase; 345 | buildActionMask = 2147483647; 346 | files = ( 347 | ); 348 | runOnlyForDeploymentPostprocessing = 0; 349 | }; 350 | /* End PBXSourcesBuildPhase section */ 351 | 352 | /* Begin PBXTargetDependency section */ 353 | 6ED15EC12CD55F12005E38B1 /* PBXTargetDependency */ = { 354 | isa = PBXTargetDependency; 355 | target = 6ED15EBD2CD55F12005E38B1 /* Plugin */; 356 | targetProxy = 6ED15EC02CD55F12005E38B1 /* PBXContainerItemProxy */; 357 | }; 358 | 6EDFED752CE2B3A5003C1B4F /* PBXTargetDependency */ = { 359 | isa = PBXTargetDependency; 360 | productRef = 6EDFED742CE2B3A5003C1B4F /* SwiftUIFX */; 361 | }; 362 | /* End PBXTargetDependency section */ 363 | 364 | /* Begin XCBuildConfiguration section */ 365 | 6ED15EF22CD55F12005E38B1 /* Debug */ = { 366 | isa = XCBuildConfiguration; 367 | baseConfigurationReference = 6ED1605E2CD936FF005E38B1 /* Config.xcconfig */; 368 | buildSettings = { 369 | CODE_SIGN_STYLE = Automatic; 370 | DEVELOPMENT_TEAM = YF6GMG9Q86; 371 | ENABLE_USER_SCRIPT_SANDBOXING = NO; 372 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 373 | INFOPLIST_FILE = "$(TARGET_NAME)/Supporting Files/Info.plist"; 374 | LD_RUNPATH_SEARCH_PATHS = ( 375 | "$(inherited)", 376 | "@loader_path/../Frameworks", 377 | ); 378 | LIBRARY_SEARCH_PATHS = ( 379 | "$(inherited)", 380 | "$(PROJECT_DIR)/.build/apple/Products/Release", 381 | ); 382 | MACH_O_TYPE = mh_execute; 383 | PRODUCT_BUNDLE_IDENTIFIER = com.finnvoorhees.SwiftUIFX.plugin; 384 | PRODUCT_NAME = "$(TARGET_NAME)"; 385 | SWIFT_OBJC_BRIDGING_HEADER = "$(TARGET_NAME)/Supporting Files/$(TARGET_NAME)-Bridging-Header.h"; 386 | WRAPPER_EXTENSION = pluginkit; 387 | }; 388 | name = Debug; 389 | }; 390 | 6ED15EF32CD55F12005E38B1 /* Release */ = { 391 | isa = XCBuildConfiguration; 392 | baseConfigurationReference = 6ED1605E2CD936FF005E38B1 /* Config.xcconfig */; 393 | buildSettings = { 394 | CODE_SIGN_STYLE = Automatic; 395 | DEVELOPMENT_TEAM = YF6GMG9Q86; 396 | ENABLE_USER_SCRIPT_SANDBOXING = NO; 397 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 398 | INFOPLIST_FILE = "$(TARGET_NAME)/Supporting Files/Info.plist"; 399 | LD_RUNPATH_SEARCH_PATHS = ( 400 | "$(inherited)", 401 | "@loader_path/../Frameworks", 402 | ); 403 | LIBRARY_SEARCH_PATHS = ( 404 | "$(inherited)", 405 | "$(PROJECT_DIR)/.build/apple/Products/Release", 406 | ); 407 | MACH_O_TYPE = mh_execute; 408 | PRODUCT_BUNDLE_IDENTIFIER = com.finnvoorhees.SwiftUIFX.plugin; 409 | PRODUCT_NAME = "$(TARGET_NAME)"; 410 | SWIFT_OBJC_BRIDGING_HEADER = "$(TARGET_NAME)/Supporting Files/$(TARGET_NAME)-Bridging-Header.h"; 411 | WRAPPER_EXTENSION = pluginkit; 412 | }; 413 | name = Release; 414 | }; 415 | 6ED15EF62CD55F12005E38B1 /* Debug */ = { 416 | isa = XCBuildConfiguration; 417 | baseConfigurationReference = 6ED1605E2CD936FF005E38B1 /* Config.xcconfig */; 418 | buildSettings = { 419 | CODE_SIGN_ENTITLEMENTS = "$(TARGET_NAME)/Supporting Files/Entitlements.entitlements"; 420 | CODE_SIGN_STYLE = Automatic; 421 | DEVELOPMENT_TEAM = YF6GMG9Q86; 422 | ENABLE_HARDENED_RUNTIME = NO; 423 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 424 | INFOPLIST_FILE = "$(TARGET_NAME)/Supporting Files/Info.plist"; 425 | PRODUCT_BUNDLE_IDENTIFIER = com.finnvoorhees.SwiftUIFX; 426 | PRODUCT_NAME = "SwiftUIFX Mac"; 427 | SWIFT_VERSION = 6.0; 428 | }; 429 | name = Debug; 430 | }; 431 | 6ED15EF72CD55F12005E38B1 /* Release */ = { 432 | isa = XCBuildConfiguration; 433 | baseConfigurationReference = 6ED1605E2CD936FF005E38B1 /* Config.xcconfig */; 434 | buildSettings = { 435 | CODE_SIGN_ENTITLEMENTS = "$(TARGET_NAME)/Supporting Files/Entitlements.entitlements"; 436 | CODE_SIGN_STYLE = Automatic; 437 | DEVELOPMENT_TEAM = YF6GMG9Q86; 438 | ENABLE_HARDENED_RUNTIME = NO; 439 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 440 | INFOPLIST_FILE = "$(TARGET_NAME)/Supporting Files/Info.plist"; 441 | PRODUCT_BUNDLE_IDENTIFIER = com.finnvoorhees.SwiftUIFX; 442 | PRODUCT_NAME = "SwiftUIFX Mac"; 443 | SWIFT_VERSION = 6.0; 444 | }; 445 | name = Release; 446 | }; 447 | 6ED15EF92CD55F12005E38B1 /* Debug */ = { 448 | isa = XCBuildConfiguration; 449 | baseConfigurationReference = 6ED1605E2CD936FF005E38B1 /* Config.xcconfig */; 450 | buildSettings = { 451 | ADDITIONAL_SDKS = /Library/Developer/SDKs/FxPlug.sdk; 452 | ALWAYS_SEARCH_USER_PATHS = NO; 453 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 454 | CLANG_ANALYZER_NONNULL = YES; 455 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 456 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 457 | CLANG_ENABLE_MODULES = YES; 458 | CLANG_ENABLE_OBJC_ARC = NO; 459 | CLANG_ENABLE_OBJC_WEAK = YES; 460 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 461 | CLANG_WARN_BOOL_CONVERSION = YES; 462 | CLANG_WARN_COMMA = YES; 463 | CLANG_WARN_CONSTANT_CONVERSION = YES; 464 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 465 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 466 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 467 | CLANG_WARN_EMPTY_BODY = YES; 468 | CLANG_WARN_ENUM_CONVERSION = YES; 469 | CLANG_WARN_INFINITE_RECURSION = YES; 470 | CLANG_WARN_INT_CONVERSION = YES; 471 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 472 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 473 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 474 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 475 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 476 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 477 | CLANG_WARN_STRICT_PROTOTYPES = YES; 478 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 479 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 480 | CLANG_WARN_UNREACHABLE_CODE = YES; 481 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 482 | COPY_PHASE_STRIP = NO; 483 | DEBUG_INFORMATION_FORMAT = dwarf; 484 | ENABLE_STRICT_OBJC_MSGSEND = YES; 485 | ENABLE_TESTABILITY = YES; 486 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 487 | FRAMEWORK_SEARCH_PATHS = ( 488 | /Library/Frameworks, 489 | "$(inherited)", 490 | ); 491 | GCC_C_LANGUAGE_STANDARD = gnu17; 492 | GCC_DYNAMIC_NO_PIC = NO; 493 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 494 | GCC_NO_COMMON_BLOCKS = YES; 495 | GCC_OPTIMIZATION_LEVEL = 0; 496 | GCC_PREPROCESSOR_DEFINITIONS = ( 497 | "DEBUG=1", 498 | "$(inherited)", 499 | ); 500 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 501 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 502 | GCC_WARN_UNDECLARED_SELECTOR = YES; 503 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 504 | GCC_WARN_UNUSED_FUNCTION = YES; 505 | GCC_WARN_UNUSED_VARIABLE = YES; 506 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 507 | MACOSX_DEPLOYMENT_TARGET = 15.0; 508 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 509 | MTL_FAST_MATH = YES; 510 | ONLY_ACTIVE_ARCH = YES; 511 | SDKROOT = macosx; 512 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; 513 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 514 | SWIFT_VERSION = 5; 515 | }; 516 | name = Debug; 517 | }; 518 | 6ED15EFA2CD55F12005E38B1 /* Release */ = { 519 | isa = XCBuildConfiguration; 520 | baseConfigurationReference = 6ED1605E2CD936FF005E38B1 /* Config.xcconfig */; 521 | buildSettings = { 522 | ADDITIONAL_SDKS = /Library/Developer/SDKs/FxPlug.sdk; 523 | ALWAYS_SEARCH_USER_PATHS = NO; 524 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 525 | CLANG_ANALYZER_NONNULL = YES; 526 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 527 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 528 | CLANG_ENABLE_MODULES = YES; 529 | CLANG_ENABLE_OBJC_ARC = NO; 530 | CLANG_ENABLE_OBJC_WEAK = YES; 531 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 532 | CLANG_WARN_BOOL_CONVERSION = YES; 533 | CLANG_WARN_COMMA = YES; 534 | CLANG_WARN_CONSTANT_CONVERSION = YES; 535 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 536 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 537 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 538 | CLANG_WARN_EMPTY_BODY = YES; 539 | CLANG_WARN_ENUM_CONVERSION = YES; 540 | CLANG_WARN_INFINITE_RECURSION = YES; 541 | CLANG_WARN_INT_CONVERSION = YES; 542 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 543 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 544 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 545 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 546 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 547 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 548 | CLANG_WARN_STRICT_PROTOTYPES = YES; 549 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 550 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 551 | CLANG_WARN_UNREACHABLE_CODE = YES; 552 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 553 | COPY_PHASE_STRIP = NO; 554 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 555 | ENABLE_NS_ASSERTIONS = NO; 556 | ENABLE_STRICT_OBJC_MSGSEND = YES; 557 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 558 | FRAMEWORK_SEARCH_PATHS = ( 559 | /Library/Frameworks, 560 | "$(inherited)", 561 | ); 562 | GCC_C_LANGUAGE_STANDARD = gnu17; 563 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 564 | GCC_NO_COMMON_BLOCKS = YES; 565 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 566 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 567 | GCC_WARN_UNDECLARED_SELECTOR = YES; 568 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 569 | GCC_WARN_UNUSED_FUNCTION = YES; 570 | GCC_WARN_UNUSED_VARIABLE = YES; 571 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 572 | MACOSX_DEPLOYMENT_TARGET = 15.0; 573 | MTL_ENABLE_DEBUG_INFO = NO; 574 | MTL_FAST_MATH = YES; 575 | SDKROOT = macosx; 576 | SWIFT_COMPILATION_MODE = wholemodule; 577 | SWIFT_VERSION = 5; 578 | }; 579 | name = Release; 580 | }; 581 | /* End XCBuildConfiguration section */ 582 | 583 | /* Begin XCConfigurationList section */ 584 | 6ED15EAE2CD55F12005E38B1 /* Build configuration list for PBXProject "SwiftUIFX" */ = { 585 | isa = XCConfigurationList; 586 | buildConfigurations = ( 587 | 6ED15EF92CD55F12005E38B1 /* Debug */, 588 | 6ED15EFA2CD55F12005E38B1 /* Release */, 589 | ); 590 | defaultConfigurationIsVisible = 0; 591 | defaultConfigurationName = Release; 592 | }; 593 | 6ED15EF12CD55F12005E38B1 /* Build configuration list for PBXNativeTarget "Plugin" */ = { 594 | isa = XCConfigurationList; 595 | buildConfigurations = ( 596 | 6ED15EF22CD55F12005E38B1 /* Debug */, 597 | 6ED15EF32CD55F12005E38B1 /* Release */, 598 | ); 599 | defaultConfigurationIsVisible = 0; 600 | defaultConfigurationName = Release; 601 | }; 602 | 6ED15EF52CD55F12005E38B1 /* Build configuration list for PBXNativeTarget "macOS App" */ = { 603 | isa = XCConfigurationList; 604 | buildConfigurations = ( 605 | 6ED15EF62CD55F12005E38B1 /* Debug */, 606 | 6ED15EF72CD55F12005E38B1 /* Release */, 607 | ); 608 | defaultConfigurationIsVisible = 0; 609 | defaultConfigurationName = Release; 610 | }; 611 | /* End XCConfigurationList section */ 612 | 613 | /* Begin XCLocalSwiftPackageReference section */ 614 | 6EAB61492CD953150061B077 /* XCLocalSwiftPackageReference "../SwiftUIFX" */ = { 615 | isa = XCLocalSwiftPackageReference; 616 | relativePath = ../SwiftUIFX; 617 | }; 618 | /* End XCLocalSwiftPackageReference section */ 619 | 620 | /* Begin XCSwiftPackageProductDependency section */ 621 | 6EDFED742CE2B3A5003C1B4F /* SwiftUIFX */ = { 622 | isa = XCSwiftPackageProductDependency; 623 | package = 6EAB61492CD953150061B077 /* XCLocalSwiftPackageReference "../SwiftUIFX" */; 624 | productName = SwiftUIFX; 625 | }; 626 | /* End XCSwiftPackageProductDependency section */ 627 | }; 628 | rootObject = 6ED15EAB2CD55F12005E38B1 /* Project object */; 629 | } 630 | -------------------------------------------------------------------------------- /SwiftUIFX.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftUIFX.xcodeproj/xcshareddata/xcschemes/macOS App.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 25 | 26 | 32 | 33 | 43 | 47 | 48 | 49 | 55 | 56 | 57 | 58 | 64 | 66 | 72 | 73 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /macOS App/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import AppKit 2 | 3 | @objc(AppDelegate) @main class AppDelegate: NSObject, NSApplicationDelegate { 4 | @IBOutlet var window: NSWindow! 5 | } 6 | -------------------------------------------------------------------------------- /macOS App/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | Default 539 | 540 | 541 | 542 | 543 | 544 | 545 | Left to Right 546 | 547 | 548 | 549 | 550 | 551 | 552 | Right to Left 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | Default 564 | 565 | 566 | 567 | 568 | 569 | 570 | Left to Right 571 | 572 | 573 | 574 | 575 | 576 | 577 | Right to Left 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | -------------------------------------------------------------------------------- /macOS App/Supporting Files/Entitlements.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /macOS App/Supporting Files/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | LSApplicationCategoryType 24 | public.app-category.video 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | --------------------------------------------------------------------------------