";
89 | };
90 | /* End PBXGroup section */
91 |
92 | /* Begin PBXNativeTarget section */
93 | 27B2AAC0293595890077B204 /* FluidGradientExample */ = {
94 | isa = PBXNativeTarget;
95 | buildConfigurationList = 27B2AACF2935958A0077B204 /* Build configuration list for PBXNativeTarget "FluidGradientExample" */;
96 | buildPhases = (
97 | 27B2AABD293595890077B204 /* Sources */,
98 | 27B2AABE293595890077B204 /* Frameworks */,
99 | 27B2AABF293595890077B204 /* Resources */,
100 | );
101 | buildRules = (
102 | );
103 | dependencies = (
104 | );
105 | name = FluidGradientExample;
106 | packageProductDependencies = (
107 | 2776120329378B6F009ABDD2 /* FluidGradient */,
108 | );
109 | productName = FluidGradientExample;
110 | productReference = 27B2AAC1293595890077B204 /* FluidGradientExample.app */;
111 | productType = "com.apple.product-type.application";
112 | };
113 | /* End PBXNativeTarget section */
114 |
115 | /* Begin PBXProject section */
116 | 27B2AAB9293595890077B204 /* Project object */ = {
117 | isa = PBXProject;
118 | attributes = {
119 | BuildIndependentTargetsInParallel = 1;
120 | LastSwiftUpdateCheck = 1410;
121 | LastUpgradeCheck = 1410;
122 | TargetAttributes = {
123 | 27B2AAC0293595890077B204 = {
124 | CreatedOnToolsVersion = 14.1;
125 | };
126 | };
127 | };
128 | buildConfigurationList = 27B2AABC293595890077B204 /* Build configuration list for PBXProject "FluidGradientExample" */;
129 | compatibilityVersion = "Xcode 14.0";
130 | developmentRegion = en;
131 | hasScannedForEncodings = 0;
132 | knownRegions = (
133 | en,
134 | Base,
135 | );
136 | mainGroup = 27B2AAB8293595890077B204;
137 | productRefGroup = 27B2AAC2293595890077B204 /* Products */;
138 | projectDirPath = "";
139 | projectRoot = "";
140 | targets = (
141 | 27B2AAC0293595890077B204 /* FluidGradientExample */,
142 | );
143 | };
144 | /* End PBXProject section */
145 |
146 | /* Begin PBXResourcesBuildPhase section */
147 | 27B2AABF293595890077B204 /* Resources */ = {
148 | isa = PBXResourcesBuildPhase;
149 | buildActionMask = 2147483647;
150 | files = (
151 | 27B2AACC2935958A0077B204 /* Preview Assets.xcassets in Resources */,
152 | 27B2AAC92935958A0077B204 /* Assets.xcassets in Resources */,
153 | );
154 | runOnlyForDeploymentPostprocessing = 0;
155 | };
156 | /* End PBXResourcesBuildPhase section */
157 |
158 | /* Begin PBXSourcesBuildPhase section */
159 | 27B2AABD293595890077B204 /* Sources */ = {
160 | isa = PBXSourcesBuildPhase;
161 | buildActionMask = 2147483647;
162 | files = (
163 | 27B2AAC7293595890077B204 /* ContentView.swift in Sources */,
164 | 27B2AAC5293595890077B204 /* FluidGradientExampleApp.swift in Sources */,
165 | );
166 | runOnlyForDeploymentPostprocessing = 0;
167 | };
168 | /* End PBXSourcesBuildPhase section */
169 |
170 | /* Begin XCBuildConfiguration section */
171 | 27B2AACD2935958A0077B204 /* Debug */ = {
172 | isa = XCBuildConfiguration;
173 | buildSettings = {
174 | ALWAYS_SEARCH_USER_PATHS = NO;
175 | CLANG_ANALYZER_NONNULL = YES;
176 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
177 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
178 | CLANG_ENABLE_MODULES = YES;
179 | CLANG_ENABLE_OBJC_ARC = YES;
180 | CLANG_ENABLE_OBJC_WEAK = YES;
181 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
182 | CLANG_WARN_BOOL_CONVERSION = YES;
183 | CLANG_WARN_COMMA = YES;
184 | CLANG_WARN_CONSTANT_CONVERSION = YES;
185 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
186 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
187 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
188 | CLANG_WARN_EMPTY_BODY = YES;
189 | CLANG_WARN_ENUM_CONVERSION = YES;
190 | CLANG_WARN_INFINITE_RECURSION = YES;
191 | CLANG_WARN_INT_CONVERSION = YES;
192 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
193 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
194 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
195 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
196 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
197 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
198 | CLANG_WARN_STRICT_PROTOTYPES = YES;
199 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
200 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
201 | CLANG_WARN_UNREACHABLE_CODE = YES;
202 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
203 | COPY_PHASE_STRIP = NO;
204 | DEBUG_INFORMATION_FORMAT = dwarf;
205 | ENABLE_STRICT_OBJC_MSGSEND = YES;
206 | ENABLE_TESTABILITY = YES;
207 | GCC_C_LANGUAGE_STANDARD = gnu11;
208 | GCC_DYNAMIC_NO_PIC = NO;
209 | GCC_NO_COMMON_BLOCKS = YES;
210 | GCC_OPTIMIZATION_LEVEL = 0;
211 | GCC_PREPROCESSOR_DEFINITIONS = (
212 | "DEBUG=1",
213 | "$(inherited)",
214 | );
215 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
216 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
217 | GCC_WARN_UNDECLARED_SELECTOR = YES;
218 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
219 | GCC_WARN_UNUSED_FUNCTION = YES;
220 | GCC_WARN_UNUSED_VARIABLE = YES;
221 | IPHONEOS_DEPLOYMENT_TARGET = 16.1;
222 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
223 | MTL_FAST_MATH = YES;
224 | ONLY_ACTIVE_ARCH = YES;
225 | SDKROOT = iphoneos;
226 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
227 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
228 | };
229 | name = Debug;
230 | };
231 | 27B2AACE2935958A0077B204 /* Release */ = {
232 | isa = XCBuildConfiguration;
233 | buildSettings = {
234 | ALWAYS_SEARCH_USER_PATHS = NO;
235 | CLANG_ANALYZER_NONNULL = YES;
236 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
237 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
238 | CLANG_ENABLE_MODULES = YES;
239 | CLANG_ENABLE_OBJC_ARC = YES;
240 | CLANG_ENABLE_OBJC_WEAK = YES;
241 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
242 | CLANG_WARN_BOOL_CONVERSION = YES;
243 | CLANG_WARN_COMMA = YES;
244 | CLANG_WARN_CONSTANT_CONVERSION = YES;
245 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
246 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
247 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
248 | CLANG_WARN_EMPTY_BODY = YES;
249 | CLANG_WARN_ENUM_CONVERSION = YES;
250 | CLANG_WARN_INFINITE_RECURSION = YES;
251 | CLANG_WARN_INT_CONVERSION = YES;
252 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
253 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
254 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
255 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
256 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
258 | CLANG_WARN_STRICT_PROTOTYPES = YES;
259 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
260 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
261 | CLANG_WARN_UNREACHABLE_CODE = YES;
262 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
263 | COPY_PHASE_STRIP = NO;
264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
265 | ENABLE_NS_ASSERTIONS = NO;
266 | ENABLE_STRICT_OBJC_MSGSEND = YES;
267 | GCC_C_LANGUAGE_STANDARD = gnu11;
268 | GCC_NO_COMMON_BLOCKS = YES;
269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
271 | GCC_WARN_UNDECLARED_SELECTOR = YES;
272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
273 | GCC_WARN_UNUSED_FUNCTION = YES;
274 | GCC_WARN_UNUSED_VARIABLE = YES;
275 | IPHONEOS_DEPLOYMENT_TARGET = 16.1;
276 | MTL_ENABLE_DEBUG_INFO = NO;
277 | MTL_FAST_MATH = YES;
278 | SDKROOT = iphoneos;
279 | SWIFT_COMPILATION_MODE = wholemodule;
280 | SWIFT_OPTIMIZATION_LEVEL = "-O";
281 | VALIDATE_PRODUCT = YES;
282 | };
283 | name = Release;
284 | };
285 | 27B2AAD02935958A0077B204 /* Debug */ = {
286 | isa = XCBuildConfiguration;
287 | buildSettings = {
288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
289 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
290 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
291 | CODE_SIGN_STYLE = Automatic;
292 | CURRENT_PROJECT_VERSION = 1;
293 | DEVELOPMENT_ASSET_PATHS = "\"FluidGradientExample/Preview Content\"";
294 | DEVELOPMENT_TEAM = ZQK6SX26CE;
295 | ENABLE_PREVIEWS = YES;
296 | GENERATE_INFOPLIST_FILE = YES;
297 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
298 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
299 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
300 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
301 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
302 | IPHONEOS_DEPLOYMENT_TARGET = 16.0;
303 | LD_RUNPATH_SEARCH_PATHS = (
304 | "$(inherited)",
305 | "@executable_path/Frameworks",
306 | );
307 | MACOSX_DEPLOYMENT_TARGET = 13.0;
308 | MARKETING_VERSION = 1.0;
309 | PRODUCT_BUNDLE_IDENTIFIER = com.cindori.FluidGradientExample;
310 | PRODUCT_NAME = "$(TARGET_NAME)";
311 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
312 | SUPPORTS_MACCATALYST = NO;
313 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
314 | SWIFT_EMIT_LOC_STRINGS = YES;
315 | SWIFT_VERSION = 5.0;
316 | TARGETED_DEVICE_FAMILY = "1,2";
317 | };
318 | name = Debug;
319 | };
320 | 27B2AAD12935958A0077B204 /* Release */ = {
321 | isa = XCBuildConfiguration;
322 | buildSettings = {
323 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
324 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
325 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
326 | CODE_SIGN_STYLE = Automatic;
327 | CURRENT_PROJECT_VERSION = 1;
328 | DEVELOPMENT_ASSET_PATHS = "\"FluidGradientExample/Preview Content\"";
329 | DEVELOPMENT_TEAM = ZQK6SX26CE;
330 | ENABLE_PREVIEWS = YES;
331 | GENERATE_INFOPLIST_FILE = YES;
332 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
333 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
334 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
335 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
336 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
337 | IPHONEOS_DEPLOYMENT_TARGET = 16.0;
338 | LD_RUNPATH_SEARCH_PATHS = (
339 | "$(inherited)",
340 | "@executable_path/Frameworks",
341 | );
342 | MACOSX_DEPLOYMENT_TARGET = 13.0;
343 | MARKETING_VERSION = 1.0;
344 | PRODUCT_BUNDLE_IDENTIFIER = com.cindori.FluidGradientExample;
345 | PRODUCT_NAME = "$(TARGET_NAME)";
346 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
347 | SUPPORTS_MACCATALYST = NO;
348 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
349 | SWIFT_EMIT_LOC_STRINGS = YES;
350 | SWIFT_VERSION = 5.0;
351 | TARGETED_DEVICE_FAMILY = "1,2";
352 | };
353 | name = Release;
354 | };
355 | /* End XCBuildConfiguration section */
356 |
357 | /* Begin XCConfigurationList section */
358 | 27B2AABC293595890077B204 /* Build configuration list for PBXProject "FluidGradientExample" */ = {
359 | isa = XCConfigurationList;
360 | buildConfigurations = (
361 | 27B2AACD2935958A0077B204 /* Debug */,
362 | 27B2AACE2935958A0077B204 /* Release */,
363 | );
364 | defaultConfigurationIsVisible = 0;
365 | defaultConfigurationName = Release;
366 | };
367 | 27B2AACF2935958A0077B204 /* Build configuration list for PBXNativeTarget "FluidGradientExample" */ = {
368 | isa = XCConfigurationList;
369 | buildConfigurations = (
370 | 27B2AAD02935958A0077B204 /* Debug */,
371 | 27B2AAD12935958A0077B204 /* Release */,
372 | );
373 | defaultConfigurationIsVisible = 0;
374 | defaultConfigurationName = Release;
375 | };
376 | /* End XCConfigurationList section */
377 |
378 | /* Begin XCSwiftPackageProductDependency section */
379 | 2776120329378B6F009ABDD2 /* FluidGradient */ = {
380 | isa = XCSwiftPackageProductDependency;
381 | productName = FluidGradient;
382 | };
383 | /* End XCSwiftPackageProductDependency section */
384 | };
385 | rootObject = 27B2AAB9293595890077B204 /* Project object */;
386 | }
387 |
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Icon.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | },
9 | {
10 | "filename" : "icon_16x16.png",
11 | "idiom" : "mac",
12 | "scale" : "1x",
13 | "size" : "16x16"
14 | },
15 | {
16 | "filename" : "icon_16x16@2x@2x.png",
17 | "idiom" : "mac",
18 | "scale" : "2x",
19 | "size" : "16x16"
20 | },
21 | {
22 | "filename" : "icon_32x32.png",
23 | "idiom" : "mac",
24 | "scale" : "1x",
25 | "size" : "32x32"
26 | },
27 | {
28 | "filename" : "icon_32x32@2x@2x.png",
29 | "idiom" : "mac",
30 | "scale" : "2x",
31 | "size" : "32x32"
32 | },
33 | {
34 | "filename" : "icon_128x128.png",
35 | "idiom" : "mac",
36 | "scale" : "1x",
37 | "size" : "128x128"
38 | },
39 | {
40 | "filename" : "icon_128x128@2x@2x.png",
41 | "idiom" : "mac",
42 | "scale" : "2x",
43 | "size" : "128x128"
44 | },
45 | {
46 | "filename" : "icon_256x256.png",
47 | "idiom" : "mac",
48 | "scale" : "1x",
49 | "size" : "256x256"
50 | },
51 | {
52 | "filename" : "icon_256x256@2x@2x.png",
53 | "idiom" : "mac",
54 | "scale" : "2x",
55 | "size" : "256x256"
56 | },
57 | {
58 | "filename" : "icon_512x512.png",
59 | "idiom" : "mac",
60 | "scale" : "1x",
61 | "size" : "512x512"
62 | },
63 | {
64 | "filename" : "icon_512x512@2x@2x.png",
65 | "idiom" : "mac",
66 | "scale" : "2x",
67 | "size" : "512x512"
68 | }
69 | ],
70 | "info" : {
71 | "author" : "xcode",
72 | "version" : 1
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/Icon.png
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x@2x.png
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x@2x.png
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x@2x.png
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x@2x.png
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/FluidGradientExample/FluidGradientExample/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x@2x.png
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // FluidGradientExample
4 | //
5 | // Created by João Gabriel Pozzobon dos Santos on 28/11/22.
6 | //
7 |
8 | import SwiftUI
9 | import FluidGradient
10 |
11 | struct ContentView: View {
12 | @State var colors: [Color] = []
13 | @State var highlights: [Color] = []
14 |
15 | @State var speed = 1.0
16 |
17 | let colorPool: [Color] = [.blue, .green, .yellow, .orange, .red, .pink, .purple, .teal, .indigo]
18 |
19 | var body: some View {
20 | VStack {
21 | gradient
22 | .backgroundStyle(.quaternary)
23 | .cornerRadius(16)
24 | .padding(4)
25 |
26 | HStack {
27 | Button("Randomize colors", action: setColors)
28 | Slider(value: $speed, in: 0...5)
29 | }.padding(4)
30 | }
31 | .padding(16)
32 | .navigationTitle("FluidGradient")
33 | .onAppear(perform: setColors)
34 | }
35 |
36 | func setColors() {
37 | colors = []
38 | highlights = []
39 | for _ in 0...Int.random(in: 5...5) {
40 | colors.append(colorPool.randomElement()!)
41 | }
42 | for _ in 0...Int.random(in: 5...5) {
43 | highlights.append(colorPool.randomElement()!)
44 | }
45 | }
46 |
47 | var gradient: some View {
48 | FluidGradient(blobs: colors,
49 | highlights: highlights,
50 | speed: speed)
51 | }
52 | }
53 |
54 | struct ContentView_Previews: PreviewProvider {
55 | static var previews: some View {
56 | ContentView()
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/FluidGradientExampleApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FluidGradientExampleApp.swift
3 | // FluidGradientExample
4 | //
5 | // Created by João Gabriel Pozzobon dos Santos on 28/11/22.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct FluidGradientExampleApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | ContentView()
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/FluidGradientExample/FluidGradientExample/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Cindori
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 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.7
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: "FluidGradient",
8 | platforms: [
9 | .macOS(.v11),
10 | .iOS(.v14)
11 | ],
12 | products: [
13 | // Products define the executables and libraries a package produces, and make them visible to other packages.
14 | .library(
15 | name: "FluidGradient",
16 | targets: ["FluidGradient"]),
17 | ],
18 | dependencies: [
19 | // Dependencies declare other packages that this package depends on.
20 | // .package(url: /* package url */, from: "1.0.0"),
21 | ],
22 | targets: [
23 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
24 | // Targets can depend on other targets in this package, and on products in packages this package depends on.
25 | .target(
26 | name: "FluidGradient",
27 | dependencies: []),
28 | ]
29 | )
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 🐰 Fluid Gradient
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | A fluid, animated gradient implemented with CoreAnimation and SwiftUI, made available as a [Swift Package](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app).
14 |
15 | 
16 |
17 | ## How it works
18 |
19 | This implementation works by displaying stacked "blobs" in a coordinate space, and blurring them afterwards to make it seem seamless. The blobs are simple `CAGradientLayer` layers added to two separate `CALayer` layers: base and highlight. The latter one has an overlay blend mode to create unique patterns. You can optionally provide colors for both the base and highlight layers.
20 |
21 | ### Why CALayer?
22 |
23 | While it's easy to create the blob shapes in SwiftUI, animation in SwiftUI is still performed on the CPU. This means that your app will probably consume double-digit CPU percentages and be noted as a "high" energy consumer in Activity Monitor.
24 |
25 | We use CALayer instead because it offloads all the work to the WindowServer, making your app have a zero performance impact despite running the gradient animation at full screen refresh rate.
26 |
27 | 
28 |
29 | > **Note**
30 | > You can learn to code this project by yourself in a series of development tutorial articles written for the [Cindori Blog](https://cindori.com/developer/animated-gradient).
31 | > - [Building a fluid gradient with CoreAnimation & SwiftUI: Part 1](https://cindori.com/developer/animated-gradient)
32 | > - [Building a fluid gradient with CoreAnimation & SwiftUI: Part 2](https://cindori.com/developer/animated-gradient-2)
33 |
34 | ## Example usage
35 |
36 | You can find an example buildable project that uses FluidGradient in the root of this repository (requires Xcode 14 and macOS Ventura). To use it in your app, you can start with the following:
37 |
38 | ```swift
39 | import SwiftUI
40 | import FluidGradient
41 |
42 | struct ContentView: View {
43 | var body: some View {
44 | FluidGradient(blobs: [.red, .green, .blue],
45 | highlights: [.yellow, .orange, .purple],
46 | speed: 1.0,
47 | blur: 0.75)
48 | .background(.quaternary)
49 | }
50 | }
51 | ```
52 |
53 | ## About Cindori
54 |
55 | [](https://cindori.com)
56 |
57 | We're a small team of developers dedicated to crafting amazing experiences for Apple platforms.
58 |
59 | Check out our apps and developer blog at [cindori.com](https://cindori.com).
60 |
61 | ## Contributors
62 | - [Oskar Groth (@oskargroth)](https://github.com/oskargroth) – Founder, developer and writer
63 | - [João Gabriel (@joogps)](https://github.com/joogps) – Team member, developer and writer
64 |
65 | ## Licensing
66 | This project is made available through the [MIT License](https://opensource.org/licenses/MIT).
67 |
68 |
--------------------------------------------------------------------------------
/Sources/FluidGradient/BlobLayer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BlobLayer.swift
3 | // BlobLayer
4 | //
5 | // Created by João Gabriel Pozzobon dos Santos on 04/10/22.
6 | //
7 |
8 | import SwiftUI
9 |
10 | /// A CALayer that draws a single blob on the screen
11 | public class BlobLayer: CAGradientLayer {
12 | init(color: Color) {
13 | super.init()
14 |
15 | self.type = .radial
16 | #if os(OSX)
17 | autoresizingMask = [.layerWidthSizable, .layerHeightSizable]
18 | #endif
19 |
20 | // Set color
21 | set(color: color)
22 |
23 | // Center point
24 | let position = newPosition()
25 | self.startPoint = position
26 |
27 | // Radius
28 | let radius = newRadius()
29 | self.endPoint = position.displace(by: radius)
30 | }
31 |
32 | /// Generate a random point on the canvas
33 | func newPosition() -> CGPoint {
34 | return CGPoint(x: CGFloat.random(in: 0.0...1.0),
35 | y: CGFloat.random(in: 0.0...1.0)).capped()
36 | }
37 |
38 | /// Generate a random radius for the blob
39 | func newRadius() -> CGPoint {
40 | let size = CGFloat.random(in: 0.15...0.75)
41 | let viewRatio = frame.width/frame.height
42 | let safeRatio = max(viewRatio.isNaN ? 1 : viewRatio, 1)
43 | let ratio = safeRatio*CGFloat.random(in: 0.25...1.75)
44 | return CGPoint(x: size,
45 | y: size*ratio)
46 | }
47 |
48 | /// Animate the blob to a random point and size on screen at set speed
49 | func animate(speed: CGFloat) {
50 | guard speed > 0 else { return }
51 |
52 | self.removeAllAnimations()
53 | let currentLayer = self.presentation() ?? self
54 |
55 | let animation = CASpringAnimation()
56 | animation.mass = 10/speed
57 | animation.damping = 50
58 | animation.duration = 1/speed
59 |
60 | animation.isRemovedOnCompletion = false
61 | animation.fillMode = CAMediaTimingFillMode.forwards
62 |
63 | let position = newPosition()
64 | let radius = newRadius()
65 |
66 | // Center point
67 | let start = animation.copy() as! CASpringAnimation
68 | start.keyPath = "startPoint"
69 | start.fromValue = currentLayer.startPoint
70 | start.toValue = position
71 |
72 | // Radius
73 | let end = animation.copy() as! CASpringAnimation
74 | end.keyPath = "endPoint"
75 | end.fromValue = currentLayer.endPoint
76 | end.toValue = position.displace(by: radius)
77 |
78 | self.startPoint = position
79 | self.endPoint = position.displace(by: radius)
80 |
81 | // Opacity
82 | let value = Float.random(in: 0.5...1)
83 | let opacity = animation.copy() as! CASpringAnimation
84 | opacity.fromValue = self.opacity
85 | opacity.toValue = value
86 |
87 | self.opacity = value
88 |
89 | self.add(opacity, forKey: "opacity")
90 | self.add(start, forKey: "startPoint")
91 | self.add(end, forKey: "endPoint")
92 | }
93 |
94 | /// Set the color of the blob
95 | func set(color: Color) {
96 | // Converted to the system color so that cgColor isn't nil
97 | self.colors = [SystemColor(color).cgColor,
98 | SystemColor(color).cgColor,
99 | SystemColor(color.opacity(0.0)).cgColor]
100 | self.locations = [0.0, 0.9, 1.0]
101 | }
102 |
103 | required init?(coder: NSCoder) {
104 | fatalError("init(coder:) has not been implemented")
105 | }
106 |
107 | // Required by the framework
108 | public override init(layer: Any) {
109 | super.init(layer: layer)
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/Sources/FluidGradient/CGPoint+Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGPoint+Extensions.swift
3 | //
4 | //
5 | // Created by João Gabriel Pozzobon dos Santos on 03/10/22.
6 | //
7 |
8 | import CoreGraphics
9 |
10 | extension CGPoint {
11 | /// Build a point from an origin and a displacement
12 | func displace(by point: CGPoint = .init(x: 0.0, y: 0.0)) -> CGPoint {
13 | return CGPoint(x: self.x+point.x,
14 | y: self.y+point.y)
15 | }
16 |
17 | /// Caps the point to the unit space
18 | func capped() -> CGPoint {
19 | return CGPoint(x: max(min(x, 1), 0),
20 | y: max(min(y, 1), 0))
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/FluidGradient/FluidGradient.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FluidGradient.swift
3 | // FluidGradient
4 | //
5 | // Created by Oskar Groth on 2021-12-23.
6 | //
7 |
8 | import SwiftUI
9 |
10 | public struct FluidGradient: View {
11 | private var blobs: [Color]
12 | private var highlights: [Color]
13 | private var speed: CGFloat
14 | private var blur: CGFloat
15 |
16 | @State var blurValue: CGFloat = 0.0
17 |
18 | public init(blobs: [Color],
19 | highlights: [Color] = [],
20 | speed: CGFloat = 1.0,
21 | blur: CGFloat = 0.75) {
22 | self.blobs = blobs
23 | self.highlights = highlights
24 | self.speed = speed
25 | self.blur = blur
26 | }
27 |
28 | public var body: some View {
29 | Representable(blobs: blobs,
30 | highlights: highlights,
31 | speed: speed,
32 | blurValue: $blurValue)
33 | .blur(radius: pow(blurValue, blur))
34 | .accessibility(hidden: true)
35 | .clipped()
36 | }
37 | }
38 |
39 | #if os(OSX)
40 | typealias SystemRepresentable = NSViewRepresentable
41 | #else
42 | typealias SystemRepresentable = UIViewRepresentable
43 | #endif
44 |
45 | // MARK: - Representable
46 | extension FluidGradient {
47 | struct Representable: SystemRepresentable {
48 | var blobs: [Color]
49 | var highlights: [Color]
50 | var speed: CGFloat
51 |
52 | @Binding var blurValue: CGFloat
53 |
54 | func makeView(context: Context) -> FluidGradientView {
55 | context.coordinator.view
56 | }
57 |
58 | func updateView(_ view: FluidGradientView, context: Context) {
59 | context.coordinator.create(blobs: blobs, highlights: highlights)
60 | DispatchQueue.main.async {
61 | context.coordinator.update(speed: speed)
62 | }
63 | }
64 |
65 | #if os(OSX)
66 | func makeNSView(context: Context) -> FluidGradientView {
67 | makeView(context: context)
68 | }
69 | func updateNSView(_ view: FluidGradientView, context: Context) {
70 | updateView(view, context: context)
71 | }
72 | #else
73 | func makeUIView(context: Context) -> FluidGradientView {
74 | makeView(context: context)
75 | }
76 | func updateUIView(_ view: FluidGradientView, context: Context) {
77 | updateView(view, context: context)
78 | }
79 | #endif
80 |
81 | func makeCoordinator() -> Coordinator {
82 | Coordinator(blobs: blobs,
83 | highlights: highlights,
84 | speed: speed,
85 | blurValue: $blurValue)
86 | }
87 | }
88 |
89 | class Coordinator: FluidGradientDelegate {
90 | var blobs: [Color]
91 | var highlights: [Color]
92 | var speed: CGFloat
93 | var blurValue: Binding
94 |
95 | var view: FluidGradientView
96 |
97 | init(blobs: [Color],
98 | highlights: [Color],
99 | speed: CGFloat,
100 | blurValue: Binding) {
101 | self.blobs = blobs
102 | self.highlights = highlights
103 | self.speed = speed
104 | self.blurValue = blurValue
105 | self.view = FluidGradientView(blobs: blobs,
106 | highlights: highlights,
107 | speed: speed)
108 | self.view.delegate = self
109 | }
110 |
111 | /// Create blobs and highlights
112 | func create(blobs: [Color], highlights: [Color]) {
113 | guard blobs != self.blobs || highlights != self.highlights else { return }
114 | self.blobs = blobs
115 | self.highlights = highlights
116 |
117 | view.create(blobs, layer: view.baseLayer)
118 | view.create(highlights, layer: view.highlightLayer)
119 | view.update(speed: speed)
120 | }
121 |
122 | /// Update speed
123 | func update(speed: CGFloat) {
124 | guard speed != self.speed else { return }
125 | self.speed = speed
126 | view.update(speed: speed)
127 | }
128 |
129 | func updateBlur(_ value: CGFloat) {
130 | blurValue.wrappedValue = value
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/Sources/FluidGradient/FluidGradientView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FluidGradientView.swift
3 | // FluidGradientView
4 | //
5 | // Created by Oskar Groth on 2021-12-23.
6 | //
7 |
8 | import SwiftUI
9 | import Combine
10 |
11 | #if os(OSX)
12 | import AppKit
13 | public typealias SystemColor = NSColor
14 | public typealias SystemView = NSView
15 | #else
16 | import UIKit
17 | public typealias SystemColor = UIColor
18 | public typealias SystemView = UIView
19 | #endif
20 |
21 | /// A system view that presents an animated gradient with ``CoreAnimation``
22 | public class FluidGradientView: SystemView {
23 | var speed: CGFloat
24 |
25 | let baseLayer = ResizableLayer()
26 | let highlightLayer = ResizableLayer()
27 |
28 | var cancellables = Set()
29 |
30 | weak var delegate: FluidGradientDelegate?
31 |
32 | init(blobs: [Color] = [],
33 | highlights: [Color] = [],
34 | speed: CGFloat = 1.0) {
35 | self.speed = speed
36 | super.init(frame: .zero)
37 |
38 | if let compositingFilter = CIFilter(name: "CIOverlayBlendMode") {
39 | highlightLayer.compositingFilter = compositingFilter
40 | }
41 |
42 | #if os(OSX)
43 | layer = ResizableLayer()
44 |
45 | wantsLayer = true
46 | postsFrameChangedNotifications = true
47 |
48 | layer?.delegate = self
49 | baseLayer.delegate = self
50 | highlightLayer.delegate = self
51 |
52 | self.layer?.addSublayer(baseLayer)
53 | self.layer?.addSublayer(highlightLayer)
54 | #else
55 | self.layer.addSublayer(baseLayer)
56 | self.layer.addSublayer(highlightLayer)
57 | #endif
58 |
59 | create(blobs, layer: baseLayer)
60 | create(highlights, layer: highlightLayer)
61 | DispatchQueue.main.async {
62 | self.update(speed: speed)
63 | }
64 | }
65 |
66 | required init?(coder: NSCoder) {
67 | fatalError("init(coder:) has not been implemented")
68 | }
69 |
70 | /// Create blobs and add to specified layer
71 | public func create(_ colors: [Color], layer: CALayer) {
72 | // Remove blobs at the end if colors are removed
73 | let count = layer.sublayers?.count ?? 0
74 | let removeCount = count - colors.count
75 | if removeCount > 0 {
76 | layer.sublayers?.removeLast(removeCount)
77 | }
78 |
79 | for (index, color) in colors.enumerated() {
80 | if index < count {
81 | if let existing = layer.sublayers?[index] as? BlobLayer {
82 | existing.set(color: color)
83 | }
84 | } else {
85 | layer.addSublayer(BlobLayer(color: color))
86 | }
87 | }
88 | }
89 |
90 | /// Update sublayers and set speed and blur levels
91 | public func update(speed: CGFloat) {
92 | cancellables.removeAll()
93 | self.speed = speed
94 | guard speed > 0 else { return }
95 |
96 | let layers = (baseLayer.sublayers ?? []) + (highlightLayer.sublayers ?? [])
97 | for layer in layers {
98 | if let layer = layer as? BlobLayer {
99 | Timer.publish(every: .random(in: 0.8/speed...1.2/speed),
100 | on: .main,
101 | in: .common)
102 | .autoconnect()
103 | .sink { _ in
104 | #if os(OSX)
105 | let visible = self.window?.occlusionState.contains(.visible)
106 | guard visible == true else { return }
107 | #endif
108 | layer.animate(speed: speed)
109 | }
110 | .store(in: &cancellables)
111 | }
112 | }
113 | }
114 |
115 | /// Compute and update new blur value
116 | private func updateBlur() {
117 | delegate?.updateBlur(min(frame.width, frame.height))
118 | }
119 |
120 | /// Functional methods
121 | #if os(OSX)
122 | public override func viewDidMoveToWindow() {
123 | super.viewDidMoveToWindow()
124 | let scale = window?.backingScaleFactor ?? 2
125 | layer?.contentsScale = scale
126 | baseLayer.contentsScale = scale
127 | highlightLayer.contentsScale = scale
128 |
129 | updateBlur()
130 | }
131 |
132 | public override func resize(withOldSuperviewSize oldSize: NSSize) {
133 | updateBlur()
134 | }
135 | #else
136 | public override func layoutSubviews() {
137 | layer.frame = self.bounds
138 | baseLayer.frame = self.bounds
139 | highlightLayer.frame = self.bounds
140 |
141 | updateBlur()
142 | }
143 | #endif
144 | }
145 |
146 | protocol FluidGradientDelegate: AnyObject {
147 | func updateBlur(_ value: CGFloat)
148 | }
149 |
150 | #if os(OSX)
151 | extension FluidGradientView: CALayerDelegate, NSViewLayerContentScaleDelegate {
152 | public func layer(_ layer: CALayer,
153 | shouldInheritContentsScale newScale: CGFloat,
154 | from window: NSWindow) -> Bool {
155 | return true
156 | }
157 | }
158 | #endif
159 |
--------------------------------------------------------------------------------
/Sources/FluidGradient/ResizableLayer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResizableLayer.swift
3 | // ResizableLayer
4 | //
5 | // Created by João Gabriel Pozzobon dos Santos on 03/10/22.
6 | //
7 |
8 | import SwiftUI
9 |
10 | /// An implementation of ``CALayer`` that resizes its sublayers
11 | public class ResizableLayer: CALayer {
12 | override init() {
13 | super.init()
14 | #if os(OSX)
15 | autoresizingMask = [.layerWidthSizable, .layerHeightSizable]
16 | #endif
17 | sublayers = []
18 | }
19 |
20 | public override init(layer: Any) {
21 | super.init(layer: layer)
22 | }
23 |
24 | required init?(coder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 | public override func layoutSublayers() {
29 | super.layoutSublayers()
30 | sublayers?.forEach { layer in
31 | layer.frame = self.frame
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/assets/Glass hare.blend:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/assets/Glass hare.blend
--------------------------------------------------------------------------------
/assets/Icon.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/assets/Icon.sketch
--------------------------------------------------------------------------------
/assets/cindori.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/assets/cindori.jpg
--------------------------------------------------------------------------------
/assets/icon-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/assets/icon-small.png
--------------------------------------------------------------------------------
/assets/performance.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/assets/performance.jpg
--------------------------------------------------------------------------------
/assets/video.mov:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cindori/FluidGradient/9ddda4cf23671ef0228e88681ec6210cb3e0d7f7/assets/video.mov
--------------------------------------------------------------------------------