<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title></title>
    <link rel="self" type="application/atom+xml" href="/atom.xml"/>
    <link rel="alternate" type="text/html" href="/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2025-08-24T00:00:00+00:00</updated>
    <id>/atom.xml</id>
    <entry xml:lang="en">
        <title>Chladni Figures</title>
        <published>2025-08-24T00:00:00+00:00</published>
        <updated>2025-08-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="/posts/chladni/"/>
        <id>/posts/chladni/</id>
        
        <content type="html" xml:base="/posts/chladni/">&lt;link rel=&quot;stylesheet&quot; href=&quot;.&#x2F;chladni.css&quot;&gt;
&lt;!-- &lt;meta property=&quot;og:title&quot; content=&quot;{{ page.title }}&quot;&gt;
&lt;meta property=&quot;og:description&quot; content=&quot;{{ page.description }}&quot;&gt;
&lt;meta property=&quot;og:image&quot; content=&quot;{{ thumbnail.url }}&quot;&gt;
&lt;meta property=&quot;og:type&quot; content=&quot;website&quot;&gt; --&gt;
&lt;div class=&quot;canvas-container&quot;&gt;
	&lt;canvas id=&quot;main-canvas&quot; class=&quot;art-canvas&quot;&#x2F;&gt;
&lt;&#x2F;div&gt;
&lt;div id=&quot;video-fallback&quot;&gt;
	&lt;video class=&quot;art-canvas&quot; controls&gt;
		&lt;source src=&quot;&#x2F;posts&#x2F;chladni&#x2F;chladni_bevy.mp4&quot; type=&quot;video&#x2F;mp4&quot;&gt;
	&lt;&#x2F;video&gt;
	&lt;div class=&quot;hint&quot;&gt;
	&lt;span class=&quot;hint-text&quot;&gt;Hint:&lt;&#x2F;span&gt; Load this page in a WebGPU-supported browser to control a live simulation!
&lt;&#x2F;div&gt;

&lt;&#x2F;div&gt;
&lt;script type=&quot;module&quot;&gt;
	import init from &#x27;&#x2F;posts&#x2F;chladni&#x2F;chladni.js&#x27;
	async function isWebgpuSupported() {
		if (!navigator.gpu) {
			return false;
		}
		try {
			const adapter = await navigator.gpu.requestAdapter();
			return adapter !== null;
		} catch (err) {
			return false;
		}
	}
	isWebgpuSupported().then((supported) =&gt; {
		if (supported) {
			document.getElementById(&quot;video-fallback&quot;).hidden = true;
			init();
		} else {
			document.getElementsByClassName(&quot;canvas-container&quot;)[0].hidden = true
		}
	});
&lt;&#x2F;script&gt;
&lt;br&gt;
&lt;p&gt;Draw on the canvas to place&#x2F;remove constraints:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Left click: Place a wall constraint (prevents the plate underneath from moving)&lt;&#x2F;li&gt;
&lt;li&gt;Right click: Place an oscillator constraint (Forces the plate to move up and down)&lt;&#x2F;li&gt;
&lt;li&gt;Middle click: Clear constraint&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can adjust the frequency of oscillators using &quot;brush frequency&quot; slider at the bottom.&lt;&#x2F;p&gt;
&lt;hr&#x2F;&gt;
&lt;p&gt;This is a little simulation of Chladni patterns in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bevy.org&quot;&gt;Bevy&lt;&#x2F;a&gt;, using compute shaders for the plate simulation and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;laundmo&#x2F;bevy-spatial&quot;&gt;bevy_spatial&lt;&#x2F;a&gt; for the particles.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Ernst_Chladni#Chladni_figures&quot;&gt;Chladni figures&lt;&#x2F;a&gt; are patterns obtained by placing sand on a metal plate, and vibrating it.&lt;&#x2F;p&gt;
&lt;div class=&quot;quote&quot;&gt;
	&lt;p class=&quot;quote-body&quot;&gt;When resonating, a plate or membrane is divided into regions that vibrate in opposite directions, bounded by lines where no vibration occurs (nodal lines).&lt;&#x2F;p&gt;
	&lt;span class=&quot;quote-source&quot;&gt; https:&amp;#x2F;&amp;#x2F;en.wikipedia.org&amp;#x2F;wiki&amp;#x2F;Ernst_Chladni#Chladni_figures&lt;&#x2F;span&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;The sand will naturally be pushed toward the nodal lines, making the figures appear.&lt;&#x2F;p&gt;
