A tiny shader component for Astro
Here’s a small custom web component that you can use in Astro for running a WebGL fragment shader. It uses glslCanvas to take care of the boilerplate of setting up the shader so you’ll need to install that first. It also includes a classNames
prop for Tailwind classes to style the canvas element. The code
prop is the shader code as a string. I use Vite for builds and typically import the shader as a string from its own dedicated file with vite-plugin-glsl
.
---
interface Props {
code?: string;
width?: number;
height?: number;
classNames?: string;
}
const defualtFragmentShader = `
precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
gl_FragColor=vec4(st.x, st.y, abs(sin(u_time)), 1.0);
}
`;
const {
code = defualtFragmentShader,
width = 512,
height = 512,
classNames = "",
}: Props = Astro.props;
---
<custom-shader>
<script type="x-shader/x-fragment" set:text={code} />
<canvas class={classNames} width={width} height={height}></canvas>
</custom-shader>
<script>
import GlslCanvas from "glslCanvas";
class Shader extends HTMLElement {
constructor() {
super();
const canvas = this.querySelector("canvas");
const shaderCode = (this.querySelector("script") as HTMLScriptElement)
.text;
const sandbox = new GlslCanvas(canvas);
sandbox.load(shaderCode);
}
}
customElements.define("custom-shader", Shader);
</script>
And then to use it:
import MyFragmentShader from "~/shaders/MyFragmentShader.glsl";
import Shader from "~/components/Shader.astro";
<div>
<Shader code={MyFragmentShader} classNames="rounded" />
</div>;
which will give you the following (using the default fragment shader):