# shader-doodle puts a fragment shader canvas in one HTML tag

> shader-doodle is a web component that renders a GLSL fragment shader on a flat responsive canvas, with built in uniforms for time, resolution and mouse, a texture component for images, video, canvas and webcam input, and a Shadertoy compatibility mode. This branch is the alpha rewrite, and the stable version lives on the v0 branch.

**mmmerl/shader-doodle** — A friendly web-component for writing and rendering shaders.

- Repository: https://github.com/mmmerl/shader-doodle
- Website: https://shader-doodle-overview.glitch.me/
- Stars: 589 · Forks: 37
- Language: JavaScript
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/mmmerl-shader-doodle

## A shader in a script tag inside a component

The core idea is small enough to state in one sentence. shader-doodle is a simple web component loosely based on The Book of Shaders' glsl previewer and on Shadertoy, and it sets up a flat responsive canvas on which to draw fragment shaders, providing several built in uniforms relating to time, resolution and mouse position. The API section is honest that right now the api is fairly basic, and that matters for setting expectations. What you write is GLSL, the default syntax is vanilla glsl, and the fragment shader goes in a script element with a custom type.

```html
<script src="https://unpkg.com/shader-doodle@alpha"></script>
<shader-doodle>
  <script type="x-shader/x-fragment">
    void main() {
      vec2 st = gl_FragCoord.xy / u_resolution.xy;
      vec3 color = vec3(st.x, st.y, abs(sin(u_time)));

      gl_FragColor = vec4(color, 1.0);
    }
  </script>
</shader-doodle>
```

The custom script type is the interesting design decision. A browser will not execute a script it does not recognise, so a non standard type keeps the shader source inert until the component reads it and compiles it. That means the shader is not a string you have to escape, and it is not a JavaScript string either, so the editor tooling that highlights GLSL inside a page has something to recognise. The canvas is described as flat and responsive, which means the component sizes itself to its container and there is no separate viewport element to manage. This is the friendly web component the title promises, and the screenshots in the README, ranging from a simple hello shader to raymarching with clouds, are all built on the same three lines of GLSL.

## Two uniform naming schemes, because Shadertoy muscle memory is widespread

The pre-defined uniforms list is the API in full, and it comes in two flavours. The default mode exposes a uniform float u_time for shader playback time in seconds, u_delta for the delta time between frames, an int u_frame for the playback frame, a vec4 u_date with year, month, day and seconds, a vec2 u_resolution for viewport resolution in pixels, a vec2 u_mouse for mouse pixel coordinates, a vec4 u_mousedrag holding the last click or current drag position in xy and the starting drag position in zw, flipped negative when not mousedown, and a vec3 u_orientation carrying the device orientation API values alpha, beta and gamma. The Shadertoy mode, enabled by putting the shadertoy attribute on the element, exposes the same values under the names a Shadertoy shader expects: iTime, iDelta, iFrame, iDate, iResolution, iCurrentMouse, iMouse and iOrientation. The README flags the slight difference in mouse uniform naming between the two, which is the one place a shader ported from one convention to the other will not compile as written.



This is a small decision with a large audience effect. Everyone who has written a Shadertoy shader knows the i names, and everyone who has followed The Book of Shaders knows the u names, and the component serves both by renaming the uniforms rather than asking the user to rewrite them. The device orientation uniform is the one that shows the component is aimed at more than static images, since it opens up a phone or tablet tilting the canvas as an input.

## Textures from an image, a video, a canvas or the camera

The second component is sd-texture, and it is what turns a shader from a demo into something that reacts to input. Textures can be used as a sampler2D in a shader by using the sd-texture component, and it passes in two uniforms, a sampler2D with the texture name and a vec2 with the texture name followed by _resolution. The attributes are what make it flexible. The src attribute is the source of an image or video, or a selector for a canvas. The name attribute specifies a name for the texture uniform, defaulting to u_texture with the index appended. The webcam attribute overrides src and tries to use the WebRTC webcam as the texture source. And force-update forces a texture to always update, which the README says is useful when using a canvas animation or an animated gif as a texture.

```html
<shader-doodle>
  <sd-texture src="image.jpg"></sd-texture>
  <script type="x-shader/x-fragment">
    uniform sampler2D u_texture0;

    void main() {
      vec2 uv = gl_FragCoord.xy / u_resolution.xy;
      vec4 texture = texture2D(u_texture0, uv);

      gl_FragColor = texture;
    }
  </script>
</shader-doodle>
```

The name attribute is the key to multiple textures, since each one needs a distinct sampler and the README shows a two-texture example, and the demo directory confirms the range with files for an image element, an image file, a video element, a video file, a canvas element, a canvas with force update, a webcam, audio, orientation, a React integration, a Node.js integration, and a multi-doodle page. That demo list is a good map of the component's intended uses, and it shows the author expected it to be embedded in other frameworks rather than used only standalone.

## Installing it: a script tag or an npm import

There are two installation paths, and both are one line. The script include loads the component from a CDN with the alpha dist tag.

```html
<script src="https://unpkg.com/shader-doodle@alpha"></script>
```

