Mirror: A frag-canvas custom element to apply Shadertoy fragment shaders to a canvas or image/video element
1# frag-canvas
2
3**A custom element providing a canvas to apply a fragment shader to.**
4
5The `<frag-canvas>` element renders an output canvas and applies a fragment
6shader to it. The canvas' input is either determined by an internal input
7canvas (that can be drawn to using the usual `getContext()` draw context)
8or an input image or video element, passed as a child element.
9
10The fragment shader is sourced from a script child or the element's text
11contents.
12
13The fragment shader may either be written in GLSL ES 100 or GLSL ES 300,
14but the internal context will always be created using WebGL 2.
15
16The fragment shader may use input uniforms that are roughly the same
17as [ShaderToy's](https://www.shadertoy.com/howto) with these
18uniforms being supported:
19
20- `iResolution`
21- `iChannelResolution` (with one channel only)
22- `iTime`
23- `iTimeDelta`
24- `iFrame`
25- `iChannel` (always `0`)
26- `iDate`
27
28Only one channel will be provided (`uniform sampler2D iChannel0`)
29
30### Applying a fragment shader to an image
31
32```html
33<frag-canvas id="canvas">
34 <script type="x-shader/x-fragment">
35 precision mediump float;
36
37 uniform vec2 iResolution;
38 uniform float iTime;
39 uniform sampler2D iChannel0;
40
41 void mainImage(out vec4 fragColor, in vec2 fragCoord) {
42 vec2 uv = fragCoord/iResolution.xy;
43 vec4 texColor = texture2D(iChannel0, uv);
44 float wave = sin(uv.y * 10.0 + iTime) * 0.01;
45 vec2 distortedUV = uv + vec2(wave, 0.0);
46 vec4 finalColor = texture2D(iChannel0, distortedUV);
47 fragColor = finalColor;
48 }
49
50 void main() {
51 mainImage(gl_FragColor, gl_FragCoord.xy);
52 }
53 </script>
54 <img src="./photo.jpg" />
55</frag-canvas>
56```
57
58### Applying a fragment shader to canvas contents
59
60```html
61<frag-canvas id="example">
62 <script type="x-shader/x-fragment">
63 precision mediump float;
64
65 uniform vec2 iResolution;
66 uniform float iTime;
67 uniform sampler2D iChannel0;
68
69 void mainImage(out vec4 fragColor, in vec2 fragCoord) {
70 vec2 uv = fragCoord/iResolution.xy;
71 vec4 texColor = texture2D(iChannel0, uv);
72 float wave = sin(uv.y * 10.0 + iTime) * 0.01;
73 vec2 distortedUV = uv + vec2(wave, 0.0);
74 vec4 finalColor = texture2D(iChannel0, distortedUV);
75 fragColor = finalColor;
76 }
77
78 void main() {
79 mainImage(gl_FragColor, gl_FragCoord.xy);
80 }
81 </script>
82</frag-canvas>
83
84<script>
85 const canvas = document.getElementById('example');
86 const ctx = canvas.getContext('2d');
87
88 requestAnimationFrame(draw() => {
89 ctx.fillStyle = 'red';
90 ctx.fillRect(100, 100, 200, 200);
91 ctx.fillStyle = 'blue';
92 ctx.beginPath();
93 ctx.arc(300, 300, 50, 0, Math.PI * 2);
94 ctx.fill();
95 });
96</script>
97```
98
99### Auto-resizing the canvas while redrawing
100
101```html
102<frag-canvas id="example" autoresize>
103 <script type="x-shader/x-fragment">
104 precision mediump float;
105
106 uniform vec2 iResolution;
107 uniform float iTime;
108 uniform sampler2D iChannel0;
109
110 void mainImage(out vec4 fragColor, in vec2 fragCoord) {
111 vec2 uv = fragCoord/iResolution.xy;
112 vec4 texColor = texture2D(iChannel0, uv);
113 float wave = sin(uv.y * 10.0 + iTime) * 0.01;
114 vec2 distortedUV = uv + vec2(wave, 0.0);
115 vec4 finalColor = texture2D(iChannel0, distortedUV);
116 fragColor = finalColor;
117 }
118
119 void main() {
120 mainImage(gl_FragColor, gl_FragCoord.xy);
121 }
122 </script>
123</frag-canvas>
124
125<script>
126 const canvas = document.getElementById('example');
127 const ctx = canvas.getContext('2d');
128
129 requestAnimationFrame(function draw() {
130 ctx.fillStyle = 'red';
131 ctx.fillRect(100, 100, 200, 200);
132 ctx.fillStyle = 'blue';
133 ctx.beginPath();
134 ctx.arc(300, 300, 50, 0, Math.PI * 2);
135 ctx.fill();
136 requestAnimationFrame(draw);
137 });
138</script>
139```