<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: samasastudio</title>
    <description>The latest articles on DEV Community by samasastudio (@samasastudio).</description>
    <link>https://dev.to/samasastudio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F345526%2Fad5b01e2-8955-4b23-bd2f-a45d36b89780.jpg</url>
      <title>DEV Community: samasastudio</title>
      <link>https://dev.to/samasastudio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/samasastudio"/>
    <language>en</language>
    <item>
      <title>GLSL Canvas Component for React, Hooks &amp; Typescript</title>
      <dc:creator>samasastudio</dc:creator>
      <pubDate>Thu, 20 May 2021 22:18:04 +0000</pubDate>
      <link>https://dev.to/samasastudio/glsl-canvas-component-for-react-hooks-typescript-4p3c</link>
      <guid>https://dev.to/samasastudio/glsl-canvas-component-for-react-hooks-typescript-4p3c</guid>
      <description>&lt;p&gt;Hey Devs,&lt;/p&gt;

&lt;p&gt;Recently I've been spending some creative time in KodeLife and designing a small library of GLSL shaders that I like to have on hand for projects.  When finally rendering these shaders on the web, I can't recommend &lt;a href="https://www.npmjs.com/package/glslCanvas/v/0.0.14" rel="noopener noreferrer"&gt;glslCanvas&lt;/a&gt; 👨🏻‍🎨 enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  Canvas
&lt;/h3&gt;

&lt;p&gt;There are a few common canvas-related bugs that you may run into when dealing with CSS sizing, resolution and adaptive resizing though.  Usually this comes in the form of pixelated shaders, poor u_mouse movement mapping, and the shader just rendering overall at the wrong size.  👾  So!  I took the time experiment with the glslCanvas rendering lifecycle and React's useRef to make a handy functional component that skips you right past these bugs and directly to an easy-to-use canvas the fills whatever container you want to wrap it in.  🍱&lt;/p&gt;

&lt;h3&gt;
  
  
  Resizing helper function
&lt;/h3&gt;

&lt;p&gt;To start, here's a simple helper function that will save you some headache when adaptively sizing the canvas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const resizer = (
    canvas: HTMLCanvasElement,
    container: HTMLDivElement
  ): void =&amp;gt; {
    canvas.width = container.clientWidth + window.devicePixelRatio;
    canvas.height = container.clientHeight + window.devicePixelRatio;
    canvas.style.width = container.clientWidth + "px";
    canvas.style.height = container.clientHeight + "px";
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GLSL Freebie
&lt;/h3&gt;

&lt;p&gt;Also if you haven't worked with GLSL before and want to try out the component, &lt;a href="https://github.com/samasastudio/asa-shaders/blob/master/src/fragments/fbmFrag.ts" rel="noopener noreferrer"&gt;here's a a solid one that works right out of the box without any images&lt;/a&gt;. ✨ Just pass in 'frag' as your prop for frag in the component. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4oi5lc87yvb60fihmrr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4oi5lc87yvb60fihmrr.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Component
&lt;/h3&gt;

&lt;p&gt;Last but not least here is the entire component.  It contains the helper function for sizing the canvas element, as well as a loop that helps set each uniform you want to pass in through the setUniform prop. 🥋  For example, if you wanted to set a uniform called u_image with the value of an image variable, then you could pass in &lt;code&gt;{u_image: image}&lt;/code&gt;.  Also pay close attention to the sequence that glslCanvas instantiates the canvas, sizes it, and then loads the frag.  This is important to the shader connecting its resolution to the canvas size.  🌱&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { FC, useEffect, useRef } from "react";
import GlslCanvas from "glslCanvas";

interface ShaderCanvasProps {
  frag: string;
  setUniforms?: { [key: string]: string };
}

export const ShaderCanvas: FC&amp;lt;ShaderCanvasProps&amp;gt; = (props): JSX.Element =&amp;gt; {

  const canvasRef = useRef&amp;lt;HTMLCanvasElement&amp;gt;();
  const containerRef = useRef&amp;lt;HTMLDivElement&amp;gt;();

  const resizer = (
    canvas: HTMLCanvasElement,
    container: HTMLDivElement
  ): void =&amp;gt; {
    canvas.width = container.clientWidth + window.devicePixelRatio;
    canvas.height = container.clientHeight + window.devicePixelRatio;
    canvas.style.width = container.clientWidth + "px";
    canvas.style.height = container.clientHeight + "px";
  };

  useEffect(() =&amp;gt; {
    const node = canvasRef.current;
    const container = containerRef.current;
    const sandbox = new GlslCanvas(canvasRef.current);
    for (let k in props.setUniforms) {
      sandbox.setUniform(k, props.setUniforms[k]);
    }

    resizer(node, container);
    sandbox.load(props.frag);

    const handler = () =&amp;gt; {
      if (
        node.clientWidth !== container.clientWidth ||
        node.clientHeight !== container.clientHeight
      )
        resizer(canvasRef.current, containerRef.current);
    };

    window.addEventListener("resize", handler);

    return () =&amp;gt; {
      window.removeEventListener("resize", handler);
    };
  }, []);

  return (
    &amp;lt;div ref={containerRef} style={{ width: "100%", height: "100%" }}&amp;gt;
      &amp;lt;canvas ref={canvasRef}&amp;gt;&amp;lt;/canvas&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to see this code alive in the wild, &lt;a href="https://asa-shaders.web.app/" rel="noopener noreferrer"&gt;start here&lt;/a&gt; and please respond with any ideas for refactoring or optimizing!  🛠&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