The other route is a package install of shader-doodle at the alpha tag followed by an import of the package.

```javascript
import 'shader-doodle';
```

The package metadata explains the build. The package is named shader-doodle, the version in the repository is 1.0.0-alpha.22, the MIT licence is declared, and the published entry points are three separate bundles, a CommonJS build at dist/shader-doodle.cjs.js, an ES module build at dist/shader-doodle.esm.js and a UMD build at dist/shader-doodle.umd.js, with the files array shipping only the dist directory. The build is Rollup, with the closure compiler plugin for minification and Babel for transpilation, and the Babel targets are given as the last two versions of Chrome, ChromeAndroid, Safari, iOS Safari, Firefox, FirefoxAndroid and Edge, which is a sensible compatibility target for a component that is likely to be embedded in an existing page rather than controlled by the developer. There is a dev script that runs Rollup in watch mode, a precommit hook through lint-staged and husky, and pretty scripts that run Prettier over the source and prettier-package-json over the manifest.

## The alpha branch, and where the stable version lives

The most important line for anyone planning to depend on this is the note at the top of the README, which says that this README and branch are for the new shader-doodle alpha, and that to view the current stable version you should go to the v0 branch. That is a rewrite rather than an increment, and the repository name in the package metadata points at the shader-doodle organisation rather than the fork you are reading, so the alpha lineage is shared. The version string says the same thing, 1.0.0-alpha.22, and the install instructions tag the alpha dist explicitly, both for the script include and for the npm install. There are no GitHub releases on record, so the version in the package manifest is the version you can reason about, and the alpha suffix means it can change under you. The repository is not archived and the last push was on 2026-09-15, so work is happening on the alpha, and the two branches are likely to diverge for some time. If you are writing a tutorial or a demo, the alpha is the interesting version because it is the one that matches the component API described above. If you are shipping something, the v0 branch and its published package are the safer bet, and you should read that documentation rather than this one.

## How this compares to writing the WebGL boilerplate yourself

The alternative is the obvious one, a hundred lines of WebGL setup per page, and the difference in approach is worth naming. Writing it yourself means the shader lives in a JavaScript template string, the uniforms are locations you look up and set each frame, the canvas is an element you size yourself, and a texture is something you upload and bind. The component inverts each of those. The shader is a script element of a custom type, so it is real text in your markup rather than a string in your code, the uniforms are named values the component supplies, the canvas is created and sized for you, and a texture is a child element with attributes. The second alternative is an existing shader playground embedded in an iframe, which gives you a full editor and a full feature set at the price of the iframe, the sandbox, and the fact that your shader is not in your page. The component sits between the two, and its restriction is what defines it, since there is no built-in editor, and the API is fairly basic. The other end of the spectrum is writing a full Shadertoy compatible runtime, which is a large project, and the shadertoy attribute here is a naming shim rather than an attempt at that.

## Conclusion

shader-doodle suits someone teaching GLSL, writing a small creative coding demo, or prototyping a fragment shader inside an ordinary page, since a shader is a script tag inside a component and the uniforms follow the Book of Shaders conventions most learners already know. It is the wrong tool if you need the full Shadertoy feature set, because the API is described as fairly basic and the Shadertoy mode is a naming compatibility layer rather than a port of the platform, and it is the wrong tool if you need a stable dependency, since this branch is the alpha and the stable release sits on the separate v0 branch. Before you depend on it, check the version you are pinning, because the package is published as 1.0.0-alpha.22 and the tags carry an @alpha dist tag, and read the notes on the difference between the u_ and i_ uniform names, because the mouse uniform is spelled differently in the two modes.

## FAQ

### How do I use shader-doodle in a page?

Load it with a script tag from unpkg at the alpha tag, or install it with npm install shader-doodle@alpha and import it, then put your fragment shader in a script element of type x-shader/x-fragment inside a shader-doodle element. The component sets up the canvas and supplies the built in uniforms.

### What uniforms does shader-doodle provide?

In the default mode: u_time, u_delta, u_frame, u_date, u_resolution, u_mouse, u_mousedrag and u_orientation. In Shadertoy mode the same values are exposed as iTime, iDelta, iFrame, iDate, iResolution, iCurrentMouse, iMouse and iOrientation, enabled with the shadertoy attribute on the element.

### Can shader-doodle use images, video or the webcam as a texture?

Yes, through the sd-texture component, which passes a sampler2D and a matching _resolution uniform. The src attribute takes an image, a video or a canvas selector, the webcam attribute overrides src to use the WebRTC camera, and force-update keeps a canvas animation or animated gif updated every frame.

## Sources

- [Issues](https://github.com/mmmerl/shader-doodle/issues)
- [License: MIT](https://github.com/mmmerl/shader-doodle/blob/main/LICENSE)
- [mmmerl/shader-doodle on GitHub](https://github.com/mmmerl/shader-doodle)
- [Project website](https://shader-doodle-overview.glitch.me/)
- [README](https://github.com/mmmerl/shader-doodle/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mmmerl-shader-doodle