&lt;p&gt;Depending on how you constrain the movement of the plate (e.g. pressing it down with your fingers), these regions will change and you can get a variety of different patterns.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto; width: 50%;&quot; src=&quot;https:&#x2F;&#x2F;upload.wikimedia.org&#x2F;wikipedia&#x2F;commons&#x2F;0&#x2F;03&#x2F;Bowing_chladni_plate.png&quot; title=&quot;Chladni plate diagram&quot; alt=&quot;A horizontal plate of metal with sand on top. Chladni&#x27;s left middle finger &amp; thumb press on the side of the plate. With his right hand, he bows the side of the plate using a violin bow.&quot;&#x2F;&gt;
&lt;br&gt;
&lt;p&gt;There are two parts to this simulation:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The plate: Represented as a 128x128 square grid, where each cell stores its elevation and velocity&lt;&#x2F;li&gt;
&lt;li&gt;The sand: A bunch of little sprites&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;the-plate&quot;&gt;The plate&lt;&#x2F;h2&gt;
&lt;p&gt;The plate is represented as a texure, with only a red and green channel, corresponding to elevation &amp;amp; velocity respectively.
It is simulated within a compute shader, and each point feels a force from its 4 neighbors.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #BFBDB6; background-color: #0D1017;&quot;&gt;&lt;code data-lang=&quot;wgsl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;&#x2F;&#x2F; get the data of the current cell&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt; textureLoad&lt;&#x2F;span&gt;&lt;span&gt;(input, location);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; pos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;r;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; vel&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;g;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;&#x2F;&#x2F; sample the 4 directions around the current cell&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; i: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D2A6FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D2A6FF;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;; i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;++&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span&gt; t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt; f32&lt;&#x2F;span&gt;&lt;span&gt;(i)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D2A6FF;&quot;&gt; 4.0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; TAU&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span&gt; d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt; vec2f&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;cos&lt;&#x2F;span&gt;&lt;span&gt;(t),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt; sin&lt;&#x2F;span&gt;&lt;span&gt;(t));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span&gt; other_data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt; sample_input&lt;&#x2F;span&gt;&lt;span&gt;(loc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; d);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span&gt; other_pos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; other_data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;r;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span&gt; weight&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; other_data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;g;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;	&#x2F;&#x2F; apply a force if the other cell is at a different elevation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	vel&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span&gt; (other_pos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span&gt; pos)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; TENSION&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span&gt; weight;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;&#x2F;&#x2F; integrate velocity&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span&gt; vel&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; DT&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;&#x2F;&#x2F; store the updated cell data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;textureStore&lt;&#x2F;span&gt;&lt;span&gt;(output, location,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt; vec4f&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;vec2f&lt;&#x2F;span&gt;&lt;span&gt;(pos, vel),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D2A6FF;&quot;&gt; 0.0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D2A6FF;&quot;&gt; 0.0&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;sample_input&lt;&#x2F;code&gt; function will return two values packed as a vec2f:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the red channel is position&lt;&#x2F;li&gt;
&lt;li&gt;the green channel is the weight of the connection. If it is &lt;code&gt;0.0&lt;&#x2F;code&gt;, this neighbor will not be connected to the current cell.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;At the boundaries, &lt;code&gt;sample_input&lt;&#x2F;code&gt; returns a returns a connection weight of &lt;code&gt;0.0&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;constraints&quot;&gt;Constraints&lt;&#x2F;h3&gt;
&lt;p&gt;One important aspect to the diversity of these patterns is the way that the plate is constrained.
There are three cases:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;In some parts, the plate will be totally unconstrained, free to simply follow the movement of its neighbors&lt;&#x2F;li&gt;
&lt;li&gt;In other parts, the plate might be pressed down with fingers or clamps, forcing it to have a fixed position and velocity&lt;&#x2F;li&gt;
&lt;li&gt;In other parts, the plate might be bowed, resulting in an oscillation&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;To reflect this, we encode constraints as a separate float texture with a single channel:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If a cell has a constraint value of &lt;code&gt;-1.0&lt;&#x2F;code&gt;, it is unconstrained.&lt;&#x2F;li&gt;
&lt;li&gt;Otherwise, its position will be given by &lt;code&gt;sin(time * TAU * constraint_value)&lt;&#x2F;code&gt;.
&lt;ul&gt;
&lt;li&gt;This means that we can fix a cell in place by giving it a constraint value of &lt;code&gt;0.0&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;And that we can force it to oscillate by setting it to any positive value&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;the-sand&quot;&gt;The sand&lt;&#x2F;h2&gt;
&lt;p&gt;The second component of this simulation is the sand particles.&lt;br &#x2F;&gt;
They follow very simple rules&lt;&#x2F;p&gt;
&lt;h4 id=&quot;go-where-the-plate-moves-the-least&quot;&gt;Go where the plate moves the least&lt;&#x2F;h4&gt;
&lt;p&gt;The plate oscillates above and below zero, therefore we take the absolute value of the elevation.&lt;br &#x2F;&gt;
We then take the gradient of it at the sand particle&#x27;s position. This gives us a vector going toward the biggest elevation offset from zero.&lt;br &#x2F;&gt;
We move the sand particle in the opposite direction to that gradient.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;move-away-from-other-sand-particles&quot;&gt;Move away from other sand particles&lt;&#x2F;h4&gt;
&lt;p&gt;To avoid them clumping up in the same location, we apply a small force to push them away from each other.&lt;br &#x2F;&gt;
It would be very expensive to naively compute the repulsive force of every particle against every other particle. Thankfully &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;bevy_spatial&#x2F;latest&#x2F;bevy_spatial&#x2F;&quot;&gt;bevy_spatial&lt;&#x2F;a&gt; lets us efficiently query the K nearest neighbors of a given particle by keeping all positions in a spatial datastructure.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;stay-on-the-plate&quot;&gt;Stay on the plate&lt;&#x2F;h4&gt;
&lt;p&gt;Lastly, if a particle falls off the plate, we teleport it back to a random location&lt;&#x2F;p&gt;
&lt;h2 id=&quot;source-code&quot;&gt;Source code&lt;&#x2F;h2&gt;
&lt;p&gt;You can find the full source code here! &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;Azorlogh&#x2F;chladni_figures&#x2F;&quot;&gt;https:&#x2F;&#x2F;codeberg.org&#x2F;Azorlogh&#x2F;chladni_figures&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>S P E E E D</title>
        <published>2024-09-22T00:00:00+00:00</published>
        <updated>2024-09-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="/games/speeed/"/>
        <id>/games/speeed/</id>
        
        <content type="html" xml:base="/games/speeed/">&lt;script type=&quot;module&quot;&gt;
	import init from &#x27;&#x2F;games&#x2F;speeed&#x2F;speeed.js&#x27;

	let btn = document.getElementById(&quot;start-game-btn&quot;);

	btn.addEventListener(&quot;click&quot;, () =&gt; {
		init()
	})
&lt;&#x2F;script&gt;
&lt;h3 id=&quot;controls&quot;&gt;Controls&lt;&#x2F;h3&gt;
&lt;p&gt;Move - Left&#x2F;Right arrows&lt;br &#x2F;&gt;
Jump - Space&lt;br &#x2F;&gt;
Slam - Down arrow&lt;&#x2F;p&gt;
&lt;div class=&quot;hint&quot;&gt;
	&lt;span class=&quot;hint-text&quot;&gt;Hint:&lt;&#x2F;span&gt; You can rebind the keys!
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Floral Maze</title>
        <published>2023-09-22T00:00:00+00:00</published>
        <updated>2023-09-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="/posts/floral-maze/"/>
        <id>/posts/floral-maze/</id>
        
        <content type="html" xml:base="/posts/floral-maze/">&lt;div class=&quot;canvas-container&quot;&gt;
	&lt;canvas id=&quot;main-canvas&quot; class=&quot;art-canvas&quot;&gt;&lt;&#x2F;canvas&gt;
&lt;&#x2F;div&gt;
&lt;script type=&quot;module&quot;&gt;
	import init from &#x27;&#x2F;gallery&#x2F;floral&#x2F;floral.js&#x27;
	init()
&lt;&#x2F;script&gt;
&lt;div class=&quot;hint&quot;&gt;
	&lt;span class=&quot;hint-text&quot;&gt;Hint:&lt;&#x2F;span&gt; Refresh the page for more patterns!
&lt;&#x2F;div&gt;
&lt;p&gt;This is a fun generative art piece I made inspired by plant growth and the emerging patterns in nature that arise from simple rules.&lt;&#x2F;p&gt;
&lt;p&gt;The working principle is based on agents traversing a square grid, leaving a trail as they move.
There are different types of agents, each with their own sets of rules.
One such rule is that they are never allowed to cross a previous path, which forces this maze-like formation.&lt;&#x2F;p&gt;
&lt;p&gt;There are a couple key aspect that really make this work.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;inheriting-the-rng&quot;&gt;Inheriting the RNG&lt;&#x2F;h3&gt;
&lt;p&gt;Agents move randomly according to a pseudo-random number generator (PRNG).&lt;&#x2F;p&gt;
&lt;p&gt;Those number generators have an internal state the dictates which outcome they will choose when you request a number, and whenever you do, the internal state changes in a deterministic way.&lt;&#x2F;p&gt;
&lt;p&gt;Each individual agent has its own PRNG, and every time the agent splits (or branches off), it&#x27;s copied over to the agent&#x27;s children, and therefore they will produce the same sorts of patterns (that is, until they diverge due differences in their environment).&lt;&#x2F;p&gt;
&lt;p&gt;All of the agents&#x27; actions are taken relative to their heading direction (turn left, turn right, move forward). To enable more symmetries, their direction is not only represented as a rotation, but a chirality as well (clock-wise or counter-clockwise). Thus the direction can be represented by the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Examples_of_groups#dihedral_group_of_order_8&quot;&gt;dihedral group Dih&lt;sub&gt;4&lt;&#x2F;sub&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;One very neat aspect of this inheritance mechanism is that it enables many scales of symmetry:
Typically, the first agent will quickly split, and since there aren&#x27;t many paths yet, they will be able to produce large patterns without diverging, resulting in very large-scale symmetries.
However, the agents could also quickly collide and diverge, producing more chaotic patterns.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mutation&quot;&gt;Mutation&lt;&#x2F;h3&gt;
&lt;p&gt;Even with symmetry and randomness, results can still look too bland and predictable. This is where the second aspect comes into play: The genetic code.&lt;&#x2F;p&gt;
&lt;p&gt;Agents are associated with a piece of genetic code which describes their preferred behavior (e.g. likes to turn a lot, prefers horizontal lines, produces fewer branches, etc.)
As time moves forward, the genome of agents sporadically mutates according to its random number generator, leading to different regions of the board having different visual properties.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
