├── .gitignore ├── Audio ├── apikeyMissing.mp3 ├── enviromentCreating.mp3 ├── enviromentFailed.mp3 ├── promptMissing.mp3 └── welcome.mp3 ├── Flode_VR.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ ├── WorkspaceSettings.xcsettings │ │ └── swiftpm │ │ │ └── Package.resolved │ └── xcuserdata │ │ └── tadeo.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── WorkspaceSettings.xcsettings └── xcuserdata │ └── tadeo.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── Flode_VR ├── AssetSelectorView.swift ├── Assets.xcassets │ ├── AppIcon.solidimagestack │ │ ├── Back.solidimagestacklayer │ │ │ ├── Content.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── background.png │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── Front.solidimagestacklayer │ │ │ ├── Content.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── layer1.png │ │ │ └── Contents.json │ │ └── Middle.solidimagestacklayer │ │ │ ├── Content.imageset │ │ │ ├── Contents.json │ │ │ └── layer2.png │ │ │ └── Contents.json │ ├── Contents.json │ ├── airplane.imageset │ │ ├── Contents.json │ │ └── WhatsApp Image 2024-02-09 at 13.07.11.jpeg │ ├── anfield.imageset │ │ ├── Anfield1.jpg │ │ └── Contents.json │ ├── buckingham.imageset │ │ ├── Buckingham.jpg │ │ └── Contents.json │ ├── colon.imageset │ │ ├── Contents.json │ │ └── WhatsApp Image 2024-02-09 at 13.07.31.jpeg │ ├── eiffel.imageset │ │ ├── Contents.json │ │ └── Eiffel.jpg │ ├── esteros.imageset │ │ ├── Contents.json │ │ └── Esteros.jpg │ ├── fitz.imageset │ │ ├── Contents.json │ │ └── Fitz.jpg │ ├── iceland.imageset │ │ ├── Contents.json │ │ └── Islandia.jpg │ ├── jefferson.imageset │ │ ├── Contents.json │ │ └── Jefferson.jpg │ ├── mask.imageset │ │ ├── Contents.json │ │ └── mask.png │ ├── penguins.imageset │ │ ├── Contents.json │ │ └── Pinguinos.jpg │ ├── perito.imageset │ │ ├── Contents.json │ │ └── Perito.jpg │ ├── salinas.imageset │ │ ├── Contents.json │ │ └── WhatsApp Image 2024-02-09 at 13.05.21.jpeg │ ├── scientific.imageset │ │ ├── Contents.json │ │ └── WhatsApp Image 2024-02-09 at 13.07.02.jpeg │ ├── sunflower.imageset │ │ ├── Contents.json │ │ └── Sunflower.jpg │ └── underwater.imageset │ │ ├── Contents.json │ │ └── Underwater.jpg ├── ContentView.swift ├── Flode_VR.entitlements ├── Flode_VRApp.swift ├── ImageBasedLighting.skybox │ └── ImageBasedLight.exr ├── ImmersiveView.swift ├── Info.plist ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── SavedEnvironmentsView.swift ├── SettingsView.swift ├── SkyBoxControlsView.swift └── UserPreferences.swift ├── Flode_VRTests └── Flode_VRTests.swift ├── LICENSE ├── Packages └── RealityKitContent │ ├── .swiftpm │ └── xcode │ │ └── xcuserdata │ │ └── tadeo.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist │ ├── Package.realitycomposerpro │ ├── ProjectData │ │ └── main.json │ └── WorkspaceData │ │ ├── SceneMetadataList.json │ │ └── Settings.rcprojectdata │ ├── Package.swift │ ├── README.md │ └── Sources │ └── RealityKitContent │ ├── RealityKitContent.rkassets │ ├── Immersive.usda │ ├── Materials │ │ └── GridMaterial.usda │ └── Scene.usda │ └── RealityKitContent.swift ├── README.md └── video.mp4 /.gitignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | # Xcode 3 | # 4 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 5 | 6 | ## User settings 7 | xcuserdata/ 8 | 9 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 10 | *.xcscmblueprint 11 | *.xccheckout 12 | 13 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 14 | build/ 15 | DerivedData/ 16 | *.moved-aside 17 | *.pbxuser 18 | !default.pbxuser 19 | *.mode1v3 20 | !default.mode1v3 21 | *.mode2v3 22 | !default.mode2v3 23 | *.perspectivev3 24 | !default.perspectivev3 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | 29 | ## App packaging 30 | *.ipa 31 | *.dSYM.zip 32 | *.dSYM 33 | 34 | ## Playgrounds 35 | timeline.xctimeline 36 | playground.xcworkspace 37 | 38 | # Swift Package Manager 39 | # 40 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 41 | Packages/ 42 | Package.pins 43 | Package.resolved 44 | # *.xcodeproj 45 | # 46 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 47 | # hence it is not needed unless you have added a package configuration file to your project 48 | # .swiftpm 49 | 50 | .build/ 51 | 52 | # CocoaPods 53 | # 54 | # We recommend against adding the Pods directory to your .gitignore. However 55 | # you should judge for yourself, the pros and cons are mentioned at: 56 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 57 | # 58 | # Pods/ 59 | # 60 | # Add this line if you want to avoid checking in source code from the Xcode workspace 61 | # *.xcworkspace 62 | 63 | # Carthage 64 | # 65 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 66 | # Carthage/Checkouts 67 | 68 | Carthage/Build/ 69 | 70 | # Accio dependency management 71 | Dependencies/ 72 | .accio/ 73 | 74 | # fastlane 75 | # 76 | # It is recommended to not store the screenshots in the git repo. 77 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 78 | # For more information about the recommended setup visit: 79 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 80 | 81 | fastlane/report.xml 82 | fastlane/Preview.html 83 | fastlane/screenshots/**/*.png 84 | fastlane/test_output 85 | 86 | # Code Injection 87 | # 88 | # After new code Injection tools there's a generated folder /iOSInjectionProject 89 | # https://github.com/johnno1962/injectionforxcode 90 | 91 | iOSInjectionProject/ 92 | -------------------------------------------------------------------------------- /Audio/apikeyMissing.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flode-Labs/envi/12c8b263621b6c9a8c14b03359c6697b12ec15e3/Audio/apikeyMissing.mp3 -------------------------------------------------------------------------------- /Audio/enviromentCreating.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flode-Labs/envi/12c8b263621b6c9a8c14b03359c6697b12ec15e3/Audio/enviromentCreating.mp3 -------------------------------------------------------------------------------- /Audio/enviromentFailed.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flode-Labs/envi/12c8b263621b6c9a8c14b03359c6697b12ec15e3/Audio/enviromentFailed.mp3 -------------------------------------------------------------------------------- /Audio/promptMissing.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flode-Labs/envi/12c8b263621b6c9a8c14b03359c6697b12ec15e3/Audio/promptMissing.mp3 -------------------------------------------------------------------------------- /Audio/welcome.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flode-Labs/envi/12c8b263621b6c9a8c14b03359c6697b12ec15e3/Audio/welcome.mp3 -------------------------------------------------------------------------------- /Flode_VR.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 32D4D2C42CAB81E600C5FE03 /* UserPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32D4D2C32CAB81E600C5FE03 /* UserPreferences.swift */; }; 11 | 32D4D2C62CAB821200C5FE03 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32D4D2C52CAB821200C5FE03 /* SettingsView.swift */; }; 12 | 32D4D2C82CAB867C00C5FE03 /* SavedEnvironmentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32D4D2C72CAB867C00C5FE03 /* SavedEnvironmentsView.swift */; }; 13 | FD3551272B72F020004C820C /* RealityKitContent in Frameworks */ = {isa = PBXBuildFile; productRef = FD3551262B72F020004C820C /* RealityKitContent */; }; 14 | FD3551292B72F020004C820C /* Flode_VRApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3551282B72F020004C820C /* Flode_VRApp.swift */; }; 15 | FD35512B2B72F020004C820C /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD35512A2B72F020004C820C /* ContentView.swift */; }; 16 | FD35512D2B72F020004C820C /* ImmersiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD35512C2B72F020004C820C /* ImmersiveView.swift */; }; 17 | FD35512F2B72F020004C820C /* ImageBasedLighting.skybox in Resources */ = {isa = PBXBuildFile; fileRef = FD35512E2B72F020004C820C /* ImageBasedLighting.skybox */; }; 18 | FD3551312B72F021004C820C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FD3551302B72F021004C820C /* Assets.xcassets */; }; 19 | FD3551342B72F021004C820C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FD3551332B72F021004C820C /* Preview Assets.xcassets */; }; 20 | FD35513F2B72F021004C820C /* Flode_VRTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD35513E2B72F021004C820C /* Flode_VRTests.swift */; }; 21 | FD3551492B72F78F004C820C /* SkyBoxControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3551482B72F78F004C820C /* SkyBoxControlsView.swift */; }; 22 | FD54E3A12B755BEC00B19777 /* Replicate in Frameworks */ = {isa = PBXBuildFile; productRef = FD54E3A02B755BEC00B19777 /* Replicate */; }; 23 | FD90C5402B769A100005C69E /* video.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = FD90C53F2B769A100005C69E /* video.mp4 */; }; 24 | FDEAA67E2B75C12200F1A02A /* AssetSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDEAA67D2B75C12200F1A02A /* AssetSelectorView.swift */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | FD35513B2B72F021004C820C /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = FD3551192B72F020004C820C /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = FD3551202B72F020004C820C; 33 | remoteInfo = Flode_VR; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | 32D4D2C32CAB81E600C5FE03 /* UserPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreferences.swift; sourceTree = ""; }; 39 | 32D4D2C52CAB821200C5FE03 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 40 | 32D4D2C72CAB867C00C5FE03 /* SavedEnvironmentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavedEnvironmentsView.swift; sourceTree = ""; }; 41 | FD3551212B72F020004C820C /* Flode_VR.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Flode_VR.app; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | FD3551252B72F020004C820C /* RealityKitContent */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = RealityKitContent; sourceTree = ""; }; 43 | FD3551282B72F020004C820C /* Flode_VRApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Flode_VRApp.swift; sourceTree = ""; }; 44 | FD35512A2B72F020004C820C /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 45 | FD35512C2B72F020004C820C /* ImmersiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImmersiveView.swift; sourceTree = ""; }; 46 | FD35512E2B72F020004C820C /* ImageBasedLighting.skybox */ = {isa = PBXFileReference; lastKnownFileType = file.skybox; path = ImageBasedLighting.skybox; sourceTree = ""; }; 47 | FD3551302B72F021004C820C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 48 | FD3551332B72F021004C820C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 49 | FD3551352B72F021004C820C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | FD35513A2B72F021004C820C /* Flode_VRTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Flode_VRTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | FD35513E2B72F021004C820C /* Flode_VRTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Flode_VRTests.swift; sourceTree = ""; }; 52 | FD3551482B72F78F004C820C /* SkyBoxControlsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkyBoxControlsView.swift; sourceTree = ""; }; 53 | FD54E3A22B755D8C00B19777 /* Flode_VR.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Flode_VR.entitlements; sourceTree = ""; }; 54 | FD90C53F2B769A100005C69E /* video.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = video.mp4; sourceTree = ""; }; 55 | FDEAA67D2B75C12200F1A02A /* AssetSelectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetSelectorView.swift; sourceTree = ""; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | FD35511E2B72F020004C820C /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | FD54E3A12B755BEC00B19777 /* Replicate in Frameworks */, 64 | FD3551272B72F020004C820C /* RealityKitContent in Frameworks */, 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | FD3551372B72F021004C820C /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | /* End PBXFrameworksBuildPhase section */ 76 | 77 | /* Begin PBXGroup section */ 78 | FD3551182B72F020004C820C = { 79 | isa = PBXGroup; 80 | children = ( 81 | FD90C53F2B769A100005C69E /* video.mp4 */, 82 | FD3551232B72F020004C820C /* Flode_VR */, 83 | FD3551242B72F020004C820C /* Packages */, 84 | FD35513D2B72F021004C820C /* Flode_VRTests */, 85 | FD3551222B72F020004C820C /* Products */, 86 | ); 87 | sourceTree = ""; 88 | }; 89 | FD3551222B72F020004C820C /* Products */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | FD3551212B72F020004C820C /* Flode_VR.app */, 93 | FD35513A2B72F021004C820C /* Flode_VRTests.xctest */, 94 | ); 95 | name = Products; 96 | sourceTree = ""; 97 | }; 98 | FD3551232B72F020004C820C /* Flode_VR */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 32D4D2C72CAB867C00C5FE03 /* SavedEnvironmentsView.swift */, 102 | 32D4D2C52CAB821200C5FE03 /* SettingsView.swift */, 103 | 32D4D2C32CAB81E600C5FE03 /* UserPreferences.swift */, 104 | FD54E3A22B755D8C00B19777 /* Flode_VR.entitlements */, 105 | FD3551282B72F020004C820C /* Flode_VRApp.swift */, 106 | FD35512A2B72F020004C820C /* ContentView.swift */, 107 | FD35512C2B72F020004C820C /* ImmersiveView.swift */, 108 | FD3551482B72F78F004C820C /* SkyBoxControlsView.swift */, 109 | FDEAA67D2B75C12200F1A02A /* AssetSelectorView.swift */, 110 | FD35512E2B72F020004C820C /* ImageBasedLighting.skybox */, 111 | FD3551302B72F021004C820C /* Assets.xcassets */, 112 | FD3551352B72F021004C820C /* Info.plist */, 113 | FD3551322B72F021004C820C /* Preview Content */, 114 | ); 115 | path = Flode_VR; 116 | sourceTree = ""; 117 | }; 118 | FD3551242B72F020004C820C /* Packages */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | FD3551252B72F020004C820C /* RealityKitContent */, 122 | ); 123 | path = Packages; 124 | sourceTree = ""; 125 | }; 126 | FD3551322B72F021004C820C /* Preview Content */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | FD3551332B72F021004C820C /* Preview Assets.xcassets */, 130 | ); 131 | path = "Preview Content"; 132 | sourceTree = ""; 133 | }; 134 | FD35513D2B72F021004C820C /* Flode_VRTests */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | FD35513E2B72F021004C820C /* Flode_VRTests.swift */, 138 | ); 139 | path = Flode_VRTests; 140 | sourceTree = ""; 141 | }; 142 | /* End PBXGroup section */ 143 | 144 | /* Begin PBXNativeTarget section */ 145 | FD3551202B72F020004C820C /* Flode_VR */ = { 146 | isa = PBXNativeTarget; 147 | buildConfigurationList = FD3551422B72F021004C820C /* Build configuration list for PBXNativeTarget "Flode_VR" */; 148 | buildPhases = ( 149 | FD35511D2B72F020004C820C /* Sources */, 150 | FD35511E2B72F020004C820C /* Frameworks */, 151 | FD35511F2B72F020004C820C /* Resources */, 152 | ); 153 | buildRules = ( 154 | ); 155 | dependencies = ( 156 | ); 157 | name = Flode_VR; 158 | packageProductDependencies = ( 159 | FD3551262B72F020004C820C /* RealityKitContent */, 160 | FD54E3A02B755BEC00B19777 /* Replicate */, 161 | ); 162 | productName = Flode_VR; 163 | productReference = FD3551212B72F020004C820C /* Flode_VR.app */; 164 | productType = "com.apple.product-type.application"; 165 | }; 166 | FD3551392B72F021004C820C /* Flode_VRTests */ = { 167 | isa = PBXNativeTarget; 168 | buildConfigurationList = FD3551452B72F021004C820C /* Build configuration list for PBXNativeTarget "Flode_VRTests" */; 169 | buildPhases = ( 170 | FD3551362B72F021004C820C /* Sources */, 171 | FD3551372B72F021004C820C /* Frameworks */, 172 | FD3551382B72F021004C820C /* Resources */, 173 | ); 174 | buildRules = ( 175 | ); 176 | dependencies = ( 177 | FD35513C2B72F021004C820C /* PBXTargetDependency */, 178 | ); 179 | name = Flode_VRTests; 180 | productName = Flode_VRTests; 181 | productReference = FD35513A2B72F021004C820C /* Flode_VRTests.xctest */; 182 | productType = "com.apple.product-type.bundle.unit-test"; 183 | }; 184 | /* End PBXNativeTarget section */ 185 | 186 | /* Begin PBXProject section */ 187 | FD3551192B72F020004C820C /* Project object */ = { 188 | isa = PBXProject; 189 | attributes = { 190 | BuildIndependentTargetsInParallel = 1; 191 | LastSwiftUpdateCheck = 1520; 192 | LastUpgradeCheck = 1520; 193 | TargetAttributes = { 194 | FD3551202B72F020004C820C = { 195 | CreatedOnToolsVersion = 15.2; 196 | }; 197 | FD3551392B72F021004C820C = { 198 | CreatedOnToolsVersion = 15.2; 199 | TestTargetID = FD3551202B72F020004C820C; 200 | }; 201 | }; 202 | }; 203 | buildConfigurationList = FD35511C2B72F020004C820C /* Build configuration list for PBXProject "Flode_VR" */; 204 | compatibilityVersion = "Xcode 14.0"; 205 | developmentRegion = en; 206 | hasScannedForEncodings = 0; 207 | knownRegions = ( 208 | en, 209 | Base, 210 | ); 211 | mainGroup = FD3551182B72F020004C820C; 212 | packageReferences = ( 213 | FD54E39F2B755BEC00B19777 /* XCRemoteSwiftPackageReference "replicate-swift" */, 214 | ); 215 | productRefGroup = FD3551222B72F020004C820C /* Products */; 216 | projectDirPath = ""; 217 | projectRoot = ""; 218 | targets = ( 219 | FD3551202B72F020004C820C /* Flode_VR */, 220 | FD3551392B72F021004C820C /* Flode_VRTests */, 221 | ); 222 | }; 223 | /* End PBXProject section */ 224 | 225 | /* Begin PBXResourcesBuildPhase section */ 226 | FD35511F2B72F020004C820C /* Resources */ = { 227 | isa = PBXResourcesBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | FD3551312B72F021004C820C /* Assets.xcassets in Resources */, 231 | FD3551342B72F021004C820C /* Preview Assets.xcassets in Resources */, 232 | FD35512F2B72F020004C820C /* ImageBasedLighting.skybox in Resources */, 233 | FD90C5402B769A100005C69E /* video.mp4 in Resources */, 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | }; 237 | FD3551382B72F021004C820C /* Resources */ = { 238 | isa = PBXResourcesBuildPhase; 239 | buildActionMask = 2147483647; 240 | files = ( 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | /* End PBXResourcesBuildPhase section */ 245 | 246 | /* Begin PBXSourcesBuildPhase section */ 247 | FD35511D2B72F020004C820C /* Sources */ = { 248 | isa = PBXSourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | 32D4D2C62CAB821200C5FE03 /* SettingsView.swift in Sources */, 252 | FDEAA67E2B75C12200F1A02A /* AssetSelectorView.swift in Sources */, 253 | 32D4D2C42CAB81E600C5FE03 /* UserPreferences.swift in Sources */, 254 | FD35512B2B72F020004C820C /* ContentView.swift in Sources */, 255 | 32D4D2C82CAB867C00C5FE03 /* SavedEnvironmentsView.swift in Sources */, 256 | FD3551292B72F020004C820C /* Flode_VRApp.swift in Sources */, 257 | FD3551492B72F78F004C820C /* SkyBoxControlsView.swift in Sources */, 258 | FD35512D2B72F020004C820C /* ImmersiveView.swift in Sources */, 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | }; 262 | FD3551362B72F021004C820C /* Sources */ = { 263 | isa = PBXSourcesBuildPhase; 264 | buildActionMask = 2147483647; 265 | files = ( 266 | FD35513F2B72F021004C820C /* Flode_VRTests.swift in Sources */, 267 | ); 268 | runOnlyForDeploymentPostprocessing = 0; 269 | }; 270 | /* End PBXSourcesBuildPhase section */ 271 | 272 | /* Begin PBXTargetDependency section */ 273 | FD35513C2B72F021004C820C /* PBXTargetDependency */ = { 274 | isa = PBXTargetDependency; 275 | target = FD3551202B72F020004C820C /* Flode_VR */; 276 | targetProxy = FD35513B2B72F021004C820C /* PBXContainerItemProxy */; 277 | }; 278 | /* End PBXTargetDependency section */ 279 | 280 | /* Begin XCBuildConfiguration section */ 281 | FD3551402B72F021004C820C /* Debug */ = { 282 | isa = XCBuildConfiguration; 283 | buildSettings = { 284 | ALWAYS_SEARCH_USER_PATHS = NO; 285 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 286 | CLANG_ANALYZER_NONNULL = YES; 287 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 288 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 289 | CLANG_ENABLE_MODULES = YES; 290 | CLANG_ENABLE_OBJC_ARC = YES; 291 | CLANG_ENABLE_OBJC_WEAK = YES; 292 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 293 | CLANG_WARN_BOOL_CONVERSION = YES; 294 | CLANG_WARN_COMMA = YES; 295 | CLANG_WARN_CONSTANT_CONVERSION = YES; 296 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 297 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 298 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 299 | CLANG_WARN_EMPTY_BODY = YES; 300 | CLANG_WARN_ENUM_CONVERSION = YES; 301 | CLANG_WARN_INFINITE_RECURSION = YES; 302 | CLANG_WARN_INT_CONVERSION = YES; 303 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 304 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 305 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 306 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 307 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 308 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 309 | CLANG_WARN_STRICT_PROTOTYPES = YES; 310 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 311 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 312 | CLANG_WARN_UNREACHABLE_CODE = YES; 313 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 314 | COPY_PHASE_STRIP = NO; 315 | DEBUG_INFORMATION_FORMAT = dwarf; 316 | ENABLE_STRICT_OBJC_MSGSEND = YES; 317 | ENABLE_TESTABILITY = YES; 318 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 319 | GCC_C_LANGUAGE_STANDARD = gnu17; 320 | GCC_DYNAMIC_NO_PIC = NO; 321 | GCC_NO_COMMON_BLOCKS = YES; 322 | GCC_OPTIMIZATION_LEVEL = 0; 323 | GCC_PREPROCESSOR_DEFINITIONS = ( 324 | "DEBUG=1", 325 | "$(inherited)", 326 | ); 327 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 328 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 329 | GCC_WARN_UNDECLARED_SELECTOR = YES; 330 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 331 | GCC_WARN_UNUSED_FUNCTION = YES; 332 | GCC_WARN_UNUSED_VARIABLE = YES; 333 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 334 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 335 | MTL_FAST_MATH = YES; 336 | ONLY_ACTIVE_ARCH = YES; 337 | SDKROOT = xros; 338 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; 339 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 340 | XROS_DEPLOYMENT_TARGET = 1.0; 341 | }; 342 | name = Debug; 343 | }; 344 | FD3551412B72F021004C820C /* Release */ = { 345 | isa = XCBuildConfiguration; 346 | buildSettings = { 347 | ALWAYS_SEARCH_USER_PATHS = NO; 348 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 349 | CLANG_ANALYZER_NONNULL = YES; 350 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 351 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 352 | CLANG_ENABLE_MODULES = YES; 353 | CLANG_ENABLE_OBJC_ARC = YES; 354 | CLANG_ENABLE_OBJC_WEAK = YES; 355 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 356 | CLANG_WARN_BOOL_CONVERSION = YES; 357 | CLANG_WARN_COMMA = YES; 358 | CLANG_WARN_CONSTANT_CONVERSION = YES; 359 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 360 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 361 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 362 | CLANG_WARN_EMPTY_BODY = YES; 363 | CLANG_WARN_ENUM_CONVERSION = YES; 364 | CLANG_WARN_INFINITE_RECURSION = YES; 365 | CLANG_WARN_INT_CONVERSION = YES; 366 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 367 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 368 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 369 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 370 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 371 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 372 | CLANG_WARN_STRICT_PROTOTYPES = YES; 373 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 374 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 375 | CLANG_WARN_UNREACHABLE_CODE = YES; 376 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 377 | COPY_PHASE_STRIP = NO; 378 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 379 | ENABLE_NS_ASSERTIONS = NO; 380 | ENABLE_STRICT_OBJC_MSGSEND = YES; 381 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 382 | GCC_C_LANGUAGE_STANDARD = gnu17; 383 | GCC_NO_COMMON_BLOCKS = YES; 384 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 385 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 386 | GCC_WARN_UNDECLARED_SELECTOR = YES; 387 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 388 | GCC_WARN_UNUSED_FUNCTION = YES; 389 | GCC_WARN_UNUSED_VARIABLE = YES; 390 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 391 | MTL_ENABLE_DEBUG_INFO = NO; 392 | MTL_FAST_MATH = YES; 393 | SDKROOT = xros; 394 | SWIFT_COMPILATION_MODE = wholemodule; 395 | VALIDATE_PRODUCT = YES; 396 | XROS_DEPLOYMENT_TARGET = 1.0; 397 | }; 398 | name = Release; 399 | }; 400 | FD3551432B72F021004C820C /* Debug */ = { 401 | isa = XCBuildConfiguration; 402 | buildSettings = { 403 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 404 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 405 | CODE_SIGN_ENTITLEMENTS = Flode_VR/Flode_VR.entitlements; 406 | CODE_SIGN_STYLE = Automatic; 407 | CURRENT_PROJECT_VERSION = 1; 408 | DEVELOPMENT_ASSET_PATHS = "\"Flode_VR/Preview Content\""; 409 | DEVELOPMENT_TEAM = 48JKZFC7HJ; 410 | ENABLE_PREVIEWS = YES; 411 | GENERATE_INFOPLIST_FILE = YES; 412 | INFOPLIST_FILE = "$(TARGET_NAME)/Info.plist"; 413 | LD_RUNPATH_SEARCH_PATHS = ( 414 | "$(inherited)", 415 | "@executable_path/Frameworks", 416 | ); 417 | MARKETING_VERSION = 1.0; 418 | PRODUCT_BUNDLE_IDENTIFIER = "Flode.Flode-VR"; 419 | PRODUCT_NAME = "$(TARGET_NAME)"; 420 | SUPPORTED_PLATFORMS = "xros xrsimulator"; 421 | SWIFT_EMIT_LOC_STRINGS = YES; 422 | SWIFT_VERSION = 5.0; 423 | TARGETED_DEVICE_FAMILY = "1,2,7"; 424 | }; 425 | name = Debug; 426 | }; 427 | FD3551442B72F021004C820C /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 431 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 432 | CODE_SIGN_ENTITLEMENTS = Flode_VR/Flode_VR.entitlements; 433 | CODE_SIGN_STYLE = Automatic; 434 | CURRENT_PROJECT_VERSION = 1; 435 | DEVELOPMENT_ASSET_PATHS = "\"Flode_VR/Preview Content\""; 436 | DEVELOPMENT_TEAM = 48JKZFC7HJ; 437 | ENABLE_PREVIEWS = YES; 438 | GENERATE_INFOPLIST_FILE = YES; 439 | INFOPLIST_FILE = "$(TARGET_NAME)/Info.plist"; 440 | LD_RUNPATH_SEARCH_PATHS = ( 441 | "$(inherited)", 442 | "@executable_path/Frameworks", 443 | ); 444 | MARKETING_VERSION = 1.0; 445 | PRODUCT_BUNDLE_IDENTIFIER = "Flode.Flode-VR"; 446 | PRODUCT_NAME = "$(TARGET_NAME)"; 447 | SUPPORTED_PLATFORMS = "xros xrsimulator"; 448 | SWIFT_EMIT_LOC_STRINGS = YES; 449 | SWIFT_VERSION = 5.0; 450 | TARGETED_DEVICE_FAMILY = "1,2,7"; 451 | }; 452 | name = Release; 453 | }; 454 | FD3551462B72F021004C820C /* Debug */ = { 455 | isa = XCBuildConfiguration; 456 | buildSettings = { 457 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 458 | BUNDLE_LOADER = "$(TEST_HOST)"; 459 | CODE_SIGN_STYLE = Automatic; 460 | CURRENT_PROJECT_VERSION = 1; 461 | DEVELOPMENT_TEAM = 48JKZFC7HJ; 462 | GENERATE_INFOPLIST_FILE = YES; 463 | MARKETING_VERSION = 1.0; 464 | PRODUCT_BUNDLE_IDENTIFIER = "Flode.Flode-VRTests"; 465 | PRODUCT_NAME = "$(TARGET_NAME)"; 466 | SUPPORTED_PLATFORMS = "xros xrsimulator"; 467 | SWIFT_EMIT_LOC_STRINGS = NO; 468 | SWIFT_VERSION = 5.0; 469 | TARGETED_DEVICE_FAMILY = "1,2,7"; 470 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Flode_VR.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Flode_VR"; 471 | XROS_DEPLOYMENT_TARGET = 1.0; 472 | }; 473 | name = Debug; 474 | }; 475 | FD3551472B72F021004C820C /* Release */ = { 476 | isa = XCBuildConfiguration; 477 | buildSettings = { 478 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 479 | BUNDLE_LOADER = "$(TEST_HOST)"; 480 | CODE_SIGN_STYLE = Automatic; 481 | CURRENT_PROJECT_VERSION = 1; 482 | DEVELOPMENT_TEAM = 48JKZFC7HJ; 483 | GENERATE_INFOPLIST_FILE = YES; 484 | MARKETING_VERSION = 1.0; 485 | PRODUCT_BUNDLE_IDENTIFIER = "Flode.Flode-VRTests"; 486 | PRODUCT_NAME = "$(TARGET_NAME)"; 487 | SUPPORTED_PLATFORMS = "xros xrsimulator"; 488 | SWIFT_EMIT_LOC_STRINGS = NO; 489 | SWIFT_VERSION = 5.0; 490 | TARGETED_DEVICE_FAMILY = "1,2,7"; 491 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Flode_VR.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Flode_VR"; 492 | XROS_DEPLOYMENT_TARGET = 1.0; 493 | }; 494 | name = Release; 495 | }; 496 | /* End XCBuildConfiguration section */ 497 | 498 | /* Begin XCConfigurationList section */ 499 | FD35511C2B72F020004C820C /* Build configuration list for PBXProject "Flode_VR" */ = { 500 | isa = XCConfigurationList; 501 | buildConfigurations = ( 502 | FD3551402B72F021004C820C /* Debug */, 503 | FD3551412B72F021004C820C /* Release */, 504 | ); 505 | defaultConfigurationIsVisible = 0; 506 | defaultConfigurationName = Release; 507 | }; 508 | FD3551422B72F021004C820C /* Build configuration list for PBXNativeTarget "Flode_VR" */ = { 509 | isa = XCConfigurationList; 510 | buildConfigurations = ( 511 | FD3551432B72F021004C820C /* Debug */, 512 | FD3551442B72F021004C820C /* Release */, 513 | ); 514 | defaultConfigurationIsVisible = 0; 515 | defaultConfigurationName = Release; 516 | }; 517 | FD3551452B72F021004C820C /* Build configuration list for PBXNativeTarget "Flode_VRTests" */ = { 518 | isa = XCConfigurationList; 519 | buildConfigurations = ( 520 | FD3551462B72F021004C820C /* Debug */, 521 | FD3551472B72F021004C820C /* Release */, 522 | ); 523 | defaultConfigurationIsVisible = 0; 524 | defaultConfigurationName = Release; 525 | }; 526 | /* End XCConfigurationList section */ 527 | 528 | /* Begin XCRemoteSwiftPackageReference section */ 529 | FD54E39F2B755BEC00B19777 /* XCRemoteSwiftPackageReference "replicate-swift" */ = { 530 | isa = XCRemoteSwiftPackageReference; 531 | repositoryURL = "https://github.com/replicate/replicate-swift"; 532 | requirement = { 533 | kind = upToNextMajorVersion; 534 | minimumVersion = 0.20.0; 535 | }; 536 | }; 537 | /* End XCRemoteSwiftPackageReference section */ 538 | 539 | /* Begin XCSwiftPackageProductDependency section */ 540 | FD3551262B72F020004C820C /* RealityKitContent */ = { 541 | isa = XCSwiftPackageProductDependency; 542 | productName = RealityKitContent; 543 | }; 544 | FD54E3A02B755BEC00B19777 /* Replicate */ = { 545 | isa = XCSwiftPackageProductDependency; 546 | package = FD54E39F2B755BEC00B19777 /* XCRemoteSwiftPackageReference "replicate-swift" */; 547 | productName = Replicate; 548 | }; 549 | /* End XCSwiftPackageProductDependency section */ 550 | }; 551 | rootObject = FD3551192B72F020004C820C /* Project object */; 552 | } 553 | -------------------------------------------------------------------------------- /Flode_VR.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Flode_VR.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Flode_VR.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Flode_VR.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "replicate-swift", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/replicate/replicate-swift", 7 | "state" : { 8 | "revision" : "286ba0babc7c9db35f83d53832299c12a805580e", 9 | "version" : "0.20.0" 10 | } 11 | } 12 | ], 13 | "version" : 2 14 | } 15 | -------------------------------------------------------------------------------- /Flode_VR.xcodeproj/project.xcworkspace/xcuserdata/tadeo.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flode-Labs/envi/12c8b263621b6c9a8c14b03359c6697b12ec15e3/Flode_VR.xcodeproj/project.xcworkspace/xcuserdata/tadeo.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Flode_VR.xcodeproj/project.xcworkspace/xcuserdata/tadeo.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildLocationStyle 6 | UseAppPreferences 7 | CustomBuildLocationType 8 | RelativeToDerivedData 9 | DerivedDataLocationStyle 10 | Default 11 | ShowSharedSchemesAutomaticallyEnabled 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Flode_VR.xcodeproj/xcuserdata/tadeo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /Flode_VR.xcodeproj/xcuserdata/tadeo.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Flode_VR.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Flode_VR/AssetSelectorView.swift: -------------------------------------------------------------------------------- 1 | 2 | import SwiftUI 3 | 4 | struct AssetSelectorView: View { 5 | 6 | // To have access to the object passed to the view 7 | @EnvironmentObject var skyBoxSettings:SkyboxSettings 8 | 9 | var body: some View { 10 | VStack{ 11 | Text("Welcome to Envi 👋") 12 | .font(.largeTitle) 13 | .bold() 14 | Text("Think beyond your room") 15 | .font(.title3) 16 | 17 | AutoScroller(imageNames: ["anfield", "esteros", "iceland", "fitz", "salinas", "scientific", "airplane", "colon"]) 18 | .padding(.top, 20) 19 | 20 | Text("By Flode Labs") 21 | .font(.footnote) 22 | .underline() 23 | .padding(.top, 50) 24 | } 25 | .padding(.top, -40) 26 | } 27 | } 28 | 29 | #Preview { 30 | SkyBoxControlsView() 31 | } 32 | 33 | struct SkyBoxButton: View { 34 | var onClick: () -> Void 35 | var iconName: String 36 | var title: String 37 | 38 | var body: some View { 39 | Button(action: onClick, label: { 40 | Image(systemName: iconName) 41 | .font(.largeTitle) 42 | Text(title) // Using short title 43 | .font(.caption) 44 | }) 45 | } 46 | } 47 | 48 | struct AutoScroller: View { 49 | var imageNames: [String] 50 | let timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect() 51 | 52 | @State private var selectedImageIndex: Int = 0 53 | @EnvironmentObject var skyBoxSettings:SkyboxSettings 54 | 55 | var body: some View { 56 | VStack{ 57 | Text("Choose an example below to discover new places ✨") 58 | ZStack { 59 | TabView(selection: $selectedImageIndex) { 60 | ForEach(0.. 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Flode_VR/Flode_VRApp.swift: -------------------------------------------------------------------------------- 1 | 2 | import SwiftUI 3 | 4 | @main 5 | struct Flode_VRApp: App { 6 | @ObservedObject var skyBoxSettings = SkyboxSettings() 7 | 8 | var body: some Scene { 9 | // VR 10 | ImmersiveSpace(id: "ImmersiveSpace") { 11 | ImmersiveView() 12 | .environmentObject(skyBoxSettings) 13 | }.immersionStyle(selection: .constant(.full), in: .full) 14 | 15 | // Window 16 | WindowGroup(id: "SkyBoxControls"){ 17 | TabView { 18 | AssetSelectorView() 19 | .environmentObject(skyBoxSettings) 20 | .tabItem { 21 | Label("Spaces", systemImage: "table.fill") 22 | } 23 | SkyBoxControlsView() 24 | .environmentObject(skyBoxSettings) 25 | .tabItem { 26 | Label("Generative AI", systemImage: "wand.and.stars.inverse") 27 | } 28 | SettingsView() 29 | .environmentObject(skyBoxSettings) 30 | .tabItem { 31 | Label("Settings", systemImage: "gearshape.fill") 32 | } 33 | SavedEnvironmentsView() 34 | .environmentObject(skyBoxSettings) 35 | .tabItem { 36 | Label("Saved", systemImage: "folder.fill") 37 | } 38 | } 39 | } 40 | .defaultSize(width: 1000, height: 500) 41 | } 42 | } 43 | 44 | class SkyboxSettings: ObservableObject { 45 | @Published var currentSkybox = "esteros" 46 | @Published var loading = false 47 | @Published var openAIAPIKey: String = "" 48 | @Published var replicateAPIKey: String = "" 49 | @Published var userPreferences = UserPreferences() 50 | @Published var savedEnvironments: [String] = [] 51 | } 52 | 53 | -------------------------------------------------------------------------------- /Flode_VR/ImageBasedLighting.skybox/ImageBasedLight.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flode-Labs/envi/12c8b263621b6c9a8c14b03359c6697b12ec15e3/Flode_VR/ImageBasedLighting.skybox/ImageBasedLight.exr -------------------------------------------------------------------------------- /Flode_VR/ImmersiveView.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import SwiftUI 4 | import RealityKit 5 | import RealityKitContent 6 | import AVFoundation 7 | 8 | struct ImmersiveView: View { 9 | 10 | @Environment(\.openWindow) var openWindow 11 | @EnvironmentObject var skyBoxSettings: SkyboxSettings 12 | 13 | var body: some View { 14 | RealityView { content in 15 | guard let skyBoxEntity = createSkybox() else { 16 | return 17 | } 18 | content.add(skyBoxEntity) 19 | } update: { content in 20 | if !skyBoxSettings.loading { 21 | if skyBoxSettings.currentSkybox.contains("http") || skyBoxSettings.currentSkybox.contains("file://") { 22 | updateSkyboxURL(with: skyBoxSettings.currentSkybox, content: content) 23 | } else { 24 | updateSkybox(with: skyBoxSettings.currentSkybox, content: content) 25 | } 26 | } else { 27 | updateVideoSkybox(content: content) 28 | } 29 | } 30 | .onAppear { 31 | openWindow(id: "SkyBoxControls") 32 | } 33 | } 34 | 35 | private func createSkybox() -> Entity? { 36 | let skyBoxMesh = MeshResource.generateSphere(radius: 1000) 37 | var skyBoxMaterial = UnlitMaterial() 38 | guard let skyBoxTexture = try? TextureResource.load(named: skyBoxSettings.currentSkybox) else { return nil } 39 | skyBoxMaterial.color = .init(texture: .init(skyBoxTexture)) 40 | let skyBoxEntity = Entity() 41 | skyBoxEntity.components.set(ModelComponent( 42 | mesh: skyBoxMesh, 43 | materials: [skyBoxMaterial] 44 | )) 45 | skyBoxEntity.name = "SkyBox" 46 | skyBoxEntity.scale = .init(x: -1, y: 1, z: 1) 47 | skyBoxEntity.orientation = simd_quatf(angle: .pi/2, axis: [0, 1, 0]) 48 | return skyBoxEntity 49 | } 50 | 51 | private func updateSkybox(with newSkyBoxName: String, content: RealityViewContent) { 52 | let skyBoxEntity = content.entities.first { entity in 53 | entity.name == "SkyBox" 54 | } 55 | 56 | guard let updatedSkyBoxTexture = try? TextureResource.load(named: newSkyBoxName) else { 57 | return 58 | } 59 | 60 | var updatedSkyBoxMaterial = UnlitMaterial() 61 | updatedSkyBoxMaterial.color = .init(texture: .init(updatedSkyBoxTexture)) 62 | 63 | skyBoxEntity?.components.set( 64 | ModelComponent( 65 | mesh: MeshResource.generateSphere(radius: 1000), 66 | materials: [updatedSkyBoxMaterial] 67 | ) 68 | ) 69 | } 70 | 71 | private func updateSkyboxURL(with newSkyBoxName: String, content: RealityViewContent) { 72 | let skyBoxEntity = content.entities.first { entity in 73 | entity.name == "SkyBox" 74 | } 75 | 76 | var skyBoxTexture: TextureResource? 77 | 78 | if newSkyBoxName.hasPrefix("http") { 79 | let remoteURL = URL(string: newSkyBoxName)! 80 | let fileURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) 81 | let data = try! Data(contentsOf: remoteURL) 82 | try! data.write(to: fileURL) 83 | skyBoxTexture = try? TextureResource.load(contentsOf: fileURL) 84 | } else if newSkyBoxName.hasPrefix("file://") { 85 | let fileURL = URL(string: newSkyBoxName)! 86 | skyBoxTexture = try? TextureResource.load(contentsOf: fileURL) 87 | } else { 88 | let fileURL = URL(fileURLWithPath: newSkyBoxName) 89 | skyBoxTexture = try? TextureResource.load(contentsOf: fileURL) 90 | } 91 | 92 | guard let updatedSkyBoxTexture = skyBoxTexture else { 93 | return 94 | } 95 | 96 | var updatedSkyBoxMaterial = UnlitMaterial() 97 | updatedSkyBoxMaterial.color = .init(texture: .init(updatedSkyBoxTexture)) 98 | 99 | skyBoxEntity?.components.set( 100 | ModelComponent( 101 | mesh: MeshResource.generateSphere(radius: 1000), 102 | materials: [updatedSkyBoxMaterial] 103 | ) 104 | ) 105 | } 106 | 107 | private func updateVideoSkybox(content: RealityViewContent) { 108 | let skyBoxEntity = content.entities.first { entity in 109 | entity.name == "SkyBox" 110 | } 111 | 112 | guard let videoMaterial = createVideoMaterial() else { 113 | return 114 | } 115 | 116 | skyBoxEntity?.components.set( 117 | ModelComponent( 118 | mesh: MeshResource.generateSphere(radius: 1000), 119 | materials: [videoMaterial] 120 | ) 121 | ) 122 | } 123 | 124 | private func createVideoMaterial() -> VideoMaterial? { 125 | guard let videoURL = Bundle.main.url(forResource: "video", withExtension: "mp4") else { 126 | return nil 127 | } 128 | let avPlayer = AVPlayer(url: videoURL) 129 | let videoMaterial = VideoMaterial(avPlayer: avPlayer) 130 | avPlayer.play() 131 | return videoMaterial 132 | } 133 | } 134 | 135 | // Preview Provider 136 | struct ImmersiveView_Previews: PreviewProvider { 137 | static var previews: some View { 138 | ImmersiveView() 139 | .environmentObject(SkyboxSettings()) 140 | .previewLayout(.sizeThatFits) 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Flode_VR/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationPreferredDefaultSceneSessionRole 8 | UISceneSessionRoleImmersiveSpaceApplication 9 | UIApplicationSupportsMultipleScenes 10 | 11 | UISceneConfigurations 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Flode_VR/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Flode_VR/SavedEnvironmentsView.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import SwiftUI 4 | 5 | struct SavedEnvironmentsView: View { 6 | @EnvironmentObject var skyBoxSettings: SkyboxSettings 7 | 8 | var body: some View { 9 | NavigationView { 10 | List { 11 | ForEach(skyBoxSettings.savedEnvironments, id: \.self) { path in 12 | HStack { 13 | Text(URL(fileURLWithPath: path).lastPathComponent) 14 | Spacer() 15 | Button("Load") { 16 | skyBoxSettings.currentSkybox = path 17 | } 18 | } 19 | } 20 | .onDelete(perform: delete) 21 | } 22 | .navigationTitle("Saved Environments") 23 | .toolbar { 24 | EditButton() 25 | } 26 | } 27 | } 28 | 29 | func delete(at offsets: IndexSet) { 30 | skyBoxSettings.savedEnvironments.remove(atOffsets: offsets) 31 | } 32 | } 33 | 34 | // Preview Provider 35 | struct SavedEnvironmentsView_Previews: PreviewProvider { 36 | static var previews: some View { 37 | SavedEnvironmentsView() 38 | .environmentObject(SkyboxSettings()) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Flode_VR/SettingsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingsView.swift 3 | // Flode_VR 4 | // 5 | // 6 | 7 | import SwiftUI 8 | 9 | struct SettingsView: View { 10 | @EnvironmentObject var skyBoxSettings: SkyboxSettings 11 | @State private var showOpenAIKey: Bool = false 12 | @State private var showReplicateKey: Bool = false 13 | 14 | let styles = [ 15 | (name: "Animated", imageName: "animated"), 16 | (name: "Cartoon", imageName: "cartoon"), 17 | (name: "Realistic", imageName: "realistic"), 18 | (name: "Abstract", imageName: "abstract") 19 | ] 20 | 21 | let avoidOptions = [ 22 | (name: "Scary Things", imageName: "scary"), 23 | (name: "Monsters", imageName: "monster"), 24 | (name: "Persons", imageName: "persons"), 25 | (name: "Violence", imageName: "violence") 26 | ] 27 | 28 | var body: some View { 29 | VStack { 30 | Text("Settings").font(.largeTitle) 31 | Form { 32 | Section(header: Text("API Keys")) { 33 | HStack { 34 | if showOpenAIKey { 35 | TextField("OpenAI API Key", text: $skyBoxSettings.openAIAPIKey) 36 | } else { 37 | SecureField("OpenAI API Key", text: $skyBoxSettings.openAIAPIKey) 38 | } 39 | Button(action: { 40 | showOpenAIKey.toggle() 41 | }) { 42 | Image(systemName: showOpenAIKey ? "eye.slash" : "eye") 43 | } 44 | } 45 | HStack { 46 | if showReplicateKey { 47 | TextField("Replicate API Key", text: $skyBoxSettings.replicateAPIKey) 48 | } else { 49 | SecureField("Replicate API Key", text: $skyBoxSettings.replicateAPIKey) 50 | } 51 | Button(action: { 52 | showReplicateKey.toggle() 53 | }) { 54 | Image(systemName: showReplicateKey ? "eye.slash" : "eye") 55 | } 56 | } 57 | } 58 | Section(header: Text("Preferences")) { 59 | Toggle(isOn: $skyBoxSettings.userPreferences.improvePrompt) { 60 | Text("Improve Prompt") 61 | } 62 | .disabled(skyBoxSettings.openAIAPIKey.isEmpty) // Disable if OpenAI API key is not provided 63 | 64 | Text("Select a style you prefer:") 65 | ScrollView(.horizontal) { 66 | HStack { 67 | ForEach(styles, id: \.name) { style in 68 | VStack { 69 | Image(style.imageName) 70 | .resizable() 71 | .frame(width: 100, height: 100) 72 | .border(skyBoxSettings.userPreferences.style == style.name ? Color.blue : Color.clear, width: 2) 73 | .onTapGesture { 74 | skyBoxSettings.userPreferences.style = style.name 75 | } 76 | Text(style.name) 77 | } 78 | } 79 | } 80 | } 81 | Text("Select things you want to avoid:") 82 | ScrollView(.horizontal) { 83 | HStack { 84 | ForEach(avoidOptions, id: \.name) { option in 85 | VStack { 86 | Image(option.imageName) 87 | .resizable() 88 | .frame(width: 100, height: 100) 89 | .border(skyBoxSettings.userPreferences.avoid.contains(option.name) ? Color.red : Color.clear, width: 2) 90 | .onTapGesture { 91 | if skyBoxSettings.userPreferences.avoid.contains(option.name) { 92 | skyBoxSettings.userPreferences.avoid.removeAll { $0 == option.name } 93 | } else { 94 | skyBoxSettings.userPreferences.avoid.append(option.name) 95 | } 96 | } 97 | Text(option.name) 98 | } 99 | } 100 | } 101 | } 102 | } 103 | } 104 | .padding() 105 | } 106 | } 107 | } 108 | 109 | // Preview Provider 110 | struct SettingsView_Previews: PreviewProvider { 111 | static var previews: some View { 112 | SettingsView() 113 | .environmentObject(SkyboxSettings()) 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Flode_VR/SkyBoxControlsView.swift: -------------------------------------------------------------------------------- 1 | 2 | import SwiftUI 3 | import Replicate 4 | import Foundation 5 | import AVFoundation 6 | 7 | struct SkyBoxControlsView: View { 8 | @EnvironmentObject var skyBoxSettings: SkyboxSettings 9 | @State private var prompt: String = "" 10 | @State private var isToolbarVisible: Bool = true 11 | @State private var isSubmitting: Bool = false 12 | 13 | // Audio players 14 | private var promptMissingPlayer: AVAudioPlayer? 15 | private var apiKeyMissingPlayer: AVAudioPlayer? 16 | private var welcomePlayer: AVAudioPlayer? 17 | private var generatingPlayer: AVAudioPlayer? 18 | private var generationFailedPlayer: AVAudioPlayer? 19 | 20 | // Replicate client 21 | private var replicate: Replicate.Client { 22 | Replicate.Client(token: skyBoxSettings.replicateAPIKey.isEmpty ? "API" : skyBoxSettings.replicateAPIKey) 23 | } 24 | 25 | init() { 26 | // Initialize the audio players 27 | promptMissingPlayer = loadAudioPlayer(fileName: "promptMissing") 28 | apiKeyMissingPlayer = loadAudioPlayer(fileName: "apikeyMissing") 29 | welcomePlayer = loadAudioPlayer(fileName: "welcome") 30 | generatingPlayer = loadAudioPlayer(fileName: "environmentCreating") 31 | generationFailedPlayer = loadAudioPlayer(fileName: "environmentFailed") 32 | } 33 | 34 | let columns = [ 35 | GridItem(.adaptive(minimum: 150)) 36 | ] 37 | 38 | // Adjusting structure for short titles and detailed prompts 39 | let templatePrompts: [String: (title: String, detailedPrompt: String)] = [ 40 | "sunrise.fill": ("Sunrise", "Sunrise over mountains"), 41 | "sunset.fill": ("Sunset", "Beautiful sunset by the beach"), 42 | "sparkles": ("Stars", "Starry night sky"), 43 | "tree.fill": ("Forest", "Misty forest at dawn"), 44 | "building.2.fill": ("City", "Futuristic cityscape at night"), 45 | "mountain.2.fill": ("Mountains", "Snowy mountains under clear blue sky"), 46 | "hurricane": ("Anime", "Tokyo city street anime style"), 47 | "sparkle": ("Galaxy", "Galaxy"), 48 | "book.fill": ("Fantasy", "Fantasy forest of elf"), 49 | "tornado.circle.fill": ("Desert", "Desert"), 50 | ] 51 | 52 | var body: some View { 53 | VStack { 54 | Text("Generate a new environment using AI").font(.largeTitle) 55 | 56 | Text("Examples").font(.largeTitle) 57 | LazyVGrid(columns: columns, spacing: 20) { 58 | ForEach(Array(templatePrompts.keys), id: \.self) { key in 59 | let item = templatePrompts[key]! 60 | Button(action: { 61 | self.prompt = item.detailedPrompt 62 | }) { 63 | VStack { 64 | Image(systemName: key) 65 | .font(.largeTitle) 66 | Text(item.title) 67 | .font(.caption) 68 | } 69 | } 70 | .disabled(isSubmitting) 71 | } 72 | } 73 | .padding(.horizontal, 50) 74 | .toolbar { 75 | if isToolbarVisible { 76 | ToolbarItem(placement: .bottomOrnament) { 77 | HStack { 78 | TextField("Enter the prompt for the environment", text: $prompt) 79 | .textFieldStyle(RoundedBorderTextFieldStyle()) 80 | .disabled(isSubmitting) 81 | 82 | Button(action: { 83 | if prompt.isEmpty { 84 | playAudio(audioPlayer: promptMissingPlayer) 85 | return 86 | } else if skyBoxSettings.replicateAPIKey.isEmpty { 87 | playAudio(audioPlayer: apiKeyMissingPlayer) 88 | return 89 | } 90 | 91 | Task { 92 | await callApiAndUpdateSkybox(with: prompt) 93 | } 94 | }) { 95 | Image(systemName: "paperplane.fill") 96 | .foregroundColor(.white) 97 | .padding(8) 98 | .background(Color.blue) 99 | .clipShape(Circle()) 100 | } 101 | } 102 | .frame(maxWidth: .infinity) 103 | } 104 | } 105 | } 106 | .onAppear { 107 | isToolbarVisible = true 108 | if skyBoxSettings.replicateAPIKey.isEmpty { 109 | playAudio(audioPlayer: welcomePlayer) 110 | } 111 | } 112 | .onDisappear { 113 | isToolbarVisible = false 114 | } 115 | } 116 | } 117 | 118 | func loadAudioPlayer(fileName: String) -> AVAudioPlayer? { 119 | guard let url = Bundle.main.url(forResource: fileName, withExtension: "mp3") else { return nil } 120 | return try? AVAudioPlayer(contentsOf: url) 121 | } 122 | 123 | func playAudio(audioPlayer: AVAudioPlayer?) { 124 | [promptMissingPlayer, apiKeyMissingPlayer, welcomePlayer, generatingPlayer, generationFailedPlayer].forEach { player in 125 | if player !== audioPlayer { 126 | player?.stop() 127 | } 128 | } 129 | audioPlayer?.stop() 130 | audioPlayer?.currentTime = 0 131 | audioPlayer?.play() 132 | } 133 | 134 | // Calls the API and returns the generated image 135 | func callApiAndUpdateSkybox(with input: String) async { 136 | playAudio(audioPlayer: generatingPlayer) 137 | 138 | self.isSubmitting = true 139 | defer { self.isSubmitting = false } 140 | 141 | do { 142 | self.skyBoxSettings.loading = true 143 | 144 | var promptToUse = input 145 | 146 | if skyBoxSettings.userPreferences.improvePrompt && !skyBoxSettings.openAIAPIKey.isEmpty { 147 | // Improve the prompt using OpenAI 148 | promptToUse = try await improvePromptWithPreferences( 149 | prompt: input, 150 | userPreferences: skyBoxSettings.userPreferences, 151 | apiKey: skyBoxSettings.openAIAPIKey 152 | ) 153 | } else if skyBoxSettings.userPreferences.improvePrompt && skyBoxSettings.openAIAPIKey.isEmpty { 154 | // Play audio if OpenAI API key is missing 155 | playAudio(audioPlayer: apiKeyMissingPlayer) 156 | self.skyBoxSettings.userPreferences.improvePrompt = false 157 | } 158 | 159 | // First model: igorriti/flux-360 160 | let flux360Model = try await replicate.getModel("igorriti/flux-360") 161 | if let flux360Version = flux360Model.latestVersion { 162 | let flux360Prediction = try await replicate.createPrediction( 163 | version: flux360Version.id, 164 | input: [ 165 | "model": "dev", 166 | "prompt": "\(promptToUse)", 167 | "lora_scale": 1, 168 | "num_outputs": 1, 169 | "aspect_ratio": "3:2", 170 | "output_format": "png", 171 | "guidance_scale": 3.5, 172 | "output_quality": 80, 173 | "prompt_strength": 0.8, 174 | "extra_lora_scale": 0.8, 175 | "num_inference_steps": 28 176 | ], 177 | wait: true 178 | ) 179 | 180 | // Print the result to the console 181 | print(flux360Prediction) 182 | // Corrected the output handling 183 | guard let fluxOutputArray = flux360Prediction.output?.arrayValue, 184 | let fluxImageUrlString = fluxOutputArray.first?.stringValue, 185 | let fluxImageUrl = URL(string: fluxImageUrlString) else { 186 | throw NSError(domain: "ImageGeneration", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to generate image"]) 187 | } 188 | 189 | // Process image (swap halves) 190 | let processedImageData = try await processImage(from: fluxImageUrl) 191 | 192 | // Load mask image from app assets 193 | guard let maskImageData = loadMaskImageFromAssets("mask") else { 194 | throw NSError(domain: "ImageProcessing", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to load mask image"]) 195 | } 196 | 197 | // Second model: vetkastar/fooocus (inpainting) 198 | let fooocusModel = try await replicate.getModel("vetkastar/fooocus") 199 | if let fooocusVersion = fooocusModel.latestVersion { 200 | let fooocusPrediction = try await replicate.createPrediction( 201 | version: fooocusVersion.id, 202 | input: [ 203 | "prompt": "\(promptToUse)", 204 | "inpaint_additional_prompt": "\(promptToUse)", 205 | "inpaint_input_image": "data:image/png;base64,\(processedImageData.base64EncodedString())", 206 | "inpaint_input_mask": "data:image/png;base64,\(maskImageData.base64EncodedString())", 207 | "inpaint_strength": 1 208 | ], 209 | wait: true 210 | ) 211 | 212 | // Extract the image URL from the output dictionary 213 | if let outputDict = fooocusPrediction.output?.objectValue, 214 | let pathsValue = outputDict["paths"], 215 | let pathsArray = pathsValue.arrayValue, 216 | let inpaintedImageUrlString = pathsArray.first?.stringValue, 217 | let inpaintedImageUrl = URL(string: inpaintedImageUrlString) { 218 | 219 | // Third model: nightmareai/real-esrgan (upscaling) 220 | let esrganModel = try await replicate.getModel("nightmareai/real-esrgan") 221 | if let esrganVersion = esrganModel.latestVersion { 222 | let esrganPrediction = try await replicate.createPrediction( 223 | version: esrganVersion.id, 224 | input: [ 225 | "image": "\(inpaintedImageUrl.absoluteString)", 226 | "scale": 2, 227 | "face_enhance": false 228 | ], 229 | wait: true 230 | ) 231 | 232 | // Corrected the output handling 233 | guard let finalImageUrlString = esrganPrediction.output?.stringValue, 234 | let finalImageUrl = URL(string: finalImageUrlString) else { 235 | throw NSError(domain: "ImageGeneration", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to upscale image"]) 236 | } 237 | 238 | // Update the skybox with the final image 239 | self.skyBoxSettings.currentSkybox = finalImageUrl.absoluteString 240 | 241 | // Save the environment locally 242 | try await saveEnvironmentImage(from: finalImageUrl) 243 | } 244 | } else { 245 | throw NSError(domain: "ImageGeneration", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to extract inpainted image URL"]) 246 | } 247 | } 248 | } 249 | 250 | } catch { 251 | print("Error during prediction: \(error)") 252 | playAudio(audioPlayer: generationFailedPlayer) 253 | } 254 | self.skyBoxSettings.loading = false 255 | } 256 | 257 | func improvePromptWithPreferences(prompt: String, userPreferences: UserPreferences, apiKey: String) async throws -> String { 258 | let url = URL(string: "https://api.openai.com/v1/chat/completions")! 259 | var request = URLRequest(url: url) 260 | request.httpMethod = "POST" 261 | request.addValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization") 262 | request.addValue("application/json", forHTTPHeaderField: "Content-Type") 263 | 264 | let systemPrompt = """ 265 | You are an AI assistant that improves image generation prompts. Try not to include a lot of details; it should be concise and not talk about feelings. You cannot use words like "Landscape". 266 | The user has the following preferences: 267 | Style: \(userPreferences.style) 268 | Things to avoid: \(userPreferences.avoid.joined(separator: ", ")) 269 | Enhance the given prompt to reflect these preferences without changing its core meaning. 270 | """ 271 | 272 | let body: [String: Any] = [ 273 | "model": "gpt-3.5-turbo", 274 | "messages": [ 275 | ["role": "system", "content": systemPrompt], 276 | ["role": "user", "content": "Improve this prompt: \(prompt)"] 277 | ], 278 | "max_tokens": 50, 279 | "temperature": 0.7 280 | ] 281 | 282 | request.httpBody = try JSONSerialization.data(withJSONObject: body, options: []) 283 | 284 | let (data, response) = try await URLSession.shared.data(for: request) 285 | 286 | guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { 287 | let errorResponse = String(data: data, encoding: .utf8) ?? "Unknown error" 288 | throw NSError(domain: "OpenAI", code: 0, userInfo: [NSLocalizedDescriptionKey: errorResponse]) 289 | } 290 | 291 | let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] 292 | if let choices = json?["choices"] as? [[String: Any]], 293 | let message = choices.first?["message"] as? [String: Any], 294 | let content = message["content"] as? String { 295 | return content 296 | } else { 297 | throw NSError(domain: "OpenAI", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid response"]) 298 | } 299 | } 300 | 301 | func processImage(from url: URL) async throws -> Data { 302 | // Implement image processing (swap halves) 303 | let (data, _) = try await URLSession.shared.data(from: url) 304 | // Swap the halves of the image 305 | guard let image = UIImage(data: data) else { 306 | throw NSError(domain: "ImageProcessing", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to load image"]) 307 | } 308 | 309 | let size = image.size 310 | let width = Int(size.width) 311 | let height = Int(size.height) 312 | let halfWidth = width / 2 313 | 314 | UIGraphicsBeginImageContext(size) 315 | guard let context = UIGraphicsGetCurrentContext() else { 316 | UIGraphicsEndImageContext() 317 | throw NSError(domain: "ImageProcessing", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create graphics context"]) 318 | } 319 | 320 | // Flip the context vertically 321 | context.translateBy(x: 0, y: size.height) 322 | context.scaleBy(x: 1.0, y: -1.0) 323 | 324 | // Left half 325 | let leftRect = CGRect(x: 0, y: 0, width: CGFloat(halfWidth), height: size.height) 326 | // Right half 327 | let rightRect = CGRect(x: CGFloat(halfWidth), y: 0, width: size.width - CGFloat(halfWidth), height: size.height) 328 | 329 | // Draw right half on the left 330 | if let rightHalf = image.cgImage?.cropping(to: CGRect(x: halfWidth, y: 0, width: width - halfWidth, height: height)) { 331 | context.draw(rightHalf, in: leftRect) 332 | } 333 | 334 | // Draw left half on the right 335 | if let leftHalf = image.cgImage?.cropping(to: CGRect(x: 0, y: 0, width: halfWidth, height: height)) { 336 | context.draw(leftHalf, in: rightRect) 337 | } 338 | 339 | guard let swappedImage = UIGraphicsGetImageFromCurrentImageContext() else { 340 | UIGraphicsEndImageContext() 341 | throw NSError(domain: "ImageProcessing", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create swapped image"]) 342 | } 343 | 344 | UIGraphicsEndImageContext() 345 | 346 | guard let swappedImageData = swappedImage.pngData() else { 347 | throw NSError(domain: "ImageProcessing", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to convert image to data"]) 348 | } 349 | 350 | return swappedImageData 351 | } 352 | 353 | func loadMaskImageFromAssets(_ imageName: String) -> Data? { 354 | if let image = UIImage(named: imageName) { 355 | return image.pngData() 356 | } 357 | return nil 358 | } 359 | 360 | func saveEnvironmentImage(from url: URL) async throws { 361 | let (data, response) = try await URLSession.shared.data(from: url) 362 | guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { 363 | throw NSError(domain: "DownloadError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to download image"]) 364 | } 365 | 366 | let filename = UUID().uuidString + ".png" 367 | let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! 368 | let fileURL = documentsURL.appendingPathComponent(filename) 369 | 370 | try data.write(to: fileURL) 371 | 372 | DispatchQueue.main.async { 373 | self.skyBoxSettings.savedEnvironments.append(fileURL.path) 374 | } 375 | } 376 | } 377 | 378 | // Preview Provider 379 | struct SkyBoxControlsView_Previews: PreviewProvider { 380 | static var previews: some View { 381 | SkyBoxControlsView().environmentObject(SkyboxSettings()) 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /Flode_VR/UserPreferences.swift: -------------------------------------------------------------------------------- 1 | 2 | import SwiftUI 3 | 4 | class UserPreferences: ObservableObject { 5 | @Published var style: String = "" 6 | @Published var avoid: [String] = [] 7 | @Published var improvePrompt: Bool = true 8 | } 9 | -------------------------------------------------------------------------------- /Flode_VRTests/Flode_VRTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Flode_VRTests.swift 3 | // Flode_VRTests 4 | // 5 | // Created by Tadeo Donegana Braunschweig on 06/02/2024. 6 | // 7 | 8 | import XCTest 9 | @testable import Flode_VR 10 | 11 | class Flode_VRTests: XCTestCase { 12 | 13 | override func setUpWithError() throws { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | } 16 | 17 | override func tearDownWithError() throws { 18 | // Put teardown code here. This method is called after the invocation of each test method in the class. 19 | } 20 | 21 | func testExample() throws { 22 | // This is an example of a functional test case. 23 | // Use XCTAssert and related functions to verify your tests produce the correct results. 24 | // Any test you write for XCTest can be annotated as throws and async. 25 | // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. 26 | // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. 27 | } 28 | 29 | func testPerformanceExample() throws { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Flode Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Packages/RealityKitContent/.swiftpm/xcode/xcuserdata/tadeo.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | RealityKitContent.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 1 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Packages/RealityKitContent/Package.realitycomposerpro/ProjectData/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "pathsToIds" : { 3 | "\/RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/GridMaterial.usda" : "CB766F92-EE55-4A63-9401-E7B8C009764D", 4 | "\/RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/Immersive.usda" : "65F6F990-A780-4474-B78B-572E0E4E273D", 5 | "\/RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/Scene.usda" : "0A9B4653-B11E-4D6A-850E-C6FCB621626C", 6 | "\/RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/Untitled Scene.usda" : "D560BB77-AAF3-4BDE-B7C4-989332A4688B", 7 | "RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/GridMaterial.usda" : "66168B71-AB05-424E-8B6C-D33D6E61B08F", 8 | "RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/Immersive.usda" : "AF09ED6F-1707-48FD-8720-65B998362C09", 9 | "RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/Scene.usda" : "D66134B1-3681-4A8E-AFE5-29F257229F3B" 10 | } 11 | } -------------------------------------------------------------------------------- /Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/SceneMetadataList.json: -------------------------------------------------------------------------------- 1 | { 2 | "0A9B4653-B11E-4D6A-850E-C6FCB621626C" : { 3 | "cameraTransform" : [ 4 | 1, 5 | 0, 6 | 0, 7 | 0, 8 | 0, 9 | 0.86602545, 10 | -0.49999994, 11 | 0, 12 | 0, 13 | 0.49999994, 14 | 0.86602545, 15 | 0, 16 | 0.0035969093, 17 | 0.35542378, 18 | 0.62919164, 19 | 1 20 | ], 21 | "objectMetadataList" : [ 22 | [ 23 | "0A9B4653-B11E-4D6A-850E-C6FCB621626C", 24 | "Root" 25 | ], 26 | { 27 | "isExpanded" : true, 28 | "isLocked" : false 29 | } 30 | ] 31 | }, 32 | "65F6F990-A780-4474-B78B-572E0E4E273D" : { 33 | "cameraTransform" : [ 34 | 1, 35 | 0, 36 | -0, 37 | 0, 38 | -0, 39 | 0.86602545, 40 | -0.49999988, 41 | 0, 42 | 0, 43 | 0.49999988, 44 | 0.86602545, 45 | 0, 46 | 1.1972517e-08, 47 | 2.6179132, 48 | 0.43191218, 49 | 1 50 | ], 51 | "objectMetadataList" : [ 52 | [ 53 | "65F6F990-A780-4474-B78B-572E0E4E273D", 54 | "Root" 55 | ], 56 | { 57 | "isExpanded" : true, 58 | "isLocked" : false 59 | } 60 | ] 61 | }, 62 | "66168B71-AB05-424E-8B6C-D33D6E61B08F" : { 63 | "cameraTransform" : [ 64 | 1, 65 | 0, 66 | -0, 67 | 0, 68 | -0, 69 | 0.8660254, 70 | -0.5, 71 | 0, 72 | 0, 73 | 0.5, 74 | 0.8660254, 75 | 0, 76 | 0, 77 | 0.23875366, 78 | 0.4135335, 79 | 1 80 | ], 81 | "objectMetadataList" : [ 82 | [ 83 | "66168B71-AB05-424E-8B6C-D33D6E61B08F", 84 | "Root" 85 | ], 86 | { 87 | "isExpanded" : true, 88 | "isLocked" : false 89 | } 90 | ] 91 | }, 92 | "AF09ED6F-1707-48FD-8720-65B998362C09" : { 93 | "cameraTransform" : [ 94 | 1, 95 | 0, 96 | -0, 97 | 0, 98 | -0, 99 | 0.7071069, 100 | -0.7071067, 101 | 0, 102 | 0, 103 | 0.7071067, 104 | 0.7071069, 105 | 0, 106 | 0, 107 | 2.8836339, 108 | -0.107588194, 109 | 1 110 | ], 111 | "objectMetadataList" : [ 112 | [ 113 | "AF09ED6F-1707-48FD-8720-65B998362C09", 114 | "Root" 115 | ], 116 | { 117 | "isExpanded" : true, 118 | "isLocked" : false 119 | }, 120 | [ 121 | "AF09ED6F-1707-48FD-8720-65B998362C09", 122 | "Root", 123 | "Sphere_Left" 124 | ], 125 | { 126 | "isExpanded" : true, 127 | "isLocked" : false 128 | }, 129 | [ 130 | "AF09ED6F-1707-48FD-8720-65B998362C09", 131 | "Root", 132 | "Sphere_Right" 133 | ], 134 | { 135 | "isExpanded" : true, 136 | "isLocked" : false 137 | } 138 | ] 139 | }, 140 | "CB766F92-EE55-4A63-9401-E7B8C009764D" : { 141 | "cameraTransform" : [ 142 | 1, 143 | 0, 144 | -0, 145 | 0, 146 | -0, 147 | 0.8660253, 148 | -0.5000001, 149 | 0, 150 | 0, 151 | 0.5000001, 152 | 0.8660253, 153 | 0, 154 | 0, 155 | 0.27093494, 156 | 0.4692731, 157 | 1 158 | ], 159 | "objectMetadataList" : [ 160 | [ 161 | "CB766F92-EE55-4A63-9401-E7B8C009764D", 162 | "Root", 163 | "GridMaterial" 164 | ], 165 | { 166 | "isExpanded" : true, 167 | "isLocked" : false 168 | }, 169 | [ 170 | "CB766F92-EE55-4A63-9401-E7B8C009764D", 171 | "Root" 172 | ], 173 | { 174 | "isExpanded" : true, 175 | "isLocked" : false 176 | } 177 | ] 178 | }, 179 | "D560BB77-AAF3-4BDE-B7C4-989332A4688B" : { 180 | "cameraTransform" : [ 181 | 1, 182 | 0, 183 | -0, 184 | 0, 185 | -0, 186 | 0.8660253, 187 | -0.5000001, 188 | 0, 189 | 0, 190 | 0.5000001, 191 | 0.8660253, 192 | 0, 193 | 0, 194 | 0.27093494, 195 | 0.4692731, 196 | 1 197 | ], 198 | "objectMetadataList" : [ 199 | 200 | ] 201 | }, 202 | "D66134B1-3681-4A8E-AFE5-29F257229F3B" : { 203 | "cameraTransform" : [ 204 | 1, 205 | 0, 206 | -0, 207 | 0, 208 | -0, 209 | 0.7071069, 210 | -0.7071067, 211 | 0, 212 | 0, 213 | 0.7071067, 214 | 0.7071069, 215 | 0, 216 | 0, 217 | 0.26894823, 218 | 0.26934713, 219 | 1 220 | ], 221 | "objectMetadataList" : [ 222 | [ 223 | "D66134B1-3681-4A8E-AFE5-29F257229F3B", 224 | "Root", 225 | "GridMaterial", 226 | "GridMaterial" 227 | ], 228 | { 229 | "isExpanded" : true, 230 | "isLocked" : false 231 | }, 232 | [ 233 | "D66134B1-3681-4A8E-AFE5-29F257229F3B", 234 | "Root" 235 | ], 236 | { 237 | "isExpanded" : true, 238 | "isLocked" : false 239 | } 240 | ] 241 | } 242 | } -------------------------------------------------------------------------------- /Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/Settings.rcprojectdata: -------------------------------------------------------------------------------- 1 | { 2 | "cameraPresets" : { 3 | 4 | }, 5 | "secondaryToolbarData" : { 6 | "isGridVisible" : true, 7 | "sceneReverbPreset" : -1 8 | }, 9 | "unitDefaults" : { 10 | "°" : "°", 11 | "kg" : "g", 12 | "m" : "cm", 13 | "m\/s" : "m\/s", 14 | "m\/s²" : "m\/s²", 15 | "s" : "s" 16 | } 17 | } -------------------------------------------------------------------------------- /Packages/RealityKitContent/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.9 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "RealityKitContent", 8 | products: [ 9 | // Products define the executables and libraries a package produces, and make them visible to other packages. 10 | .library( 11 | name: "RealityKitContent", 12 | targets: ["RealityKitContent"]), 13 | ], 14 | dependencies: [ 15 | // Dependencies declare other packages that this package depends on. 16 | // .package(url: /* package url */, from: "1.0.0"), 17 | ], 18 | targets: [ 19 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 20 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 21 | .target( 22 | name: "RealityKitContent", 23 | dependencies: []), 24 | ] 25 | ) -------------------------------------------------------------------------------- /Packages/RealityKitContent/README.md: -------------------------------------------------------------------------------- 1 | # RealityKitContent 2 | 3 | A description of this package. -------------------------------------------------------------------------------- /Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Immersive.usda: -------------------------------------------------------------------------------- 1 | #usda 1.0 2 | ( 3 | defaultPrim = "Root" 4 | metersPerUnit = 1 5 | upAxis = "Y" 6 | ) 7 | 8 | def Xform "Root" 9 | { 10 | reorder nameChildren = ["Sphere_Left", "Sphere_Right", "GridMaterial"] 11 | def Sphere "Sphere_Right" ( 12 | active = true 13 | prepend apiSchemas = ["MaterialBindingAPI"] 14 | ) 15 | { 16 | rel material:binding = ( 17 | bindMaterialAs = "weakerThanDescendants" 18 | ) 19 | double radius = 0.1 20 | quatf xformOp:orient = (1, 0, 0, 0) 21 | float3 xformOp:scale = (1, 1, 1) 22 | float3 xformOp:translate = (0.5, 1.5, -1.5) 23 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 24 | } 25 | 26 | def Sphere "Sphere_Left" ( 27 | active = true 28 | prepend apiSchemas = ["MaterialBindingAPI"] 29 | ) 30 | { 31 | rel material:binding = ( 32 | bindMaterialAs = "weakerThanDescendants" 33 | ) 34 | double radius = 0.1 35 | quatf xformOp:orient = (1, 0, 0, 0) 36 | float3 xformOp:scale = (1, 1, 1) 37 | float3 xformOp:translate = (-0.5, 1.5, -1.5) 38 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 39 | } 40 | 41 | def "GridMaterial" ( 42 | active = true 43 | prepend references = @Materials/GridMaterial.usda@ 44 | ) 45 | { 46 | float3 xformOp:scale = (1, 1, 1) 47 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Materials/GridMaterial.usda: -------------------------------------------------------------------------------- 1 | #usda 1.0 2 | ( 3 | defaultPrim = "Root" 4 | metersPerUnit = 1 5 | upAxis = "Y" 6 | ) 7 | 8 | def Xform "Root" 9 | { 10 | def Material "GridMaterial" 11 | { 12 | reorder nameChildren = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "DefaultSurfaceShader", "MaterialXPreviewSurface", "Texcoord", "Add", "Multiply", "Fractional", "LineCounts", "Multiply_1", "Separate2", "Separate2_1", "Ifgreater", "Ifgreater_1", "Max", "Background_Color"] 13 | token outputs:mtlx:surface.connect = 14 | token outputs:realitykit:vertex 15 | token outputs:surface 16 | float2 ui:nodegraph:realitykit:subgraphOutputs:pos = (2222, 300.5) 17 | float2 ui:nodegraph:realitykit:subgraphOutputs:size = (182, 89) 18 | int ui:nodegraph:realitykit:subgraphOutputs:stackingOrder = 749 19 | 20 | def Shader "DefaultSurfaceShader" 21 | { 22 | uniform token info:id = "UsdPreviewSurface" 23 | color3f inputs:diffuseColor = (1, 1, 1) 24 | float inputs:roughness = 0.75 25 | token outputs:surface 26 | } 27 | 28 | def Shader "MaterialXPreviewSurface" 29 | { 30 | uniform token info:id = "ND_UsdPreviewSurface_surfaceshader" 31 | float inputs:clearcoat 32 | float inputs:clearcoatRoughness 33 | color3f inputs:diffuseColor.connect = 34 | color3f inputs:emissiveColor 35 | float inputs:ior 36 | float inputs:metallic = 0.15 37 | float3 inputs:normal 38 | float inputs:occlusion 39 | float inputs:opacity 40 | float inputs:opacityThreshold 41 | float inputs:roughness = 0.5 42 | token outputs:out 43 | float2 ui:nodegraph:node:pos = (1967, 300.5) 44 | float2 ui:nodegraph:node:size = (208, 297) 45 | int ui:nodegraph:node:stackingOrder = 870 46 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["Advanced"] 47 | } 48 | 49 | def Shader "Texcoord" 50 | { 51 | uniform token info:id = "ND_texcoord_vector2" 52 | float2 outputs:out 53 | float2 ui:nodegraph:node:pos = (94.14453, 35.29297) 54 | float2 ui:nodegraph:node:size = (182, 43) 55 | int ui:nodegraph:node:stackingOrder = 1358 56 | } 57 | 58 | def Shader "Multiply" 59 | { 60 | uniform token info:id = "ND_multiply_vector2" 61 | float2 inputs:in1.connect = 62 | float2 inputs:in2 = (32, 15) 63 | float2 inputs:in2.connect = 64 | float2 outputs:out 65 | float2 ui:nodegraph:node:pos = (275.64453, 47.29297) 66 | float2 ui:nodegraph:node:size = (61, 36) 67 | int ui:nodegraph:node:stackingOrder = 1348 68 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:in2"] 69 | } 70 | 71 | def Shader "Fractional" 72 | { 73 | uniform token info:id = "ND_realitykit_fractional_vector2" 74 | float2 inputs:in.connect = 75 | float2 outputs:out 76 | float2 ui:nodegraph:node:pos = (440.5, 49.5) 77 | float2 ui:nodegraph:node:size = (155, 99) 78 | int ui:nodegraph:node:stackingOrder = 1345 79 | } 80 | 81 | def Shader "BaseColor" 82 | { 83 | uniform token info:id = "ND_constant_color3" 84 | color3f inputs:value = (0.89737034, 0.89737034, 0.89737034) ( 85 | colorSpace = "Input - Texture - sRGB - sRGB" 86 | ) 87 | color3f inputs:value.connect = None 88 | color3f outputs:out 89 | float2 ui:nodegraph:node:pos = (1537.5977, 363.07812) 90 | float2 ui:nodegraph:node:size = (150, 43) 91 | int ui:nodegraph:node:stackingOrder = 1353 92 | } 93 | 94 | def Shader "LineColor" 95 | { 96 | uniform token info:id = "ND_constant_color3" 97 | color3f inputs:value = (0.55945957, 0.55945957, 0.55945957) ( 98 | colorSpace = "Input - Texture - sRGB - sRGB" 99 | ) 100 | color3f inputs:value.connect = None 101 | color3f outputs:out 102 | float2 ui:nodegraph:node:pos = (1536.9844, 287.86328) 103 | float2 ui:nodegraph:node:size = (146, 43) 104 | int ui:nodegraph:node:stackingOrder = 1355 105 | } 106 | 107 | def Shader "LineWidths" 108 | { 109 | uniform token info:id = "ND_combine2_vector2" 110 | float inputs:in1 = 0.1 111 | float inputs:in2 = 0.1 112 | float2 outputs:out 113 | float2 ui:nodegraph:node:pos = (443.64453, 233.79297) 114 | float2 ui:nodegraph:node:size = (151, 43) 115 | int ui:nodegraph:node:stackingOrder = 1361 116 | } 117 | 118 | def Shader "LineCounts" 119 | { 120 | uniform token info:id = "ND_combine2_vector2" 121 | float inputs:in1 = 24 122 | float inputs:in2 = 12 123 | float2 outputs:out 124 | float2 ui:nodegraph:node:pos = (94.14453, 138.29297) 125 | float2 ui:nodegraph:node:size = (153, 43) 126 | int ui:nodegraph:node:stackingOrder = 1359 127 | } 128 | 129 | def Shader "Remap" 130 | { 131 | uniform token info:id = "ND_remap_color3" 132 | color3f inputs:in.connect = 133 | color3f inputs:inhigh.connect = None 134 | color3f inputs:inlow.connect = None 135 | color3f inputs:outhigh.connect = 136 | color3f inputs:outlow.connect = 137 | color3f outputs:out 138 | float2 ui:nodegraph:node:pos = (1755.5, 300.5) 139 | float2 ui:nodegraph:node:size = (95, 171) 140 | int ui:nodegraph:node:stackingOrder = 1282 141 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:outlow"] 142 | } 143 | 144 | def Shader "Separate2" 145 | { 146 | uniform token info:id = "ND_separate2_vector2" 147 | float2 inputs:in.connect = 148 | float outputs:outx 149 | float outputs:outy 150 | float2 ui:nodegraph:node:pos = (1212.6445, 128.91797) 151 | float2 ui:nodegraph:node:size = (116, 117) 152 | int ui:nodegraph:node:stackingOrder = 1363 153 | } 154 | 155 | def Shader "Combine3" 156 | { 157 | uniform token info:id = "ND_combine3_color3" 158 | float inputs:in1.connect = 159 | float inputs:in2.connect = 160 | float inputs:in3.connect = 161 | color3f outputs:out 162 | float2 ui:nodegraph:node:pos = (1578.1445, 128.91797) 163 | float2 ui:nodegraph:node:size = (146, 54) 164 | int ui:nodegraph:node:stackingOrder = 1348 165 | } 166 | 167 | def Shader "Range" 168 | { 169 | uniform token info:id = "ND_range_vector2" 170 | bool inputs:doclamp = 1 171 | float2 inputs:gamma = (2, 2) 172 | float2 inputs:in.connect = 173 | float2 inputs:inhigh.connect = 174 | float2 inputs:inlow = (0.02, 0.02) 175 | float2 inputs:outhigh 176 | float2 inputs:outlow 177 | float2 outputs:out 178 | float2 ui:nodegraph:node:pos = (990.64453, 128.91797) 179 | float2 ui:nodegraph:node:size = (98, 207) 180 | int ui:nodegraph:node:stackingOrder = 1364 181 | } 182 | 183 | def Shader "Subtract" 184 | { 185 | uniform token info:id = "ND_subtract_vector2" 186 | float2 inputs:in1.connect = 187 | float2 inputs:in2.connect = 188 | float2 outputs:out 189 | float2 ui:nodegraph:node:pos = (612.64453, 87.04297) 190 | float2 ui:nodegraph:node:size = (63, 36) 191 | int ui:nodegraph:node:stackingOrder = 1348 192 | } 193 | 194 | def Shader "Absval" 195 | { 196 | uniform token info:id = "ND_absval_vector2" 197 | float2 inputs:in.connect = 198 | float2 outputs:out 199 | float2 ui:nodegraph:node:pos = (765.64453, 87.04297) 200 | float2 ui:nodegraph:node:size = (123, 43) 201 | int ui:nodegraph:node:stackingOrder = 1348 202 | } 203 | 204 | def Shader "Min" 205 | { 206 | uniform token info:id = "ND_min_float" 207 | float inputs:in1.connect = 208 | float inputs:in2.connect = 209 | float outputs:out 210 | float2 ui:nodegraph:node:pos = (1388.1445, 128.91797) 211 | float2 ui:nodegraph:node:size = (114, 36) 212 | int ui:nodegraph:node:stackingOrder = 1363 213 | } 214 | } 215 | } 216 | 217 | -------------------------------------------------------------------------------- /Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Scene.usda: -------------------------------------------------------------------------------- 1 | #usda 1.0 2 | ( 3 | defaultPrim = "Root" 4 | metersPerUnit = 1 5 | upAxis = "Y" 6 | ) 7 | 8 | def Xform "Root" 9 | { 10 | reorder nameChildren = ["GridMaterial", "Sphere"] 11 | rel material:binding = None ( 12 | bindMaterialAs = "weakerThanDescendants" 13 | ) 14 | 15 | def Sphere "Sphere" ( 16 | active = true 17 | prepend apiSchemas = ["MaterialBindingAPI"] 18 | ) 19 | { 20 | rel material:binding = ( 21 | bindMaterialAs = "weakerThanDescendants" 22 | ) 23 | double radius = 0.05 24 | quatf xformOp:orient = (1, 0, 0, 0) 25 | float3 xformOp:scale = (1, 1, 1) 26 | float3 xformOp:translate = (0, 0, 0.0004) 27 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 28 | 29 | def RealityKitComponent "Collider" 30 | { 31 | uint group = 1 32 | uniform token info:id = "RealityKit.Collider" 33 | uint mask = 4294967295 34 | token type = "Default" 35 | 36 | def RealityKitStruct "Shape" 37 | { 38 | float3 extent = (0.2, 0.2, 0.2) 39 | float radius = 0.05 40 | token shapeType = "Sphere" 41 | } 42 | } 43 | 44 | def RealityKitComponent "InputTarget" 45 | { 46 | uniform token info:id = "RealityKit.InputTarget" 47 | } 48 | } 49 | 50 | def "GridMaterial" ( 51 | active = true 52 | prepend references = @Materials/GridMaterial.usda@ 53 | ) 54 | { 55 | float3 xformOp:scale = (1, 1, 1) 56 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Bundle for the RealityKitContent project 4 | public let realityKitContentBundle = Bundle.module 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Envi for Vision Pro 🥽 🌎 2 | 3 | Envi is an innovative open-source application designed for Vision Pro users, leveraging the power of artificial intelligence to generate immersive environments. By utilizing the Replicate API, Envi enables users to bring their digital worlds to life with unparalleled ease and flexibility. 4 | 5 | 6 | https://github.com/Flode-Labs/envi/assets/71894332/e7f94745-4330-43f1-9abd-dfc906ae583d 7 | 8 | 9 | ## Features 🚀 10 | 11 | - **AI-Powered Environment Generation**: Create stunning, realistic environments with the assistance of advanced AI algorithms. 12 | - **User-Controlled API Integration**: By incorporating your Replicate API token, you maintain full control over the application's operations and associated costs. 13 | - **Open-Source Flexibility**: Dive into the code, customize features, and tailor the application to fit your unique needs. 14 | 15 | ## Installation 🛠️ 16 | 17 | 1. **Clone the Repository** 18 | 19 | Open your terminal and execute the following command to clone the Envi repository: 20 | 21 | ```bash 22 | git clone https://github.com/Flode-Labs/envi.git 23 | ``` 24 | 25 | 2. **Open the Project in Xcode** 26 | 27 | Navigate to the cloned repository's directory and open the project file (`Envi.xcodeproj`) in Xcode. 28 | 29 | 2. **Build and Run the Application** 30 | 31 | Use Xcode to build and run the application on your Vision Pro device or an emulator. Ensure all dependencies are correctly configured within Xcode before launching. 32 | 33 | ## Usage Example 📖 34 | 35 | Envi offers two main menus for creating environments: 36 | 37 | - **Examples Menu**: Browse through a selection of pre-defined real-world environments to get inspired or to quickly demonstrate the capabilities of Envi. 38 | 39 | - **Creation Menu**: This is where your creativity comes into play. After saving your Replicate API token in the application's settings, navigate to this menu to specify the type of environment you wish to generate. Simply enter a description of your desired environment, and let Envi do the rest. 40 | 41 | Remember, your Replicate API token is essential for this process, as it allows you to manage the operational aspects and costs associated with generating environments. 42 | 43 | ## How to Contribute 🤝 44 | 45 | We acknowledge our journey into Swift development for the Vision Pro platform has been a learning experience, and we anticipate potential issues or non-optimal practices in our codebase. Your expertise and contributions are invaluable to us: 46 | 47 | - **Improving Code Quality**: Suggestions for better practices or solutions to potential problems are highly appreciated. 48 | - **Feature Requests**: Have an idea for a new feature? Let us know or contribute directly by submitting a pull request. 49 | - **Bug Reports**: Encounter an issue? Report it by opening an issue, and we'll look into it promptly. 50 | 51 | To contribute, please fork the repository, make your changes, and submit a pull request for review. 52 | 53 | ## Acknowledgments 👏 54 | 55 | A special thanks to the Replicate team for providing the API that powers Envi's environment generation capabilities. 56 | 57 | ## Disclaimer 📝 58 | 59 | This project is developed by enthusiasts passionate about technology and AI's potential. As we navigate through the intricacies of Swift development, we openly admit our learning curve and encourage the community to help us improve wherever possible. 60 | 61 | ## License 📄 62 | 63 | Envi is released under the MIT License. See the LICENSE file for more details. 64 | 65 | --- 66 | 67 | We're excited to see how you use and contribute to Envi! Let's create something amazing together. 🌟 68 | -------------------------------------------------------------------------------- /video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flode-Labs/envi/12c8b263621b6c9a8c14b03359c6697b12ec15e3/video.mp4 --------------------------------------------------------------------------------