{"id":7224,"date":"2023-07-06T08:52:38","date_gmt":"2023-07-06T15:52:38","guid":{"rendered":"https:\/\/cloudfour.com\/?p=7224"},"modified":"2023-08-16T15:24:29","modified_gmt":"2023-08-16T22:24:29","slug":"coding-randomized-zelda-patterns","status":"publish","type":"post","link":"https:\/\/cloudfour.com\/thinks\/coding-randomized-zelda-patterns\/","title":{"rendered":"Coding Randomized Zelda Patterns"},"content":{"rendered":"\n<p>I&#8217;ve been really enjoying the latest Zelda game, <em>Tears of the Kingdom.<\/em> One of the ways the game creates a cohesive aesthetic is by repeating patterns between the game environment and interface screens.<\/p>\n\n\n\n<p>There was one pattern in particular that I was drawn to. This repeating circle motif can be found throughout the game&#8217;s many shrines and on interface screens. The pattern is even used on <a href=\"https:\/\/www.zelda.com\/tears-of-the-kingdom\/\">the official game website<\/a>.<\/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\">\n<figure class=\"wp-block-image size-full\"><img width=\"1280\" height=\"720\" src=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1580.jpg\" alt=\"A camera capture of a wall with a pattern showing nested circles and squiggly lines\" class=\"wp-image-7230\" srcset=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1580.jpg 1280w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1580-300x169.jpg 300w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1580-1024x576.jpg 1024w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1580-768x432.jpg 768w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/figure>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img width=\"1280\" height=\"720\" src=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1581.jpg\" alt=\"A camera capture of a gold textured floor showing the circle and squiggle pattern\" class=\"wp-image-7231\" srcset=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1581.jpg 1280w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1581-300x169.jpg 300w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1581-1024x576.jpg 1024w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1581-768x432.jpg 768w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/figure>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full\"><img width=\"469\" height=\"719\" src=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1584.jpg\" alt=\"A shot of a loading screen showing nested circle groups and squiggly lines as a background element\" class=\"wp-image-7229\" srcset=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1584.jpg 469w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1584-196x300.jpg 196w\" sizes=\"(max-width: 469px) 100vw, 469px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img width=\"640\" height=\"226\" src=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1589.jpg\" alt=\"A notification that you received a Light of Blessing. There's a semi-transparent version of the circle pattern.\" class=\"wp-image-7228\" srcset=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1589.jpg 640w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/IMG_1589-300x106.jpg 300w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/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-image size-full\"><img width=\"912\" height=\"1166\" src=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/image-3.png\" alt=\"A link card titled &quot;Tips part 2&quot;. The background uses the same squiggle and circle pattern.\" class=\"wp-image-7227\" srcset=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/image-3.png 912w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/image-3-235x300.png 235w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/image-3-801x1024.png 801w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/06\/image-3-768x982.png 768w\" sizes=\"(max-width: 912px) 100vw, 912px\" \/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p>I really enjoy creating procedurally generated artwork using JavaScript and SVGs and was inspired to generate similar patterns myself. Here&#8217;s the final artwork I ended up with. Press &#8220;Randomize&#8221; to generate a new random pattern, or select a different color scheme to apply a different visual style:<\/p>\n\n\n\n<iframe height=\"650\" style=\"width: 100%;\" scrolling=\"no\" title=\"Zelda Patterns\" src=\"https:\/\/codepen.io\/phebert\/embed\/BaGZJeV?default-tab=result&#038;theme-id=light\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/BaGZJeV\">\n  Zelda Patterns<\/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\">Breaking Down the Pattern<\/h2>\n\n\n\n<p>Although the pattern is very striking, it&#8217;s constructed of only two shapes: nested circles and squiggly lines.<\/p>\n\n\n\n<div class=\"wp-block-columns is-not-stacked-on-mobile 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\">\n<figure class=\"wp-block-image size-full\"><img width=\"1000\" height=\"1000\" src=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/circle-group.svg\" alt=\"A number of nested circles with gray outlines on a white background\" class=\"wp-image-7248\"\/><\/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-image size-full is-style-default\"><img width=\"1000\" height=\"1000\" src=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/squiggles-2.svg\" alt=\"A number of vertical squiggly grey lines on a white background\" class=\"wp-image-7247\"\/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p>We can reproduce these shapes using the SVG &#8220;vector graphic&#8221; format. We&#8217;ll use JavaScript to reduce repetition in our code and allow us to randomize the placement of these shapes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Building an SVG Container<\/h2>\n\n\n\n<p>First, we need to create an SVG container for our artwork:<\/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 1000 1000\"<\/span> \n  <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"1000\"<\/span> \n  <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">\"1000\"<\/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>\n    A geometric pattern composed of nested circles and squiggly lines.\n    Inspired by Legends of Zelda: Tears of the Kingdom\n  <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\">\"pattern\"<\/span>&gt;<\/span>\n    <span class=\"hljs-comment\">&lt;!-- \n      Our graphics code goes here \n    --&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>\n<\/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 1000-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\u2019t necessary, but it will make it easier to dynamically update our pattern later.)<\/li>\n<\/ul>\n\n\n\n\n\n<aside class=\"\n  c-card\n    c-card--contained o-container__fill-pad t-alternate wp-block-cloudfour-newsletter-signup-form\"\n  >\n\n  \n  \n      <div class=\"c-card__content\">\n                  <div class=\"o-rhythm u-pad-block-n1@m\">\n      <div class=\"o-rhythm u-pad-block-n1@m\">\n                  \n\n\n\n\n\n\n\n\n\n    \n  \n\n\n\n\n  <h2 class=\"c-heading c-heading--level-2 c-heading--light\" >\n    Cloud Four&#8217;s latest insights and articles, straight to your inbox\n  <\/h2>\n                      <\/div>\n      <form action=\"https:\/\/cloudfour.us13.list-manage.com\/subscribe\/post?u=ce064f42c86a5982dd218d4de&amp;id=7e505a6a67\"\n        method=\"POST\"\n        target=\"_blank\">\n        <label class=\"u-hidden-visually\" for=\"wp-block-cloudfour-newsletter-signup-form-email-2\">Email<\/label>\n        <div class=\"o-input-group \">\n              \n\n  <input type=\"email\"   class=\"c-input\"\n          id=\"wp-block-cloudfour-newsletter-signup-form-email-2\"          name=\"EMAIL\"          placeholder=\"Your Email\"                    autocomplete=\"home email\"                                                                                                      required                      >\n            \n<button\n  class=\"c-button\"\n                      >\n    <span class=\"c-button__content\">\n          Subscribe\n      <\/span>\n  <\/button>\n          <\/div>\n      <\/form>\n    <\/div>\n  \n    <\/div>\n  \n  \n<\/aside>\n\n\n\n<h2 class=\"wp-block-heading\">Drawing Nested Circles<\/h2>\n\n\n\n<p>Now that we&#8217;ve got a container to work with, let&#8217;s start drawing our graphics! The circles are the most striking part of the pattern, so let&#8217;s start there. We can use the SVG <code>circle<\/code> element:<\/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\">circle<\/span> <span class=\"hljs-attr\">cx<\/span>=<span class=\"hljs-string\">\"500\"<\/span> <span class=\"hljs-attr\">cy<\/span>=<span class=\"hljs-string\">\"500\"<\/span> <span class=\"hljs-attr\">r<\/span>=<span class=\"hljs-string\">\"250\"<\/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>Let&#8217;s break down the code above:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>cx<\/code>: this sets the horizontal center point to 500 units<\/li>\n\n\n\n<li><code>c<\/code>y: this sets the vertical center point to 500 units<\/li>\n\n\n\n<li><code>r<\/code>: This sets the radius to 250 units<\/li>\n<\/ul>\n\n\n\n<p>By default, SVG circles (and most other SVG elements) have a black background and no border. We can customize this with a few more attributes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>fill<\/code>: This is similar to the CSS <code>background-color<\/code> property. You can set it to <code>none<\/code> to have a transparent background.<\/li>\n\n\n\n<li><code>stroke<\/code>: This is similar to the CSS <code>border-color<\/code> property. <\/li>\n\n\n\n<li><code>stroke-width<\/code>: This is similar to the CSS <code>border-width<\/code> property. It defaults to 1.<\/li>\n<\/ul>\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-tag\">&lt;<span class=\"hljs-name\">circle<\/span> <span class=\"hljs-attr\">fill<\/span>=<span class=\"hljs-string\">\"none\"<\/span> <span class=\"hljs-attr\">stroke<\/span>=<span class=\"hljs-string\">\"#000\"<\/span> <span class=\"hljs-attr\">stroke-width<\/span>=<span class=\"hljs-string\">\"10\"<\/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>These can also be applied via CSS, which makes it easier to style all of our circles at once:<\/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-class\">.fill<\/span> {\n  <span class=\"hljs-attribute\">fill<\/span>: <span class=\"hljs-number\">#fff<\/span>;\n}\n<span class=\"hljs-selector-class\">.stroke<\/span> {\n  <span class=\"hljs-attribute\">fill<\/span>: none;\n  <span class=\"hljs-attribute\">stroke<\/span>: <span class=\"hljs-number\">#999<\/span>;\n  <span class=\"hljs-attribute\">stroke-width<\/span>: <span class=\"hljs-number\">10<\/span>;\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>We&#8217;re going to be drawing a <em>lot<\/em> of circles, so let&#8217;s create a JavaScript helper function:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-6\" 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\">circle<\/span>(<span class=\"hljs-params\">{ x, y, r, className }<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">`\n    &lt;circle \n      cx=\"<span class=\"hljs-subst\">${x}<\/span>\" \n      cy=\"<span class=\"hljs-subst\">${y}<\/span>\" \n      r=\"<span class=\"hljs-subst\">${r}<\/span>\" \n      class=\"<span class=\"hljs-subst\">${className}<\/span>\"\n    \/&gt;\n  `<\/span>;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><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 can write another helper function to draw a group of nested circles:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-7\" 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\">circleGroup<\/span>(<span class=\"hljs-params\">{x, y, r }<\/span>) <\/span>{\n  <span class=\"hljs-comment\">\/\/ We'll store all our circles in an array.<\/span>\n  <span class=\"hljs-keyword\">const<\/span> circles = &#91;];\n\n  <span class=\"hljs-comment\">\/\/ First, draw a circle with a white background but no border.<\/span>\n  <span class=\"hljs-comment\">\/\/ This will hide any elements behind the circle.<\/span>\n  circles.push(circle({ x, y, r, <span class=\"hljs-attr\">class<\/span>: <span class=\"hljs-string\">'fill'<\/span> }));\n\n  <span class=\"hljs-comment\">\/\/ Decide how much space to put between our circles.<\/span>\n  <span class=\"hljs-keyword\">const<\/span> gap = <span class=\"hljs-number\">20<\/span>;\n\n  <span class=\"hljs-comment\">\/\/ Draw a number of circles, making each one smaller than the last<\/span>\n  <span class=\"hljs-comment\">\/\/ until we hit a radius of 0.<\/span>\n  <span class=\"hljs-keyword\">let<\/span> circleSize = r;\n  <span class=\"hljs-keyword\">while<\/span>(circleSize &gt; <span class=\"hljs-number\">0<\/span>) {\n    circles.push(circle({ x, y, <span class=\"hljs-attr\">r<\/span>: circleSize, <span class=\"hljs-attr\">className<\/span>: <span class=\"hljs-string\">'stroke'<\/span> }));\n\n    circleSize -= gap;\n  }\n\n  <span class=\"hljs-comment\">\/\/ Return all of our circles, joined together as a string;<\/span>\n  <span class=\"hljs-keyword\">return<\/span> circles.join(<span class=\"hljs-string\">''<\/span>);\n}\n\n<span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">'.pattern'<\/span>).innerHTML = circleGroup({\n  <span class=\"hljs-attr\">x<\/span>: <span class=\"hljs-number\">500<\/span>, \n  <span class=\"hljs-attr\">y<\/span>: <span class=\"hljs-number\">500<\/span>,\n  <span class=\"hljs-attr\">r<\/span>: <span class=\"hljs-number\">250<\/span>,\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\">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>Here&#8217;s a demo showing this in action. Click anywhere on the SVG to add a new, randomly size circle group.<\/p>\n\n\n\n<iframe height=\"550\" style=\"width: 100%;\" scrolling=\"no\" title=\"Circle Group Demo\" src=\"https:\/\/codepen.io\/phebert\/embed\/oNQZMyg?default-tab=result&#038;theme-id=light\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/oNQZMyg\">\n  Circle Group Demo<\/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\">Randomizing the Circle Placement<\/h2>\n\n\n\n<p>As you can see, adding a number of circle groups can create interesting patterns. Let&#8217;s automate this and add randomness to generate infinite random patterns. <\/p>\n\n\n\n<p>We&#8217;ll use a helper function from <a href=\"https:\/\/www.npmjs.com\/package\/randomness-helpers\">an npm package I made to generate random values<\/a> (docs coming soon!) <code>randomInt<\/code> will return an integer between a minimum and maximum value:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">randomInt(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">1000<\/span>);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><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>Using this helper, we can randomize the number of circle groups, as well as their size and placement:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> { randomInt } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'https:\/\/unpkg.com\/randomness-helpers@0.0.1\/dist\/index.js'<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> patternEl =  <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">'.pattern'<\/span>);\n<span class=\"hljs-keyword\">const<\/span> gridSize = <span class=\"hljs-number\">10000<\/span>;\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">draw<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-comment\">\/\/ Store all of our circle groups<\/span>\n  <span class=\"hljs-keyword\">const<\/span> circleGroups = &#91;];\n  <span class=\"hljs-comment\">\/\/ Add a random number of groups between 10 and 30<\/span>\n  <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">let<\/span> i = <span class=\"hljs-number\">0<\/span>; i &lt; randomInt(<span class=\"hljs-number\">10<\/span>, <span class=\"hljs-number\">30<\/span>); i++) {\n    <span class=\"hljs-comment\">\/\/ Add a circle group with a randomized location and size<\/span>\n    circleGroups.push(circleGroup({\n      <span class=\"hljs-attr\">x<\/span>: randomInt(<span class=\"hljs-number\">0<\/span>, gridSize),\n      <span class=\"hljs-attr\">y<\/span>: randomInt(<span class=\"hljs-number\">0<\/span>, gridSize),\n      <span class=\"hljs-attr\">r<\/span>: randomInt(<span class=\"hljs-number\">50<\/span>, <span class=\"hljs-number\">300<\/span>)\n    }))\n  }\n  \n  <span class=\"hljs-comment\">\/\/ Join our array and populate our SVG group element<\/span>\n  patternEl.innerHTML = circleGroups.join(<span class=\"hljs-string\">''<\/span>);\n}\n\ndraw();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><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>View the pattern below and click the &#8220;Randomize&#8221; button to generate new patterns.<\/p>\n\n\n\n<iframe height=\"550\" style=\"width: 100%;\" scrolling=\"no\" title=\"Circle Group Demo\" src=\"https:\/\/codepen.io\/phebert\/embed\/zYMwYPy?default-tab=result&#038;theme-id=light\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/zYMwYPy\">\n  Circle Group Demo<\/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\">Filling in the Background<\/h2>\n\n\n\n<p>We&#8217;re getting closer to reproducing the patterns from Zelda! But something&#8217;s missing. The empty spaces behind the circles feel kind of awkward. The patterns in Zelda often fill in these gaps with a background of squiggly lines.<\/p>\n\n\n\n<p>Let&#8217;s define a helper function to draw a single squiggly line. We can use the SVG path element, which accepts a <code>d<\/code> attribute that describes its shape. We&#8217;ll write some code to get points in a zig-zagging pattern and then use a helper called <a href=\"https:\/\/www.npmjs.com\/package\/@georgedoescode\/spline\">spline<\/a> to draw a smooth line through them.<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-10\" 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\">squigglyLine<\/span>(<span class=\"hljs-params\">x, squiggleWidth, squiggleHeight<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> points = &#91;];\n  \n  <span class=\"hljs-comment\">\/\/ Define an offset for how far the zig-zag points should<\/span>\n  <span class=\"hljs-comment\">\/\/ be placed from the center of our line.<\/span>\n  <span class=\"hljs-keyword\">let<\/span> xOffset = squiggleWidth \/ <span class=\"hljs-number\">2<\/span>;\n  \n  <span class=\"hljs-keyword\">for<\/span>(\n    <span class=\"hljs-comment\">\/\/ Start slightly above the edge of our canvas<\/span>\n    <span class=\"hljs-keyword\">let<\/span> y = <span class=\"hljs-number\">-1<\/span> * squiggleHeight; \n    <span class=\"hljs-comment\">\/\/ End slightly below the bottom<\/span>\n    y &lt;= gridSize + squiggleHeight; \n    <span class=\"hljs-comment\">\/\/ Iterate down, adding new points to our array<\/span>\n    y += squiggleHeight\n  ) {\n    <span class=\"hljs-comment\">\/\/ Add a new point.<\/span>\n    <span class=\"hljs-comment\">\/\/ Adjust our x value by our offset;<\/span>\n    points.push({y, <span class=\"hljs-attr\">x<\/span>: x + xOffset})\n    <span class=\"hljs-comment\">\/\/ Flip our x offset so the next point is <\/span>\n    <span class=\"hljs-comment\">\/\/ placed on the other side of our center line.<\/span>\n    xOffset *= <span class=\"hljs-number\">-1<\/span>;\n  }\n  \n  <span class=\"hljs-comment\">\/\/ Use our points to build a path<\/span>\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">`&lt;path d=\"<span class=\"hljs-subst\">${spline(points)}<\/span>\" class=\"stroke\" \/&gt;`<\/span>;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><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>Now that we can draw a single squiggly line, we&#8217;ll need to work from the left edge of our canvas to the right edge, building up an array of lines:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ Generate some random values to define the shape of our squiggles<\/span>\n<span class=\"hljs-keyword\">const<\/span> lineGap = randomInt(<span class=\"hljs-number\">15<\/span>, <span class=\"hljs-number\">25<\/span>);\n<span class=\"hljs-keyword\">const<\/span> squiggleWidth = randomInt(<span class=\"hljs-number\">10<\/span>, <span class=\"hljs-number\">15<\/span>);\n<span class=\"hljs-keyword\">const<\/span> squiggleHeight = randomInt(<span class=\"hljs-number\">60<\/span>, <span class=\"hljs-number\">90<\/span>);\n\n<span class=\"hljs-comment\">\/\/ Build an array of lines<\/span>\n<span class=\"hljs-keyword\">const<\/span> lines = &#91;];\n\n<span class=\"hljs-keyword\">for<\/span>(\n  <span class=\"hljs-comment\">\/\/ Start slightly to the left of our canvas<\/span>\n  <span class=\"hljs-keyword\">let<\/span> x = lineGap * <span class=\"hljs-number\">-1<\/span>; \n  <span class=\"hljs-comment\">\/\/ End slightly to the right of our canvas<\/span>\n  x &lt; gridSize + lineGap; \n  <span class=\"hljs-comment\">\/\/ Leave a gap between our lines<\/span>\n  x += lineGap\n) {\n  lines.push(squigglyLine(x, squiggleWidth, squiggleHeight));\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\">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>Once we have an array of line elements we can insert them before\/below our circles:<\/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\">patternEl.innerHTML = lines.join(<span class=\"hljs-string\">''<\/span>) + circleGroups.join(<span class=\"hljs-string\">''<\/span>);\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>Now we&#8217;re getting closer to the patterns from Zelda! Click &#8220;Randomize&#8221; to generate new patterns:<\/p>\n\n\n\n<iframe height=\"550\" style=\"width: 100%;\" scrolling=\"no\" title=\"Randomized Circle Groups\" src=\"https:\/\/codepen.io\/phebert\/embed\/xxQrPqJ?default-tab=result&#038;theme-id=light\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/xxQrPqJ\">\n  Randomized Circle Groups<\/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\">Applying Different Color Schemes<\/h2>\n\n\n\n<p>One of the strengths of this pattern is its flexibility. Being able to remix the pattern and apply different color schemes allowed Zelda&#8217;s designers to use the pattern in multiple places.<\/p>\n\n\n\n<p>Let&#8217;s update our CSS to display the patterns using different color schemes. We&#8217;ll use custom properties to store colors as variables:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-comment\">\/* Define our base custom properties *\/<\/span>\n<span class=\"hljs-selector-pseudo\">:root<\/span> {\n  <span class=\"hljs-attribute\">--fill<\/span>: <span class=\"hljs-built_in\">hsl<\/span>(<span class=\"hljs-number\">30<\/span>, <span class=\"hljs-number\">50%<\/span>, <span class=\"hljs-number\">90%<\/span>);\n  <span class=\"hljs-attribute\">--stroke<\/span>: <span class=\"hljs-built_in\">hsl<\/span>(<span class=\"hljs-number\">80<\/span>, <span class=\"hljs-number\">80%<\/span>, <span class=\"hljs-number\">28%<\/span>);\n}\n\n<span class=\"hljs-comment\">\/* Apply styles to our elements *\/<\/span>\n<span class=\"hljs-selector-tag\">svg<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-built_in\">var<\/span>(--fill);\n}\n<span class=\"hljs-selector-class\">.fill<\/span> {\n  <span class=\"hljs-attribute\">fill<\/span>: <span class=\"hljs-built_in\">var<\/span>(--fill);\n}\n<span class=\"hljs-selector-class\">.stroke<\/span> {\n  <span class=\"hljs-attribute\">fill<\/span>: none;\n  <span class=\"hljs-attribute\">stroke<\/span>: <span class=\"hljs-built_in\">var<\/span>(--stroke);\n  <span class=\"hljs-attribute\">stroke-width<\/span>: <span class=\"hljs-number\">10<\/span>;\n}\n\n<span class=\"hljs-comment\">\/* Define new themes that can be added using a class *\/<\/span>\n<span class=\"hljs-selector-class\">.theme-faded<\/span> {\n  <span class=\"hljs-attribute\">--fill<\/span>: <span class=\"hljs-built_in\">hsl<\/span>(<span class=\"hljs-number\">56<\/span>, <span class=\"hljs-number\">100%<\/span>, <span class=\"hljs-number\">95%<\/span>);\n  <span class=\"hljs-attribute\">--stroke<\/span>: <span class=\"hljs-built_in\">hsl<\/span>(<span class=\"hljs-number\">51<\/span>, <span class=\"hljs-number\">45%<\/span>, <span class=\"hljs-number\">55%<\/span>);\n}\n<span class=\"hljs-selector-class\">.theme-green<\/span> {\n  <span class=\"hljs-attribute\">--fill<\/span>: <span class=\"hljs-built_in\">hsl<\/span>(<span class=\"hljs-number\">167<\/span>, <span class=\"hljs-number\">42%<\/span>, <span class=\"hljs-number\">24%<\/span>);\n  <span class=\"hljs-attribute\">--stroke<\/span>: <span class=\"hljs-built_in\">hsl<\/span>(<span class=\"hljs-number\">169<\/span>, <span class=\"hljs-number\">44%<\/span>, <span class=\"hljs-number\">32%<\/span>);\n}\n<span class=\"hljs-selector-class\">.theme-gold<\/span> {\n  <span class=\"hljs-comment\">\/* For this theme we're referencing an SVG gradient element to apply a gradient to our strokes *\/<\/span>\n  <span class=\"hljs-attribute\">--stroke<\/span>: <span class=\"hljs-built_in\">url<\/span>(#gold-gradient);\n  <span class=\"hljs-attribute\">--fill<\/span>: <span class=\"hljs-built_in\">hsl<\/span>(<span class=\"hljs-number\">44<\/span>, <span class=\"hljs-number\">81%<\/span>, <span class=\"hljs-number\">17%<\/span>);\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\">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>Use the checkboxes in the demo below to change the color scheme and see how it affects the patterns:<\/p>\n\n\n\n<iframe height=\"650\" style=\"width: 100%;\" scrolling=\"no\" title=\"Zelda Patterns\" src=\"https:\/\/codepen.io\/phebert\/embed\/BaGZJeV?default-tab=result&#038;theme-id=light\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href=\"https:\/\/codepen.io\/phebert\/pen\/BaGZJeV\">\n  Zelda Patterns<\/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\">Printing Our Artwork With a Robot<\/h2>\n\n\n\n<p>I really enjoy generating digital art, but sometimes it&#8217;s nice to have a physical art piece you can hang on the wall or gift to a friend. And it&#8217;s always fun to play with robots. <\/p>\n\n\n\n<p>Luckily I got an <a href=\"https:\/\/www.axidraw.com\/\">Axi-Draw pen plotter<\/a> for my birthday! Pen plotters are robotically controlled pen holders that allow you to &#8220;plot&#8221; a digital drawing using a physical pen. You can select the pen and paper you&#8217;d like to use, configure the pen plotter, and then have it draw your artwork for you!<\/p>\n\n\n\n<p>It works well with SVG graphics. I made <a href=\"https:\/\/codepen.io\/phebert\/pen\/abQyKxJ?editors=0010\">a few tweaks to our algorithm<\/a> to resize the pattern and add a border, and then had my plotter go to work!<\/p>\n\n\n\n<p>Here are a couple of finished art pieces. You can easily use different colors of pens and paper to produce different styles of artwork.<\/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\">\n<figure class=\"wp-block-image size-large\"><img width=\"768\" height=\"1024\" src=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/IMG_1619-2-768x1024.jpg\" alt=\"A geometric pattern made of circles and squiggly lines printed in gold on black paper\" class=\"wp-image-7256\" srcset=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/IMG_1619-2-768x1024.jpg 768w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/IMG_1619-2-225x300.jpg 225w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/IMG_1619-2-1152x1536.jpg 1152w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/IMG_1619-2-1536x2048.jpg 1536w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/IMG_1619-2-scaled.jpg 1920w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/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-image size-large\"><img width=\"768\" height=\"1024\" src=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/IMG_1621-768x1024.jpg\" alt=\"Three different framed geometric circle patterns: One in green, one in red, and one in blue. On white paper.\" class=\"wp-image-7257\" srcset=\"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/IMG_1621-768x1024.jpg 768w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/IMG_1621-225x300.jpg 225w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/IMG_1621-1152x1536.jpg 1152w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/IMG_1621-1536x2048.jpg 1536w, https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/IMG_1621-scaled.jpg 1920w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p>And here&#8217;s the pen plotter at work:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<lite-youtube videotitle=\"Generating Zelda Circles\" nocookie videoid=\"-n3aCNsTrbA\">\n  <a class=\"lite-youtube-fallback\" href=\"https:\/\/youtu.be\/-n3aCNsTrbA\">\n    Watch on YouTube: \u201cGenerating Zelda Circles\u201d\n  <\/a>\n<\/lite-youtube>\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Other Opportunities<\/h2>\n\n\n\n<p>I had a lot of fun generating, theming, and printing these patterns. Hopefully this taught you a little bit about JavaScript, SVGs or generative art. If you&#8217;re up for a challenge, try tweaking the <a href=\"https:\/\/codepen.io\/phebert\/pen\/BaGZJeV\">CodePen<\/a> or making an art piece of your own! Are there other patterns in Zelda or in the world that could be generated? Have fun!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The new Zelda game uses repeated patterns to build a cohesive world. Let&#8217;s write code to generate these patterns and then print them with a robot!<\/p>\n","protected":false},"author":19,"featured_media":7253,"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":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[240,205,300],"tags":[],"class_list":["post-7224","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript","category-process","category-svg"],"acf":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/cloudfour.com\/wp-content\/uploads\/2023\/07\/zelda-sharing-1.png","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/posts\/7224","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=7224"}],"version-history":[{"count":0,"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/posts\/7224\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/media\/7253"}],"wp:attachment":[{"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/media?parent=7224"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/categories?post=7224"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudfour.com\/wp-json\/wp\/v2\/tags?post=7224"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}