{"id":6767,"date":"2022-12-14T21:42:36","date_gmt":"2022-12-15T05:42:36","guid":{"rendered":"https:\/\/cloudfour.com\/?p=6767"},"modified":"2022-12-15T10:33:22","modified_gmt":"2022-12-15T18:33:22","slug":"coding-a-snowflake-generator","status":"publish","type":"post","link":"https:\/\/cloudfour.com\/thinks\/coding-a-snowflake-generator\/","title":{"rendered":"Coding a Snowflake Generator"},"content":{"rendered":"\n<p>After a nice tromp through the snow last Sunday, I started to wonder if I could procedurally generate random snowflakes. After a little while coding by the window with a hot mug of coffee, I was pretty pleased with the results:<\/p>\n\n\n\n<iframe style=\"width: 100%;\" scrolling=\"no\" title=\"Animated Snowflake (Generative)\" src=\"https:\/\/codepen.io\/phebert\/embed\/KKeJmRw?default-tab=result&amp;theme-id=light\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\" height=\"565\" frameborder=\"no\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/KKeJmRw\">\n  Animated Snowflake (Generative)<\/a> by Paul Hebert (<a href=\"https:\/\/codepen.io\/phebert\">@phebert<\/a>)\n  on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.\n<\/iframe>\n\n\n\n<p>In this article, I&#8217;ll walk you through hand-coding an SVG snowflake, let you <a href=\"https:\/\/codepen.io\/phebert\/pen\/eYKXLqo\">customize your own snowflake in an interactive playground<\/a>, and show how a dash of JavaScript can help you generate infinite variations.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Beauty of Symmetry<\/h2>\n\n\n\n<p>One of the things that make snowflakes so beautiful is their symmetry. Each snowflake is composed of several symmetrical &#8220;trees&#8221; that are rotated around a circle. Knowing this, we can draw a snowflake in three steps:<\/p>\n\n\n\n<iframe style=\"width: 100%;\" scrolling=\"no\" title=\"Generative Snowflakes (Steps)\" src=\"https:\/\/codepen.io\/phebert\/embed\/jOKdowo?default-tab=result&amp;theme-id=light\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\" height=\"361\" frameborder=\"no\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/jOKdowo\">\n  Generative Snowflakes (Steps)<\/a> by Paul Hebert (<a href=\"https:\/\/codepen.io\/phebert\">@phebert<\/a>)\n  on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.\n<\/iframe>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Draw half a tree.<\/li>\n\n\n\n<li>Copy the half tree to make a full tree.<\/li>\n\n\n\n<li>Copy and rotate the tree around a center point several times.<\/li>\n<\/ol>\n\n\n\n<p>These three steps can be repeated to generate a nearly infinite number of unique snowflakes:<\/p>\n\n\n\n<iframe style=\"width: 100%;\" scrolling=\"no\" title=\"Animated Snowflake ()\" src=\"https:\/\/codepen.io\/phebert\/embed\/jOKXepb?default-tab=result&amp;theme-id=light\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\" height=\"565\" frameborder=\"no\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/jOKXepb\">\n  Animated Snowflake ()<\/a> by Paul Hebert (<a href=\"https:\/\/codepen.io\/phebert\">@phebert<\/a>)\n  on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.\n<\/iframe>\n\n\n\n<h2 class=\"wp-block-heading\">Hand-coding a snowflake<\/h2>\n\n\n\n<p>Before generating random snowflakes, we need to understand the code used to draw a snowflake. There are a few different ways to code graphics on the web. For our snowflakes, we&#8217;ll be using SVG since the syntax is similar to HTML, and they can be styled with CSS.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Setting up our canvas<\/h3>\n\n\n\n<p>First, we need to set up a canvas for our drawing. In our case, this is an SVG wrapper element:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">svg<\/span> \n  <span class=\"hljs-attr\">viewBox<\/span>=<span class=\"hljs-string\">\"0 0 100 100\"<\/span> \n  <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"100\"<\/span> \n  <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">\"100\"<\/span> \n  <span class=\"hljs-attr\">role<\/span>=<span class=\"hljs-string\">\"img\"<\/span>\n&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">title<\/span>&gt;<\/span>A Snowflake<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">title<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">g<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"snowflake\"<\/span>\n    &lt;!<span class=\"hljs-attr\">--<\/span> \n      <span class=\"hljs-attr\">Our<\/span> <span class=\"hljs-attr\">graphics<\/span> <span class=\"hljs-attr\">code<\/span> <span class=\"hljs-attr\">goes<\/span> <span class=\"hljs-attr\">here<\/span> \n    <span class=\"hljs-attr\">--<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">g<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">svg<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>This SVG will house all of our graphics. There are a few things to note:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Our <code>viewBox<\/code> describes the coordinate grid for our graphic. Everything we draw will be drawn on a 100-unit square grid.<\/li>\n\n\n\n<li><code>role=\"img\"<\/code> tells browsers to treat <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Accessibility\/ARIA\/Roles\/img_role#svg_and_roleimg\">the entire SVG as a single image<\/a> instead of exposing each inner element to assistive technologies.<\/li>\n\n\n\n<li>The <code>&lt;title&gt;<\/code> element describes the image to assistive technologies and search engines.<\/li>\n\n\n\n<li>Our graphics will be housed in a <code>&lt;g&gt;<\/code> <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/SVG\/Element\/g\">(group) element<\/a>. (This isn&#8217;t necessary, but will make it easier to dynamically update our snowflakes later.)<\/li>\n<\/ul>\n\n\n\n<p>While we&#8217;re at it, let&#8217;s give our SVG a background color with some CSS:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-comment\">\/* Give our SVG wrapper a blue background *\/<\/span>\n<span class=\"hljs-selector-tag\">svg<\/span> {\n  <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-built_in\">hsl<\/span>(<span class=\"hljs-number\">200<\/span>, <span class=\"hljs-number\">50%<\/span>, <span class=\"hljs-number\">50%<\/span>);\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Drawing half a &#8220;tree&#8221;<\/h3>\n\n\n\n<p>For our first step, we need to draw a handful of lines. Luckily SVG has a <code>&lt;line&gt;<\/code> element that does just what we need:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">line<\/span> <span class=\"hljs-attr\">x1<\/span>=<span class=\"hljs-string\">\"50\"<\/span> <span class=\"hljs-attr\">y1<\/span>=<span class=\"hljs-string\">\"50\"<\/span> <span class=\"hljs-attr\">x2<\/span>=<span class=\"hljs-string\">\"50\"<\/span> <span class=\"hljs-attr\">y2<\/span>=<span class=\"hljs-string\">\"10\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"trunk\"<\/span> \/&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>The <code>&lt;line&gt;<\/code> attribute draws a line between two points along an <code>x<\/code>\/<code>y<\/code> grid. The first point is defined by the <code>x1<\/code> and <code>y1<\/code> attributes. The second point is defined by the <code>x2<\/code> and <code>y2<\/code> attributes.<br><br>The line above will work for the &#8220;trunk&#8221; of our tree. It goes from the center of the grid (<code>50<\/code>\/<code>50<\/code>), straight up to 10 units below the top of our grid (<code>50,10<\/code>).<\/p>\n\n\n\n<p class=\"has-gray-lighter-background-color has-background\">Note: SVG strokes are centered along their paths, so this stroke will be perfectly centered. The stroke will be painted between <code>49.5<\/code> and <code>50.5<\/code> on our horizontal grid axis.<\/p>\n\n\n\n<p>Next, we need to add some &#8220;branches.&#8221; These will start touching our &#8220;trunk&#8221; and then branch up and to the left:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-comment\">&lt;!-- Start 10 above center. Move 5 left and 5 up --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">line<\/span> <span class=\"hljs-attr\">x1<\/span>=<span class=\"hljs-string\">\"50\"<\/span> <span class=\"hljs-attr\">y1<\/span>=<span class=\"hljs-string\">\"40\"<\/span> <span class=\"hljs-attr\">x2<\/span>=<span class=\"hljs-string\">\"45\"<\/span> <span class=\"hljs-attr\">y2<\/span>=<span class=\"hljs-string\">\"35\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"branch\"<\/span> \/&gt;<\/span>\n<span class=\"hljs-comment\">&lt;!-- Start 20 above center. Move 10 left and 10 up --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">line<\/span> <span class=\"hljs-attr\">x1<\/span>=<span class=\"hljs-string\">\"50\"<\/span> <span class=\"hljs-attr\">y1<\/span>=<span class=\"hljs-string\">\"30\"<\/span> <span class=\"hljs-attr\">x2<\/span>=<span class=\"hljs-string\">\"40\"<\/span> <span class=\"hljs-attr\">y2<\/span>=<span class=\"hljs-string\">\"20\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"branch\"<\/span> \/&gt;<\/span>\n<span class=\"hljs-comment\">&lt;!-- Start 35 above center. Move 8 left and 8 up --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">line<\/span> <span class=\"hljs-attr\">x1<\/span>=<span class=\"hljs-string\">\"50\"<\/span> <span class=\"hljs-attr\">y1<\/span>=<span class=\"hljs-string\">\"15\"<\/span> <span class=\"hljs-attr\">x2<\/span>=<span class=\"hljs-string\">\"42\"<\/span> <span class=\"hljs-attr\">y2<\/span>=<span class=\"hljs-string\">\"7\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"branch\"<\/span> \/&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>You&#8217;ll notice that each of our branches starts touching our branch (<code>x1=\"50\"<\/code>) and then moves up and to the left.<\/p>\n\n\n\n<p>We&#8217;ll also add a few CSS rules to style our lines:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">line<\/span> {\n  <span class=\"hljs-comment\">\/* Make all of our snowflake lines white *\/<\/span>\n  <span class=\"hljs-attribute\">stroke<\/span>: <span class=\"hljs-number\">#fff<\/span>;\n  <span class=\"hljs-comment\">\/* Round our lines' endpoints *\/<\/span>\n  <span class=\"hljs-attribute\">stroke-linecap<\/span>: round;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>Alright, we&#8217;re getting somewhere! We&#8217;ve got our &#8220;half tree.&#8221; Try tweaking the sliders below to see how a different trunk length or branch settings affects our snowflake and our SVG code:<\/p>\n\n\n\n<iframe style=\"width: 100%;\" scrolling=\"no\" title=\"Half Tree\" src=\"https:\/\/codepen.io\/phebert\/embed\/QWxobbJ?default-tab=result&amp;theme-id=light\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\" height=\"764\" frameborder=\"no\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/QWxobbJ\">\n  Half Tree<\/a> by Paul Hebert (<a href=\"https:\/\/codepen.io\/phebert\">@phebert<\/a>)\n  on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.\n<\/iframe>\n\n\n\n<h3 class=\"wp-block-heading\">Completing our &#8220;tree&#8221;<\/h3>\n\n\n\n<p>Now we&#8217;ve got half a tree, but we need to add the other half. There are a few ways we could do this:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>We could add more lines moving the other direction. <\/li>\n\n\n\n<li>We could copy and paste our lines and then use CSS or SVG transformations to flip them horizontally.<\/li>\n<\/ul>\n\n\n\n<p>But, both of these options would lead to a lot of long and repetitive code, which could be hard to maintain. Luckily, there&#8217;s an SVG <code>&lt;use&gt;<\/code> element that allows us to clone and tweak chunks of SVG code. Here&#8217;s an example of how we can reuse our half-tree:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">g<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"branches\"<\/span>&gt;<\/span>\n  <span class=\"hljs-comment\">&lt;!-- \n    Move our branch `&lt;line&gt;` elements \n    inside of a group so we can \n    reference them together.\n  --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">g<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">use<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"#branches\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"flipped-branches\"<\/span>\/&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>Note how the branches group and <code>use<\/code> element are linked by the <code>branches<\/code> ID. We&#8217;ve added a class to our <code>&lt;use&gt;<\/code> element so we can add styles to the copied branches. We&#8217;ll use the CSS <code>scale<\/code> property to flip our branches horizontally.<\/p>\n\n\n\n<p>The <code>scale<\/code> property allows us to stretch and squish an element. <code>scale<\/code> takes two values: a horizontal scale value and a vertical scale value. One funny aspect of <code>scale<\/code> is that if you scale an element to a negative value, it will be flipped instead of squished. We can use <code>-1 1<\/code> to flip our cloned branches:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.flipped-branches<\/span> {\n  <span class=\"hljs-attribute\">scale<\/span>: -<span class=\"hljs-number\">1<\/span> <span class=\"hljs-number\">1<\/span>;\n  <span class=\"hljs-attribute\">transform-origin<\/span>: center;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>You may have noticed we also set a <code>transform-origin<\/code> property in addition to <code>scale<\/code>. This tells our branches to flip relative to the center of our SVG container.<\/p>\n\n\n\n<p>Try using the &#8220;Branch Translation&#8221; slider below and see how it affects the flipped branches.<\/p>\n\n\n\n<iframe style=\"width: 100%;\" scrolling=\"no\" title=\"Full Tree\" src=\"https:\/\/codepen.io\/phebert\/embed\/YzvgjrR?default-tab=result&amp;theme-id=light\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\" height=\"764\" frameborder=\"no\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/YzvgjrR\">\n  Ful Tree<\/a> by Paul Hebert (<a href=\"https:\/\/codepen.io\/phebert\">@phebert<\/a>)\n  on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.\n<\/iframe>\n\n\n\n<h3 class=\"wp-block-heading\">Copying and rotating our &#8220;tree&#8221;<\/h3>\n\n\n\n<p>Now we&#8217;ve got one of our &#8220;trees&#8221; coded, but to get that fun snowflake effect, we&#8217;ll need to copy it several times and rotate each copy around a center point like the spokes on a bike wheel. Our friend <code>&lt;use&gt;<\/code> will help us streamline this:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">g<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"tree\"<\/span>&gt;<\/span> \n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">g<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"branches\"<\/span>&gt;<\/span>\n    <span class=\"hljs-comment\">&lt;!-- Our branches go here --&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">g<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">use<\/span> \n    <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"#branches\"<\/span> \n    <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"flipped-branches\"<\/span> \n  \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">g<\/span>&gt;<\/span>\n\n<span class=\"hljs-comment\">&lt;!-- Copy our tree --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">use<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"#tree\"<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"--index: 1;\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"rotated-tree\"<\/span> \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">use<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"#tree\"<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"--index: 2;\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"rotated-tree\"<\/span> \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">use<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"#tree\"<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"--index: 3;\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"rotated-tree\"<\/span> \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">use<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"#tree\"<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"--index: 4;\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"rotated-tree\"<\/span> \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">use<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"#tree\"<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"--index: 5;\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"rotated-tree\"<\/span> \/&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>You can see we&#8217;re using the same strategy we used to copy our branches, but this time we&#8217;re copying the entire tree five times. You may have also noticed that we&#8217;re giving each copy of the tree an <code>--index<\/code> custom property. We can use this custom property in our CSS to give each copy a different rotation around our center point:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.rotated-tree<\/span> {\n  <span class=\"hljs-attribute\">rotate<\/span>: <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">60deg<\/span> * var(--index));\n  <span class=\"hljs-attribute\">transform-origin<\/span>: center;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>Since we have six trees (our original tree and five copies), we need to rotate each copy by 60 degrees (360&nbsp;degrees divided by&nbsp;6&nbsp;trees) to space them evenly around our wheel.<\/p>\n\n\n\n<p>If we had a different number of trees, we&#8217;d need to use a different number than 60 degrees. We can use another custom property and a little math to determine the degrees of rotation dynamically:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">g<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"--tree-count: 6\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"snowflake\"<\/span>&gt;<\/span>\n  <span class=\"hljs-comment\">&lt;!-- Our trees go here --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">g<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<pre aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">rotate<\/span>: <span class=\"hljs-selector-tag\">calc<\/span>(\n  360<span class=\"hljs-selector-tag\">deg<\/span> \/ <span class=\"hljs-selector-tag\">var<\/span>(<span class=\"hljs-selector-tag\">--tree-count<\/span>) * <span class=\"hljs-selector-tag\">var<\/span>(<span class=\"hljs-selector-tag\">--index<\/span>)\n);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>Try changing the number of trees below and see how it affects the snowflake&#8217;s shape<\/p>\n\n\n\n<iframe style=\"width: 100%;\" scrolling=\"no\" title=\"Full Tree\" src=\"https:\/\/codepen.io\/phebert\/embed\/eYKXLqo?default-tab=result&amp;theme-id=light\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\" height=\"764\" frameborder=\"no\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/eYKXLqo\">\n  Full Tree<\/a> by Paul Hebert (<a href=\"https:\/\/codepen.io\/phebert\">@phebert<\/a>)\n  on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.\n<\/iframe>\n\n\n\n<h2 class=\"wp-block-heading\">Making your code configurable (a.k.a the snowflake building machine)<\/h2>\n\n\n\n<p>In the demo above, we&#8217;ve got an array of input parameters that are processed and turned into an SVG string. That sounds an awful lot like a JavaScript function! Let&#8217;s turn our hand-written SVG into a function that accepts a settings object and spits out a snowflake. <\/p>\n\n\n\n<p>This will allow us to generate random settings and procedurally generate snowflakes. (This logic is also what helped to power the demo above!)<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ Our snowflake settings.<\/span>\n<span class=\"hljs-comment\">\/\/ We could randomly generate these, or pull them from a form.<\/span>\n<span class=\"hljs-keyword\">const<\/span> settings = {\n  <span class=\"hljs-attr\">trunkLength<\/span>: <span class=\"hljs-number\">40<\/span>,\n  <span class=\"hljs-attr\">branches<\/span>: &#91;\n    { <span class=\"hljs-attr\">distance<\/span>: <span class=\"hljs-number\">10<\/span>, <span class=\"hljs-attr\">length<\/span>: <span class=\"hljs-number\">5<\/span> },\n    { <span class=\"hljs-attr\">distance<\/span>: <span class=\"hljs-number\">20<\/span>, <span class=\"hljs-attr\">length<\/span>: <span class=\"hljs-number\">10<\/span> },\n    { <span class=\"hljs-attr\">distance<\/span>: <span class=\"hljs-number\">30<\/span>, <span class=\"hljs-attr\">length<\/span>: <span class=\"hljs-number\">8<\/span> },\n  ],\n  <span class=\"hljs-attr\">treeCount<\/span>: <span class=\"hljs-number\">6<\/span>\n}\n\n<span class=\"hljs-comment\">\/\/ Call our function and use it to <\/span>\n<span class=\"hljs-comment\">\/\/ populate an SVG group<\/span>\nsvgEl.innerHTML = buildSnowflake(settings);\n\n<span class=\"hljs-comment\">\/\/ Our main function! <\/span>\n<span class=\"hljs-comment\">\/\/ Returns the full snowflake SVG code<\/span>\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">buildSnowflake<\/span>(<span class=\"hljs-params\">{trunkLength, branches, treeCount}<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">`\n    &lt;g class=\"snowflake\" style=\"--tree-count: <span class=\"hljs-subst\">${treeCount}<\/span>;\"&gt;\n      <span class=\"hljs-subst\">${buildTree({trunkLength, branches}<\/span>)}\n      <span class=\"hljs-subst\">${buildTreeCopies(treeCount)}<\/span>\n    &lt;\/g&gt;\n  `<\/span>\n}\n\n<span class=\"hljs-comment\">\/\/ A helper function that returns an <\/span>\n<span class=\"hljs-comment\">\/\/ SVG group containing a <\/span>\n<span class=\"hljs-comment\">\/\/ single \"tree\"<\/span>\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">buildTree<\/span>(<span class=\"hljs-params\">{trunkLength, branches}<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> trunk = <span class=\"hljs-string\">`\n    &lt;line x1=\"50\" y1=\"50\" x2=\"50\" y2=\"<span class=\"hljs-subst\">${<span class=\"hljs-number\">50<\/span> - trunkLength}<\/span>\" \/&gt;\n  `<\/span>;\n\n  <span class=\"hljs-keyword\">const<\/span> branchStrings = branches.map(<span class=\"hljs-function\">(<span class=\"hljs-params\">{distance, length}<\/span>) =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> startY = <span class=\"hljs-number\">50<\/span> - distance;\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">`\n      &lt;line \n        x1=\"50\" \n        y1=\"<span class=\"hljs-subst\">${startY}<\/span>\" \n        x2=\"<span class=\"hljs-subst\">${<span class=\"hljs-number\">50<\/span> - length}<\/span>\" \n        y2=\"<span class=\"hljs-subst\">${startY - length}<\/span>\" \n      \/&gt;\n    `<\/span>\n  });\n\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">`&lt;g id=\"tree\"&gt;\n    <span class=\"hljs-subst\">${trunk}<\/span>\n    &lt;g id=\"branches\"&gt;<span class=\"hljs-subst\">${branchStrings.join(<span class=\"hljs-string\">' '<\/span>)}<\/span>&lt;\/g&gt;\n    &lt;use href=\"#branches\" class=\"flipped-branches\" \/&gt;\n  &lt;\/g&gt;`<\/span>;\n}\n\n<span class=\"hljs-comment\">\/\/ A helper function that returns a <\/span>\n<span class=\"hljs-comment\">\/\/ number of `&lt;use&gt;` elements <\/span>\n<span class=\"hljs-comment\">\/\/ copying our \"tree\"<\/span>\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">buildTreeCopies<\/span>(<span class=\"hljs-params\">treeCount<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">let<\/span> copies = <span class=\"hljs-string\">''<\/span>;\n  <span class=\"hljs-keyword\">for<\/span>(<span class=\"hljs-keyword\">let<\/span> i = <span class=\"hljs-number\">0<\/span>; i &lt; treeCount; i++) {\n    copies += <span class=\"hljs-string\">`\n      &lt;use \n        href=\"#tree\" \n        style=\"--index: <span class=\"hljs-subst\">${i}<\/span>\" \n        class=\"rotated-tree\"\n      \/&gt;`<\/span> \n  }\n  <span class=\"hljs-keyword\">return<\/span> copies;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>Try <a href=\"https:\/\/codepen.io\/phebert\/pen\/dyKLRXd\">editing the settings in the CodePen below<\/a> to see how it changes the output of our function and the shape of our snowflake:<\/p>\n\n\n\n<iframe style=\"width: 100%;\" scrolling=\"no\" title=\"Untitled\" src=\"https:\/\/codepen.io\/phebert\/embed\/dyKLRXd?default-tab=result&amp;;theme-id=light\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\" height=\"487\" frameborder=\"no\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/dyKLRXd\">\n  Untitled<\/a> by Paul Hebert (<a href=\"https:\/\/codepen.io\/phebert\">@phebert<\/a>)\n  on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.\n<\/iframe>\n\n\n\n<h2 class=\"wp-block-heading\">Introducing randomness with JavaScript<\/h2>\n\n\n\n<p>Now we&#8217;ve got a handy little function for generating snowflakes. In order to make this function &#8220;generative,&#8221; we&#8217;ll need to write some logic for generating a random <code>settings<\/code> object to pass into our <code>buildSnowflake<\/code> function.<\/p>\n\n\n\n<p>We&#8217;ll use a small JS helper function called <code>randomInt<\/code> to generate random integers between two values. (I won&#8217;t dive deep into how that works here, but if you&#8217;re curious, you can view how it works in the upcoming CodePen.) <\/p>\n\n\n\n<p>Here&#8217;s an example of how we could generate a random settings object:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">randomSettings<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-comment\">\/\/ Create a random trunk length<\/span>\n  <span class=\"hljs-keyword\">const<\/span> trunkLength = randomInt(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">50<\/span>);\n  \n  <span class=\"hljs-comment\">\/\/ Create an array of branches<\/span>\n  <span class=\"hljs-comment\">\/\/ Each branch will have a random distance and length<\/span>\n  <span class=\"hljs-keyword\">const<\/span> branchCount = randomInt(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">10<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> branches = &#91;];\n  <span class=\"hljs-keyword\">for<\/span>(<span class=\"hljs-keyword\">let<\/span> i = <span class=\"hljs-number\">0<\/span>; i &lt; branchCount; i++) {\n    branches.push({ \n      <span class=\"hljs-attr\">distance<\/span>: randomInt(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">40<\/span>), \n      <span class=\"hljs-attr\">length<\/span>: randomInt(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">30<\/span>) \n    });\n  }\n  \n  <span class=\"hljs-comment\">\/\/ Determine how many trees\/spokes <\/span>\n  <span class=\"hljs-comment\">\/\/ to show<\/span>\n  <span class=\"hljs-keyword\">const<\/span> treeCount = randomInt(<span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">30<\/span>);\n  \n  <span class=\"hljs-keyword\">return<\/span> { \n    trunkLength, \n    branches, \n    treeCount \n  }\n}\n\n<span class=\"hljs-comment\">\/\/ Pass our random setting into our <\/span>\n<span class=\"hljs-comment\">\/\/ snowflake function <\/span>\nsvgEl.innerHTML = drawSnowflake(\n  randomSettings()\n);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>This makes some interesting shapes, but they don&#8217;t always feel likes <em>snowflakes<\/em>. Try clicking the &#8220;New Snowflake&#8221; button a few times below to see the generated shapes:<\/p>\n\n\n\n<iframe style=\"width: 100%;\" scrolling=\"no\" title=\"Snowflake (JS Example)\" src=\"https:\/\/codepen.io\/phebert\/embed\/dyKEQqd?default-tab=result&amp;editable=true&amp;theme-id=light\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\" height=\"457\" frameborder=\"no\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/dyKEQqd\">\n  Snowflake (JS Example)<\/a> by Paul Hebert (<a href=\"https:\/\/codepen.io\/phebert\">@phebert<\/a>)\n  on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.\n<\/iframe>\n\n\n\n<p>Sometimes the &#8220;trunk&#8221; lines are too short. Sometimes there aren&#8217;t enough &#8220;trees.&#8221; Sometimes the branches feel misaligned or extend outside our canvas. Sometimes it feels more like a doily&#8230;<\/p>\n\n\n\n<p>Some of these patterns are <em>really cool<\/em>, but if we want to make snowflakes, we&#8217;ve got some more work to do&#8230;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Introducing Constraints (a.k.a making the snowflakes more snowflakey)<\/h2>\n\n\n\n<p>First off, let&#8217;s ensure the &#8220;trunks&#8221; of our trees are a reasonable length. We&#8217;ll set a more reasonable minimum and maximum:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> trunkLength = randomInt(<span class=\"hljs-number\">20<\/span>, <span class=\"hljs-number\">40<\/span>);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>The next part is a bit trickier. There are a couple of issues with our current branches:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Sometimes they start past the end of our &#8220;trunk.&#8221;<\/li>\n\n\n\n<li>Sometimes they extend outside of our canvas.<\/li>\n<\/ul>\n\n\n\n<p>We can make a few tweaks to fix these:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ Instead of randomly generating our <\/span>\n<span class=\"hljs-comment\">\/\/ branches, we'll start near our <\/span>\n<span class=\"hljs-comment\">\/\/ center point and move outwards, <\/span>\n<span class=\"hljs-comment\">\/\/ adding branches until we extend <\/span>\n<span class=\"hljs-comment\">\/\/ past our trunk length.<\/span>\n<span class=\"hljs-keyword\">for<\/span> (\n  <span class=\"hljs-keyword\">let<\/span> distance = randomInt(<span class=\"hljs-number\">6<\/span>, <span class=\"hljs-number\">10<\/span>);\n  distance &lt; trunkLength;\n  distance += randomInt(<span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">10<\/span>)\n) {\n  branches.push({\n    distance,\n    <span class=\"hljs-comment\">\/\/ When we get towards the end of <\/span>\n    <span class=\"hljs-comment\">\/\/ our trunk, constrain the branch <\/span>\n    <span class=\"hljs-comment\">\/\/ length so they don't extend too far<\/span>\n    <span class=\"hljs-attr\">length<\/span>: randomInt(\n      <span class=\"hljs-number\">5<\/span>, \n      <span class=\"hljs-built_in\">Math<\/span>.min(\n        trunkLength - distance, \n        <span class=\"hljs-number\">10<\/span>\n      )\n    )\n  });\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>We&#8217;ll also want to set a minimum and maximum number of &#8220;trees&#8221; that feels more like a snowflake:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> treeCount = randomInt(<span class=\"hljs-number\">5<\/span>, <span class=\"hljs-number\">12<\/span>);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>While we&#8217;re at it, let&#8217;s randomize one more piece of our snowflake. Let&#8217;s generate <a href=\"https:\/\/cloudfour.com\/thinks\/hsl-a-color-format-for-humans\/\">a random <code>hsl<\/code> color<\/a> and use it to set our page&#8217;s background color:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> color = <span class=\"hljs-string\">`hsl(\n  <span class=\"hljs-subst\">${random(<span class=\"hljs-number\">190<\/span>, <span class=\"hljs-number\">210<\/span>)}<\/span>, \n  <span class=\"hljs-subst\">${random(<span class=\"hljs-number\">30<\/span>, <span class=\"hljs-number\">60<\/span>)}<\/span>%, \n  <span class=\"hljs-subst\">${random(<span class=\"hljs-number\">50<\/span>, <span class=\"hljs-number\">80<\/span>)}<\/span>%\n)`<\/span>;\n\n<span class=\"hljs-comment\">\/* ... meanwhile, in our `drawSnowflake` function... *\/<\/span>\n\n<span class=\"hljs-built_in\">document<\/span>.body.style.backgroundColor = color;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n\n\n\n<p>Let&#8217;s see how this is working:<\/p>\n\n\n\n<iframe style=\"width: 100%;\" scrolling=\"no\" title=\"Snowflake (JS Example - Randomized)\" src=\"https:\/\/codepen.io\/phebert\/embed\/bGKyOeN?default-tab=result&amp;editable=true&amp;theme-id=light\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\" height=\"457\" frameborder=\"no\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/bGKyOeN\">\n  Snowflake (JS Example &#8211; Randomized)<\/a> by Paul Hebert (<a href=\"https:\/\/codepen.io\/phebert\">@phebert<\/a>)\n  on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.\n<\/iframe>\n\n\n\n<p>These feel a bit more snowflakey to me. We&#8217;ve turned our random pattern generator into a random snowflake generator!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Make it your own<\/h2>\n\n\n\n<p>There are lots of different snowflakes and a lot of different directions we could take it from here:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>We could try changing our constraints to make different snowflake shapes.<\/li>\n\n\n\n<li>We could animate how the snowflakes are drawn.<\/li>\n\n\n\n<li>We could lay several snowflakes out in a pattern.<\/li>\n\n\n\n<li>We could animate falling snowflakes.<\/li>\n\n\n\n<li>We could use these same strategies to generate flowers, mandalas, or other geometric shapes.<\/li>\n<\/ul>\n\n\n\n<p>I hope this taught you a little bit about SVGs, JavaScript, and generative art. I&#8217;d love to see what you make with these techniques. <\/p>\n\n\n\n<p>If you remix the demos above or make brand-new generative art, post it in the comments!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hand-code an SVG snowflake, experiment in an interactive playground, and generate infinite random snowflakes with a dash of JavaScript.<\/p>\n","protected":false},"author":19,"featured_media":6782,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[235,240,205,300],"tags":[],"class_list":["post-6767","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-design","category-javascript","category-process","category-svg"],"acf":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/cloudfour.com\/wp-content\/uploads\/2022\/12\/snowflakes-looping-2.gif","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/posts\/6767","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/users\/19"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/comments?post=6767"}],"version-history":[{"count":0,"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/posts\/6767\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/media\/6782"}],"wp:attachment":[{"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/media?parent=6767"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/categories?post=6767"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/tags?post=6767"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}