{"id":3043,"date":"2024-01-26T06:00:00","date_gmt":"2024-01-26T14:00:00","guid":{"rendered":"https:\/\/rose.dev\/blog\/?p=3043"},"modified":"2024-02-07T02:36:44","modified_gmt":"2024-02-07T10:36:44","slug":"unity-shaders-intro-part-2-hlsl-cg-creating-cult-of-the-lamb-like-ui-distortion-effects","status":"publish","type":"post","link":"https:\/\/rose.dev\/blog\/2024\/01\/26\/unity-shaders-intro-part-2-hlsl-cg-creating-cult-of-the-lamb-like-ui-distortion-effects\/","title":{"rendered":"Unity Shaders Intro Part 2: HLSL\/CG | Edge Distortion Effects"},"content":{"rendered":"\n<p>I recently saw these UI effects in a game called <em>Cult of the Lamb<\/em> and they were very satisfying to watch. Let&#8217;s learn how to create our own types of effects like these. <\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/edgedistortioncotl.mp4\" playsinline><\/video><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/crowndistortioncotl.mp4\" playsinline><\/video><\/figure>\n<\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Unity (I&#8217;m using <em>2022.3.17f<\/em>)<\/li>\n\n\n\n<li>Photo editing software (Aseprite, Photoshop, etc)<\/li>\n\n\n\n<li>Seamless <a href=\"https:\/\/gen3vra.github.io\/perlinnoisegenerator\/\" target=\"_blank\" rel=\"noreferrer noopener\">perlin noise generator<\/a> for the noise texture we will need later<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Base 2D Shader<\/h2>\n\n\n\n<p>Create a basic empty file with the &#8216;.shader&#8217; extension in your Unity project <em>or<\/em> Right click &gt; Shader &gt; Standard Surface Shader<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">Shader \"Custom\/EdgeShader\" \n{\n\tProperties \n\t{\n\t}\n\t\n\tSubShader\n\t{\t\t\n\t\tPass \n\t\t{\n\t\t\tCGPROGRAM\n\t\t\tENDCG\n\t\t}\n\t}\n}\n<\/code><\/pre>\n\n\n\n<p>We want to begin with a base shader to manipulate, so let&#8217;s start by displaying a sprite.<\/p>\n\n\n\n<p>Our shader must expose it to the editor in order to set our texture. Add a line under our properties defining a main texture.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"properties\" class=\"language-properties\">_MainTex (\"Base (RGB) Trans (A)\", 2D) = \"white\" {}<\/code><\/pre>\n\n\n\n<p>And the variable under SubShader.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"properties\" class=\"language-properties\">sampler2D _MainTex;\nfloat4 _MainTex_ST;\n<\/code><\/pre>\n\n\n\n<p>The _ST value will contain the tiling and offset fields for the material texture properties. This information is passed into our shader in the format we specified.<\/p>\n\n\n\n<p>Now define the vertex and fragment functions. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">struct vct \n{\n\tfloat4 pos : SV_POSITION;\n\tfloat2 uv : TEXCOORD0;\n};\n\nvct vert_vct (appdata_base v) \n{\n\tvct o;\n\to.pos = UnityObjectToClipPos(v.vertex);\n\to.uv = TRANSFORM_TEX(v.texcoord, _MainTex);\n\treturn o;\n}\n\nfixed4 frag_mult (vct i) : COLOR \n{\n\tfixed4 col = tex2D(_MainTex, i.uv);\n\tcol.rgb = col.rgb * col.a;\n\treturn col;\n}<\/code><\/pre>\n\n\n\n<p>Simple enough.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"625\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" src=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/shaderb-1024x625.png\" alt=\"\" class=\"wp-image-3064\" srcset=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/shaderb-1024x625.png 1024w, https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/shaderb-300x183.png 300w, https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/shaderb-768x469.png 768w, https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/shaderb.png 1233w\" \/><\/figure>\n\n\n\n<p>&#8230;or is it? That doesn&#8217;t look like it&#8217;s working properly. Let&#8217;s fix it.<\/p>\n\n\n\n<p>We can add a Blend under our tags to fix the transparency issue.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"properties\" class=\"language-properties\">Blend SrcAlpha OneMinusSrcAlpha<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"431\" height=\"431\" sizes=\"auto, (max-width: 431px) 100vw, 431px\" src=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/transpfix.png\" alt=\"\" class=\"wp-image-3073\" srcset=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/transpfix.png 431w, https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/transpfix-300x300.png 300w, https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/transpfix-150x150.png 150w\" \/><\/figure>\n\n\n\n<p>And we can just add the color property to our shader. At this point, we can display 2D sprites on the screen, yay!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">Shader \"Custom\/EdgeShaderB\" \n{\n    Properties \n    {\n        _MainTex (\"Base (RGB) Trans (A)\", 2D) = \"white\" {}\n    }\n    \n    SubShader\n    {\t\t\n        Tags {\"Queue\"=\"Transparent\" \"IgnoreProjector\"=\"True\" \"RenderType\"=\"Transparent\"}\n        Blend SrcAlpha OneMinusSrcAlpha\n        \n        Pass \n        {\n            CGPROGRAM\n            #pragma vertex vert_vct\n            #pragma fragment frag_mult \n            #include \"UnityCG.cginc\"\n\n            sampler2D _MainTex;\n            float4 _MainTex_ST;\n            \n            struct vct \n            {\n                float4 vertex : POSITION;\n                fixed4 color : COLOR;\n                float2 texcoord : TEXCOORD0;\n            };\n\n            vct vert_vct(vct v)\n            {\n                vct o;\n                o.vertex = UnityObjectToClipPos(v.vertex);\n                o.color = v.color;\n                o.texcoord = v.texcoord;\n                return o;\n            }\n\n            fixed4 frag_mult (vct i) : COLOR\n            {\n                fixed4 col = tex2D(_MainTex, i.texcoord) * i.color;\n                return col;\n            }\n\n            ENDCG\n        }\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>Now we can start messing with things.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Edge Distortion Shader<\/h2>\n\n\n\n<p>We want to add some movement and distortion to our sprite. Begin with movement.<\/p>\n\n\n\n<p>How can we manipulate our shader pixels? Let&#8217;s show an example by modifying our main texture. We&#8217;ll simply change the position. To do so, we can do something simple like shifting the texture coordinate down and to the left.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">fixed4 frag_mult (vct i) : COLOR\n{\n\tfloat2 shift = i.texcoord + float2(0.15, 0.25);\n\tfixed4 col = tex2D(_MainTex, shift) * i.color;\n\n\treturn col;\n}<\/code><\/pre>\n\n\n\n<p>Okay, now how about some movement?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">fixed4 frag_mult (vct i) : COLOR\n{\n\tfloat2 shift = i.texcoord + float2(cos(_Time.x * 2.0) * 0.2, sin(_Time.x * 2.0) * 0.2);\n\tfixed4 col = tex2D(_MainTex, shift) * i.color;\n\n\treturn col;\n}<\/code><\/pre>\n\n\n\n<p>If you examine your sprite at this point, you may notice some odd distortion as it moves.<\/p>\n\n\n\n<p class=\"has-blue-gray-background-color has-background\"><strong>Set your sprite&#8217;s import settings correctly!<\/strong><br>Mesh Type: Full Rect<br>Wrap Mode: Repeat<\/p>\n\n\n\n<p>Once you ensure your sprite has the correct import settings, it&#8217;s time to introduce our final 2d sprite we want to manipulate with the shader to achieve our effect.<\/p>\n\n\n\n<p>This image will greatly change the shader appearance, and you should try different gradients and patterns. Here&#8217;s my image scaled up:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"603\" height=\"603\" sizes=\"auto, (max-width: 603px) 100vw, 603px\" src=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/shaderspritescaledup.png\" alt=\"\" class=\"wp-image-3184\" style=\"width:200px\" srcset=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/shaderspritescaledup.png 603w, https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/shaderspritescaledup-300x300.png 300w, https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/shaderspritescaledup-150x150.png 150w\" \/><\/figure>\n\n\n\n<p>But I recommend using the smallest resolution that looks good for your project due to memory and performance.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"12\" height=\"12\" sizes=\"auto, (max-width: 12px) 100vw, 12px\" src=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/shadermanipsprite.png\" alt=\"\" class=\"wp-image-3123\"\/><figcaption class=\"wp-element-caption\">yes it&#8217;s that small (12&#215;12)<\/figcaption><\/figure>\n\n\n\n<p>We also need a <strong>seamless <\/strong>noise texture, for the distortion.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"256\" height=\"256\" sizes=\"auto, (max-width: 256px) 100vw, 256px\" src=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/perlintex.png\" alt=\"\" class=\"wp-image-3109\" srcset=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/perlintex.png 256w, https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/perlintex-150x150.png 150w\" \/><\/figure>\n\n\n\n<p>Let&#8217;s add another variable for it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"properties\" class=\"language-properties\">_NoiseTex (\"Base (RGB) Trans (A)\", 2D) = \"white\" {}<\/code><\/pre>\n\n\n\n<p>Once we&#8217;ve assigned our noise texture, it&#8217;s time to start moving it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">fixed4 frag_mult (vct i) : COLOR\n{\n\tfloat2 shim = i.texcoord + float2(\n\t\ttex2D(_NoiseTex, i.vertex.xy\/500 - float2(_Time.w\/60, 0)).x,\n\t\ttex2D(_NoiseTex, i.vertex.xy\/500 - float2(0, _Time.w\/60)).y\n\t);\n\tfixed4 col = tex2D(_MainTex, shim) * i.color;\n\treturn col;\n}<\/code><\/pre>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:20%\">\n<figure class=\"wp-block-video\"><video controls loop src=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/edgedistortion-1.mp4\" playsinline><\/video><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p>Now, add the static sprite to its left in the same color and connect it vertically.<\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:20%\">\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/finaledgeshaderpreview.mp4\" playsinline><\/video><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p>Adjusting the transparency will function as expected, so we could overlay this.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">Shader \"Custom\/EdgeShader\" \n{\n    Properties \n    {\n        _MainTex (\"Base (RGB) Trans (A)\", 2D) = \"white\" {}\n        _NoiseTex (\"Base (RGB) Trans (A)\", 2D) = \"white\" {}\n    }\n    \n    SubShader\n    {\t\t\n        Tags {\"Queue\"=\"Transparent\" \"IgnoreProjector\"=\"True\" \"RenderType\"=\"Transparent\"}\n        Blend SrcAlpha OneMinusSrcAlpha \n        \n        Pass \n        {\n            CGPROGRAM\n            #pragma vertex vert_vct\n            #pragma fragment frag_mult \n            #include \"UnityCG.cginc\"\n\n            sampler2D _MainTex;\n            sampler2D _NoiseTex;\n            float4 _MainTex_ST;\n            float4 _NoiseTex_ST;\n            \n            struct vct \n            {\n                float4 vertex : POSITION;\n                fixed4 color : COLOR;\n                float2 texcoord : TEXCOORD0;\n            };\n\n            vct vert_vct(vct v)\n            {\n                vct o;\n                o.vertex = UnityObjectToClipPos(v.vertex);\n                o.color = v.color;\n                o.texcoord = v.texcoord;\n                return o;\n            }\n\n            fixed4 frag_mult (vct i) : COLOR\n            {\n                    float2 shim = i.texcoord + \n                float2(tex2D(_NoiseTex, i.vertex.xy\/500 - float2(_Time.w\/60, 0)).x,\n                tex2D(_NoiseTex, i.vertex.xy\/500 - float2(0, _Time.w\/60)).y);\n                fixed4 col = tex2D(_MainTex, shim) * i.color;\n                return col;\n            }\n\n            ENDCG\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Crown Shader<\/h2>\n\n\n\n<p>Here&#8217;s my quick little crown sprite.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"250\" height=\"250\" sizes=\"auto, (max-width: 250px) 100vw, 250px\" src=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/dahcrown.png\" alt=\"\" class=\"wp-image-3222\" srcset=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/dahcrown.png 250w, https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/dahcrown-150x150.png 150w\" \/><\/figure>\n\n\n\n<p>Let&#8217;s make it evil.<\/p>\n\n\n\n<p>We can repurpose the wall shader we just created and scale down the distortion as well as smoothing it<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">fixed4 frag_mult(v2f_vct i) : COLOR\n{\n    float2 shim = i.texcoord + float2(\n        tex2D(_NoiseTex, i.vertex.xy\/250 - float2(_Time.w\/7.2, 0)).x,\n        tex2D(_NoiseTex, i.vertex.xy\/250 - float2(0, _Time.w\/7.2)).y\n    )\/ 20;\n\n    fixed4 col = tex2D(_MainTex, col) * i.color;\n\n    return col;\n}<\/code><\/pre>\n\n\n\n<p>Then we can add another pass to handle the normal sprite display.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">Shader \"Custom\/CrownShader\" \n{\n    Properties \n    {\n        _MainTex (\"Base (RGB) Trans (A)\", 2D) = \"white\" {}\n        _NoiseTex (\"Base (RGB) Trans (A)\", 2D) = \"white\" {}\n        _SpriteColor (\"Color Tint Mult\", Color) = (1,1,1,1)\n    }\n    \n    SubShader\n    {\n        Tags {\"Queue\"=\"Transparent\" \"IgnoreProjector\"=\"True\" \"RenderType\"=\"Transparent\"}\n        Blend SrcAlpha OneMinusSrcAlpha\n        \n        Pass \n        {\n            CGPROGRAM\n            #pragma vertex vert_vct\n            #pragma fragment frag_mult \n            #pragma fragmentoption ARB_precision_hint_fastest\n            #include \"UnityCG.cginc\"\n\n            sampler2D _MainTex;\n            sampler2D _NoiseTex;\n            float4 _MainTex_ST;\n            float4 _NoiseTex_ST;\n\n            struct vct\n            {\n                float4 vertex : POSITION;\n                float4 color : COLOR;\n                float2 texcoord : TEXCOORD0;\n            };\n\n            vct vert_vct(vct v)\n            {\n                vct o;\n                o.vertex = UnityObjectToClipPos(v.vertex);\n                o.color = v.color;\n                o.texcoord = v.texcoord;\n                return o;\n            }\n\n            fixed4 frag_mult(vct i) : COLOR\n            {\n                float2 shim = i.texcoord + float2(\n                    tex2D(_NoiseTex, i.vertex.xy\/250 - float2(_Time.w\/7.2, 0)).x,\n                    tex2D(_NoiseTex, i.vertex.xy\/250 - float2(0, _Time.w\/7.2)).y\n                )\/ 20;\n\n                shim *= float2(0.97, 0.91);\n                shim -= float2(0.01, 0);\n\n                fixed4 col = tex2D(_MainTex, shim) * i.color;\n                return col;\n            }\n            \n            ENDCG\n        } \n        Pass \n        {\n            CGPROGRAM\n            #pragma vertex vert_vct\n            #pragma fragment frag_mult \n            #pragma fragmentoption ARB_precision_hint_fastest\n            #include \"UnityCG.cginc\"\n\n            sampler2D _MainTex;\n            sampler2D _NoiseTex;\n            float4 _MainTex_ST;\n            float4 _NoiseTex_ST;\n\n            float4 _SpriteColor;\n\n            struct vct \n            {\n                float4 vertex : POSITION;\n                float4 color : COLOR;\n                float2 texcoord : TEXCOORD0;\n            };\n\n            vct vert_vct(vct v)\n            {\n                vct o;\n                o.vertex = UnityObjectToClipPos(v.vertex);\n                o.color = v.color;\n                o.texcoord = v.texcoord;\n                return o;\n            }\n\n            fixed4 frag_mult(vct i) : COLOR\n            {\n                float2 uv = i.texcoord;\n                uv -= 0.5;\n                uv *= 1.1;\n                uv += 0.5;\n\n                fixed4 col = tex2D(_MainTex, uv);\n                col.rgb = _SpriteColor.rgb;\n\n                return col;\n            }\n            \n            ENDCG\n        } \n    }\n}\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<figure class=\"wp-block-video\"><video controls loop src=\"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/shaderfinalpreview.mp4\" playsinline><\/video><\/figure>\n\n\n\n<p><a href=\"https:\/\/github.com\/gen3vra\/slashdot\" target=\"_blank\" rel=\"noreferrer noopener\">Source<\/a><\/p>\n<hr>\r\nIt helps me if you share this post\r\n<br\/>\r\n<br\/>\r\nPublished 2024-01-26 06:00:00 ","protected":false},"excerpt":{"rendered":"<p>Learn how to create Unity shader effects with hlsl\/cg. Unity shader developer blog post for edge distortion effects. Cult of the Lamb like user interface shader distortion screen UI basic tutorial.<\/p>\n","protected":false},"author":1,"featured_media":3221,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":""},"categories":[835,832,833],"tags":[1220,1225,1227,1102,1231,1217,1216,1229,1228,1201,1223,1222,1211,1230,1219,1204,1232,917,3],"class_list":["post-3043","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-misc","category-software","category-technology","tag-aseprite","tag-cgprogram","tag-cgshaders","tag-coding","tag-cos","tag-cotl","tag-cult-of-the-lamb","tag-edge","tag-edge-distortion","tag-game-development","tag-hlsl","tag-intro","tag-masking","tag-noise","tag-shader-development","tag-shaders","tag-sine","tag-time","tag-unity"],"jetpack_featured_media_url":"https:\/\/rose.dev\/blog\/wp-content\/uploads\/2024\/01\/distortionbannerpreview.png","_links":{"self":[{"href":"https:\/\/rose.dev\/blog\/wp-json\/wp\/v2\/posts\/3043","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rose.dev\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rose.dev\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rose.dev\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rose.dev\/blog\/wp-json\/wp\/v2\/comments?post=3043"}],"version-history":[{"count":146,"href":"https:\/\/rose.dev\/blog\/wp-json\/wp\/v2\/posts\/3043\/revisions"}],"predecessor-version":[{"id":3295,"href":"https:\/\/rose.dev\/blog\/wp-json\/wp\/v2\/posts\/3043\/revisions\/3295"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rose.dev\/blog\/wp-json\/wp\/v2\/media\/3221"}],"wp:attachment":[{"href":"https:\/\/rose.dev\/blog\/wp-json\/wp\/v2\/media?parent=3043"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rose.dev\/blog\/wp-json\/wp\/v2\/categories?post=3043"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rose.dev\/blog\/wp-json\/wp\/v2\/tags?post=3043"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}