{"id":3248,"date":"2023-05-25T23:06:13","date_gmt":"2023-05-26T06:06:13","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/surface-duo\/?p=3248"},"modified":"2023-05-25T23:06:13","modified_gmt":"2023-05-26T06:06:13","slug":"jetpack-compose-animation-3","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/surface-duo\/jetpack-compose-animation-3\/","title":{"rendered":"Blossoming love for Compose animation"},"content":{"rendered":"<p>\n  Hello Jetpack Compose developers,\n<\/p>\n<p>\n  Today we\u2019ll be finishing up our blog series on animations in Jetpack Compose! This content was inspired by <a href=\"https:\/\/www.droidcon.com\/2022\/08\/01\/composable-sheep-a-compose-animations-journey\/\">Nicole Terc\u2019s Composable Sheep talk<\/a> from droidcon NYC.\n<\/p>\n<p>\n  Over the past two weeks, we covered some basics graphics, animation canvases, and basic animations. This week, we\u2019ll polish up our garden with some more complex animation combos and background shaders.\n<\/p>\n<h2>Creating more complex animations<\/h2>\n<p>\n  We\u2019ll be continuing to use our <code>drawSunflower<\/code> method and <code>Sketch<\/code> composable to build animations in this post, so if you haven\u2019t already, check out the previous blog posts to see how we built those functions!\n<\/p>\n<p>\n  So far, we\u2019ve built a basic sunflower, then animated its rotation, size, and color individually. Now, to create more complex animations, let\u2019s try animated multiple properties at once! We can combine petal color animations with rotation to create a rainbow spinner effect, and we can also combine the color, size, and rotation animations together for an exciting effect:\n<\/p>\n<pre>  @Composable\r\n  fun AnimatedPetalColorAndRotationSunflower() {\r\n      <em>Sketch<\/em>(\r\n          modifier = Modifier.<em>size<\/em>(100.<em>dp<\/em>),\r\n          targetValue = 360f,\r\n          animationSpec = <em>infiniteRepeatable<\/em>(<em>tween<\/em>(durationMillis = 3000, easing = <em>LinearEasing<\/em>))\r\n      ) <strong>{ <\/strong>animationState <strong>-&gt;\r\n        <\/strong><em>drawSunflower<\/em>(hue = animationState, rotation = animationState)\r\n      <strong>}<br \/><\/strong>\r\n  }\r\n\r\n  @Composable\r\n  fun AnimatedEverythingSunflower() {\r\n      <em>Sketch<\/em>(\r\n          modifier = Modifier.<em>size<\/em>(100.<em>dp<\/em>),\r\n          targetValue = 360f,\r\n          animationSpec = <em>infiniteRepeatable<\/em>(\r\n              <em>tween<\/em>(durationMillis = 800, delayMillis = 50, easing = <em>LinearOutSlowInEasing<\/em>),\r\n              repeatMode = RepeatMode.<em>Reverse<br \/>        <\/em>)\r\n      ) <strong>{ <\/strong>animationState <strong>-&gt;<br \/>        <\/strong><em>drawSunflower<\/em>(\r\n              sizePct = animationState \/ 360f,\r\n              rotation = animationState,\r\n              color = Color.hsv(hue = animationState, saturation = 1f, value = 1f)\r\n          )\r\n      <strong>}<\/strong>\r\n  }<\/pre>\n<p>\n  Our garden looks colorful and dynamic now:\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"800\" height=\"566\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2023\/05\/video-to-gif-output-image-3.gif\" class=\"wp-image-3250\" alt=\"[video-to-gif output image]\" \/>\n<\/p>\n<h2>Adding a background shader<\/h2>\n<p>\n  The last step to complete our garden is to surround the flowers with some vibrant grass, which we can do by adding a dynamic shader background. I started by checking out <a href=\"https:\/\/github.com\/drinkthestars\/composable-sheep-sketches\/blob\/main\/sheepSketches\/src\/main\/java\/trnt\/sheepsketches\/screens\/BackgroundShaderScreen.kt\">BackgroundShaderScreen.kt<\/a> and <a href=\"https:\/\/github.com\/drinkthestars\/composable-sheep-sketches\/blob\/main\/sheepSketches\/src\/main\/java\/trnt\/sheepsketches\/screens\/GradientShaderScreen.kt\">GradientShaderScreen.kt<\/a> to see how shaders were incorporated into the composable sheep project. For Android apps, you can use the Android Graphics Shading Language (<a href=\"https:\/\/developer.android.com\/develop\/ui\/views\/graphics\/agsl\">AGSL<\/a>), which is very similar to the popular OpenGL Shading Languade (<a href=\"https:\/\/en.wikibooks.org\/wiki\/GLSL_Programming\/Introduction\">GLSL<\/a>) if you\u2019re already familiar with shaders. Since our project is built with Compose Multiplatform, though, we also need to support the desktop version of the app. Instead of AGSL, for desktop we can use Skia\u2019s Shading Language (<a href=\"https:\/\/skia.org\/docs\/user\/sksl\/\">SKSL<\/a>).\n<\/p>\n<p>\n  Let\u2019s first try to modify the <b>GradientShaderScreen.kt<\/b> code to show a nice blend of greens! Throughout this process, we can use the <a href=\"https:\/\/shaders.skia.org\/?id=7184139cc74efbc200da22be620904e71851283ae33a886c599490e263f550f9\">Skia Shaders Playground<\/a> or the <a href=\"https:\/\/shdr.bkcore.com\/\">Shdr Editor (for GLSL)<\/a> tools to help visualize the results.\n<\/p>\n<h3>Basic green gradient shader<\/h3>\n<p>\n  Here\u2019s what the shader code currently looks like (<a href=\"https:\/\/user-images.githubusercontent.com\/2978958\/197999733-0d554301-32ef-41b0-a3c0-0c66e01ac26d.mp4\">and literally looks like<\/a>):\n<\/p>\n<pre>  uniform float2 iResolution;\r\n  uniform float iTime;\r\n\r\n  vec4 main(in float2 fragCoord) {\r\n    \/\/ Normalized pixel coordinates (from 0 to 1)\r\n    vec2 uv = fragCoord\/iResolution.xy;\r\n\r\n    \/\/ Time varying pixel color\r\n    vec3 col = 0.8 + 0.2*cos(iTime*2.0+uv.xxx*2.0+vec3(1,2,4));\r\n      \r\n    \/\/ Output to screen\r\n    return vec4(col,1.0);\r\n  }<\/pre>\n<p>\n  The line where <code>col<\/code> is assigned is where the time varying color is decided, so to make the gradient only show shades of green, this is the line we\u2019ll have to change. This <code>vec3<\/code> represents the RGB values of the shader color, so the first step to building a new gradient was to pick a few shades of green and note their RGB values.\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"513\" height=\"352\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2023\/05\/word-image-3248-3.png\" class=\"wp-image-3251\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2023\/05\/word-image-3248-3.png 513w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2023\/05\/word-image-3248-3-300x206.png 300w\" sizes=\"(max-width: 513px) 100vw, 513px\" \/>\n<\/p>\n<p>\n  Once the colors were chosen, all I had to do was experiment a bit in the shader preview tool and dust off my trigonometry knowledge to get the RGB values to vary between those of my chosen shades of green; this resulted in the following updated shader code:\n<\/p>\n<pre>  uniform float2 iResolution;\r\n  uniform float iTime;\r\n\r\n  vec4 main(in float2 fragCoord) {\r\n      \/\/ Normalized pixel coordinates (from 0 to 1)\r\n      vec2 uv = iTime\/iResolution.xy;\r\n\r\n      \/\/ Time varying pixel color\r\n      float r = 0.3 + 0.5*sin(iTime*2.0+uv.x*3.0);\r\n      float g = 0.9 + 0.1*cos(iTime*2.0+uv.x*3.0);\r\n      float b = 0.3 + 0.4*cos(iTime*2.0+uv.x*3.0);\r\n\r\n      \/\/ Output to screen\r\n      return vec4(r, g, b, 1.0);\r\n  }<\/pre>\n<p>\n  Now that we\u2019re happy with the shader code, all that\u2019s left to do is use it in the app as our garden background. Since our desktop and mobile implementations will be different, we can add a <code>backgroundBrush<\/code> parameter to our main composable and write the appropriate code in each module. We will again be using <code>LaunchedEffect<\/code> to create a changing time value (like we did previously with <code>Sketch<\/code>) that can be passed in as the <code>iTime<\/code> float for the shader code. And, since we don\u2019t want to cause unnecessary recomposition, we will make sure to use the lambda Modifier <code>drawBehind<\/code>. For the desktop app, we will be using Skia\u2019s <code>RuntimeEffect<\/code> to build a shader, as covered in this <a href=\"https:\/\/www.pushing-pixels.org\/2021\/09\/22\/skia-shaders-in-compose-desktop.html\">article on Skia shaders for Compose desktop<\/a>. For the Android app, we\u2019ll use <code>RuntimeShader<\/code>, as described by the <a href=\"https:\/\/developer.android.com\/develop\/ui\/views\/graphics\/agsl\/using-agsl#using_runtimeshader_with_jetpack_compose\">AGSL documentation<\/a>. Both of these versions can then be converted to an <a href=\"https:\/\/developer.android.com\/jetpack\/compose\/graphics\/draw\/brush\">Android <code>ShaderBrush<\/code><\/a> and passed into the common main composable. Check out the GitHub repo for the <a href=\"https:\/\/github.com\/khalp\/animated-garden\/blob\/main\/Garden\/common\/src\/commonMain\/kotlin\/com\/example\/common\/App.kt#L62\">fully updated <code>MyGarden<\/code> code<\/a> .\n<\/p>\n<p>\n  Here\u2019s the result:\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"800\" height=\"498\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2023\/05\/video-to-gif-output-image-4.gif\" class=\"wp-image-3252\" alt=\"[video-to-gif output image]\" \/>\n<\/p>\n<h3>Complex shader<\/h3>\n<p>\n  Now that we have the shader infrastructure set up, we can play around more with creating different shader effects. The <a href=\"https:\/\/github.com\/drinkthestars\/composable-sheep-sketches\/blob\/main\/sheepSketches\/src\/main\/java\/trnt\/sheepsketches\/screens\/GradientShaderScreen.kt#L101\"><code>noodleZoom<\/code><\/a> shader in <b>GradientShaderScreen.kt<\/b>, originally from Twitter user <a href=\"https:\/\/twitter.com\/notargs\/status\/1250468645030858753\">@notargs<\/a>, creates an <a href=\"https:\/\/user-images.githubusercontent.com\/2978958\/198214361-e9ecd2af-a395-404d-85c4-e6a5e81dfc60.mp4\">awesome zooming web-like effect<\/a> that I think would look pretty cool behind our flowers. But it\u2019s not green! So, let\u2019s try using our RGB and trig knowledge again to change the original shader code, which is shown here:\n<\/p>\n<pre>  uniform float2 iResolution;\r\n  uniform float iTime;\r\n    \/\/ Source: @notargs https:\/\/twitter.com\/notargs\/status\/1250468645030858753\r\n    float f(vec3 p) {\r\n       p.z -= iTime * 10.;\r\n       float a = p.z * .1;\r\n       p.xy *= mat2(cos(a), sin(a), -sin(a), cos(a));\r\n       return .1 - length(cos(p.xy) + sin(p.yz));\r\n    }\r\n          \r\n    half4 main(vec2 fragcoord) { \r\n       vec3 d = .5 - fragcoord.xy1 \/ iResolution.y;\r\n       vec3 p=vec3(0);\r\n       for (int i = 0; i &lt; 32; i++) {\r\n          p += f(p) * d;\r\n       }\r\n       return ((sin(p) + vec3(2, 5, 12)) \/ length(p)).xyz1;<\/pre>\n<p>\n  This, the RGB values are determined by the <code>vec3(2, 5, 12)<\/code> in the return statement. The brightness of the color also depends on this vector, so we\u2019ll also want to make sure we don\u2019t make the values too high or low. After some experimenting in the shader playground again, I settled on <code>vec3(0.95, 3.725, 2.05)<\/code>. Here\u2019s how the final iteration of our garden looks: \n<\/p>\n<p>\n  <img decoding=\"async\" width=\"800\" height=\"504\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2023\/05\/video-to-gif-output-image-5.gif\" class=\"wp-image-3254\" alt=\"[video-to-gif output image]\" \/>\n<\/p>\n<h2>Resources and feedback<\/h2>\n<p>\n  The content covered today is part of <a href=\"https:\/\/github.com\/khalp\/animated-garden\/pull\/3\">PR #3<\/a> in the <a href=\"https:\/\/github.com\/khalp\/animated-garden\">animated-garden repo<\/a>. \n<\/p>\n<p>\n  To learn more about Jetpack Compose animations and creative coding, check out these resources:\n<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/nicole-terc\/composable-sheep\">nicole-terc\/composable-sheep (github.com)<\/a>\n  <\/li>\n<li><a href=\"https:\/\/github.com\/drinkthestars\/composable-sheep-sketches\">drinkthestars\/composable-sheep-sketches: Funky composable sheep \ud83d\ude0e \ud83d\udc0f (github.com)<\/a>\n  <\/li>\n<li><a href=\"https:\/\/www.droidcon.com\/2022\/08\/01\/composable-sheep-a-compose-animations-journey\/\">Composable Sheep &#8211; A Compose Animations Journey<\/a>\n  <\/li>\n<li><a href=\"https:\/\/www.droidcon.com\/2022\/11\/15\/composable-sheep-the-creative-coding-epilogue\/\">Composable Sheep &#8211; The Creative Coding Epilogue<\/a>\n  <\/li>\n<li><a href=\"https:\/\/developer.android.com\/jetpack\/compose\/graphics\/draw\/overview\">Graphics in Jetpack Compose<\/a>\n  <\/li>\n<li><a href=\"https:\/\/developer.android.com\/jetpack\/compose\/animation\">Animations in Jetpack Compose<\/a>\n  <\/li>\n<li><a href=\"https:\/\/developer.android.com\/jetpack\/compose\/animation\/customize\">Customize animations in Jetpack Compose<\/a>\n  <\/li>\n<li><a href=\"https:\/\/developer.android.com\/jetpack\/compose\/graphics\/draw\/brush#agsl-runtimeshader\">Android Brush: Gradients and Shaders<\/a>\n  <\/li>\n<li><a href=\"https:\/\/shaders.skia.org\/\">Skia Shaders Playground<\/a>\n  <\/li>\n<li><a href=\"https:\/\/developer.android.com\/develop\/ui\/views\/graphics\/agsl\/using-agsl#using_runtimeshader_with_jetpack_compose\">AGSL with Jetpack Compose<\/a>\n  <\/li>\n<li><a href=\"https:\/\/www.pushing-pixels.org\/2021\/09\/22\/skia-shaders-in-compose-desktop.html\">Skia shaders in Compose desktop<\/a>\n  <\/li>\n<\/ul>\n<p>\n  If you have any questions, use the <a href=\"http:\/\/aka.ms\/SurfaceDuoSDK-Feedback\">feedback forum<\/a> or message us on <a href=\"https:\/\/twitter.com\/surfaceduodev\">Twitter @surfaceduodev<\/a>.\n<\/p>\n<p>\n  Since this is the end of the animated garden series, we will be livestreaming this week! You can also check out the <a href=\"https:\/\/youtube.com\/c\/surfaceduodev\">archives on YouTube<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello Jetpack Compose developers, Today we\u2019ll be finishing up our blog series on animations in Jetpack Compose! This content was inspired by Nicole Terc\u2019s Composable Sheep talk from droidcon NYC. Over the past two weeks, we covered some basics graphics, animation canvases, and basic animations. This week, we\u2019ll polish up our garden with some more [&hellip;]<\/p>\n","protected":false},"author":72597,"featured_media":3253,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[736,719,692],"class_list":["post-3248","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-surface-duo-sdk","tag-animation","tag-droidcon","tag-jetpack-compose"],"acf":[],"blog_post_summary":"<p>Hello Jetpack Compose developers, Today we\u2019ll be finishing up our blog series on animations in Jetpack Compose! This content was inspired by Nicole Terc\u2019s Composable Sheep talk from droidcon NYC. Over the past two weeks, we covered some basics graphics, animation canvases, and basic animations. This week, we\u2019ll polish up our garden with some more [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/3248","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/users\/72597"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/comments?post=3248"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/3248\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media\/3253"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media?parent=3248"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/categories?post=3248"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/tags?post=3248"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}