Skip to content

Instantly share code, notes, and snippets.

@pexavc
Last active February 2, 2022 08:12
Show Gist options
  • Save pexavc/4ca60bd507907f04b23f976a73a3b261 to your computer and use it in GitHub Desktop.
Save pexavc/4ca60bd507907f04b23f976a73a3b261 to your computer and use it in GitHub Desktop.
Test webGL shaders from a single html file using GLSL Canvas. Enter the raw shader code into the text box and click submit. A super light-weight alternative to shader toy.
<!DOCTYPE html>
<html>
<head>
<meta property="og:image" content="https://gateway.ipfs.io/ipfs/QmQt9J74g3daLLG12nTH4VpUMst3Y51uCcSYCgkWbyppSA" /><meta name="description" content="Lightweight shader toy."><title>Marble Shader Toy</title>
<meta name="viewport" content="width=device-width">
<meta name="keywords" content="shader, generator">
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<style>
@import url('https://fonts.googleapis.com/css2?family=Courier+Prime:wght@400&display=swap');
@import url('https://fonts.googleapis.com/css?family=Playfair+Display:400,400i,700,700i,900,900i');
.container {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.containerData {
display: flex;
justify-content: center;
width: 100%;
height: 100vh;
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
.codeContainer {
display: flex;
justify-content: center;
width: 100%;
height: 100vh;
position: absolute;
top: 0;
left: 0;
z-index: 2;
overflow: hidden;
}
#canvas2 {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
.slideAnim {
animation-name: slide;
animation-duration: 2s;
animation-fill-mode: forwards;
/*New content */
-webkit-animation-fill-mode: forwards;
}
@keyframes slide {
from {
opacity: 1.0;
}
to {
opacity: 0.0;
}
}
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
<script type="text/javascript">
function compile() {
localStorage.clear();
let t = document.getElementById('shaderCode').value;
var name = localStorage.getItem("name");
if (name !== null) t = name;
let oCT = document.getElementById("canvas2");
oCT.parentNode.removeChild(oCT);
let cT = document.getElementById("canvasContainer");
cT.innerHTML = "<canvas id='canvas2' class='glslCanvas' data-fragment='"+t+"' width='631px' height='631px'></canvas>";
localStorage.setItem("name", t);
return true;
}
var index = 0;
function refreshScript (src) {
console.log(index);
var scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
scriptElement.src = src + '?' + index++;
document.getElementsByTagName('body')[0].prepend(scriptElement);
}
window.onload = function() {
var t = localStorage.getItem("name");
if (t !== null) {
let oCT = document.getElementById("canvas2");
oCT.parentNode.removeChild(oCT);
let cT = document.getElementById("canvasContainer");
cT.innerHTML = "<canvas id='canvas2' class='glslCanvas' data-fragment='"+t+"' width='631px' height='631px'></canvas>";
}
}
</script>
</head>
<body>
<script type="text/javascript" src="https://rawgit.com/patriciogonzalezvivo/glslCanvas/master/dist/GlslCanvas.js">
</script>
<div class="containerToTHEContainerheh">
<div id="canvasContainer" class="containerData">
<canvas id="canvas2" class="glslCanvas" data-fragment="" width="631px" height="631px"></canvas>
</div>
<div class="codeContainer">
<form onsubmit="return compile()">
<textarea id="shaderCode" rows="5" cols="60" name="text" placeholder="Enter text"></textarea>
<br/>
<input type="submit" value="compile"/>
</form>
</div>
</div>
</body>
</html>
@pexavc
Copy link
Author

pexavc commented Feb 2, 2022

Make sure to use these headers in your shader code. Simply put them at the top of your text input.

precision highp float;
uniform vec2 u_resolution;
uniform float u_time;
uniform vec2 u_position;

These are provided values. Frag colors and coords should also be changed (if needed) as so gl_FragCoord, gl_FragColor.

Always leave your main function empty like so void main() { .

Enjoy!

@pexavc
Copy link
Author

pexavc commented Feb 2, 2022

Example shader:

precision highp float;
uniform vec2 u_resolution;
uniform float u_time;
uniform vec2 u_position;
                
const float cloudscale = 2.1;
const float speed = .20;
const float clouddark = 0.5;
const float cloudlight = 0.9;
const float cloudcover = 0.7;
const float cloudalpha = 100.0;
const float skytint = 0.5;
const vec3 skycolour1 = vec3(0.9, 0.1, 10.6);
const vec3 skycolour2 = vec3(0.4, 1.1, 01.0);

const mat2 m = mat2( 1.9,  1.2, -1.2,  0.9 );

vec2 hash( vec2 p ) {
    p = vec2(dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)));
    return -1.0 + 2.0*fract(sin(p)*43758.5453123);
}

float noise( in vec2 p ) {
    const float K1 = 0.366025404; // (sqrt(3)-1)/2;
    const float K2 = 0.211324865; // (3-sqrt(3))/6;
    vec2 i = floor(p + (p.x+p.y)*K1);   
    vec2 a = p - i + (i.x+i.y)*K2;
    vec2 o = (a.x>a.y) ? vec2(1.0,0.0) : vec2(0.0,1.0); //vec2 of = 0.5 + 0.5*vec2(sign(a.x-a.y), sign(a.y-a.x));
    vec2 b = a - o + K2;
    vec2 c = a - 1.0 + 2.0*K2;
    vec3 h = max(0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
    vec3 n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));
    return dot(n, vec3(70.0));  
}

float fbm(vec2 n) {
    float total = 0.0, amplitude = 0.5;
    for (int i = 0; i < 7; i++) {
        total -= noise(n) * amplitude;
        n = m * n;
        amplitude *= 0.5;
    }
    return total;
}

// -----------------------------------------------

void main() {
    vec2 p = gl_FragCoord.xy / u_resolution.xy;
    vec2 uv = p*vec2(u_resolution.x/u_resolution.y,1.0);    
    float time = u_time * speed;
    float q = fbm(uv * cloudscale * 0.5);
    
    //ridged noise shape
    float r = 0.0;
    uv *= cloudscale;
    uv -= q - time;
    float weight = 0.8;
    for (int i=0; i<8; i++){
        r += abs(weight*noise( uv ));
        uv = m*uv + time;
        weight *= 0.7;
    }
    
    //noise shape
    float f = 0.0;
    uv = p*vec2(u_resolution.x/u_resolution.y,1.0);
    uv *= cloudscale;
    uv -= q - time;
    weight = 0.9;
    for (int i=0; i<8; i++){
        f += weight*noise( uv );
        uv = m*uv + time;
        weight *= 0.6;
    }
    
    f *= r + f;
    
    //noise colour
    float c = 0.0;
    time = u_time * speed * 2.0;
    uv = p*vec2(u_resolution.x/u_resolution.y,1.0);
    uv *= cloudscale*2.0;
    uv -= q - time;
    weight = 0.4;
    for (int i=0; i<7; i++){
        c += weight*noise( uv );
        uv = m*uv + time;
        weight *= .6;
    }
    
    //noise ridge colour
    float c1 = 0.0;
    time = u_time * speed * 3.0;
    uv = p*vec2(u_resolution.x/u_resolution.y,1.0);
    uv *= cloudscale*3.0;
    uv -= q - time;
    weight = 0.1;
    for (int i=0; i<7; i++){
        c1 += abs(weight*noise( uv ));
        uv = m*uv + time;
        weight *= 0.2;
    }
    
    c += c1;
    
    vec3 skycolour = mix(skycolour2, skycolour1, (p.x + p.y) * .7);
    vec3 cloudcolour = vec3(9.10, 0.0, 0.0) * clamp((clouddark + cloudlight*c), 0.0, 0.0);
   
    f = cloudcover + cloudalpha*f*r;
    
    vec3 result = mix(skycolour, clamp(skytint * skycolour + cloudcolour, 0.0, 0.0), clamp(f + c, 0.0, 1.0));
    
    gl_FragColor = vec4( result, 1.0 );
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment