Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Displays GLSL fragment shaders as a website background. Supports offscreen buffers and floating point textures on almost any browser and hardware. Compatible with Shadertoy.

License

NotificationsYou must be signed in to change notification settings

xemantic/shader-web-background

Repository files navigation

Displays GLSL fragment shaders as a website background. Supports Shadertoy shaders,multipass - ping-pong offscreen buffers, feedback loops, floating-point textures.Either with WebGL 1 or 2, will try to run wherever it's technically possible.

Website/Demo: 🎆https://xemantic.github.io/shader-web-background 🎇

❔🌈👼👷 To ask questions go toxemantic discord server ☕🍵🍓👾

shader-web-background logo

I designed this library to use complex fragment shaders as part of my web design and developmentprocess. This is the tool which finally lets me embrace the web browser as a creative codingenvironment. If you are familiar with GLSL, then it might help you publish your work onweb as well. If you are coming from a web development background,then you might want to learn a bit more about shaders first, for example fromThe Book of Shaders. I hope that examples presentedin this documentation are self-explanatory. If you find it useful, then

❤️ Sponsor xemantic on GitHub orBuy me a teahttps://www.buymeacoffee.com/kazik

Kazik (morisil) Pogoda

https://xemantic.com/


Table of Contents

Features

  • simplicity: it is just rendering canvas background as fragment shader.
  • speed: designed to be embedded in HTML and start rendering before other page resourcesare downloaded.
  • extensibility: adding own interaction and controls is trivial.
  • convenience: straightforwardAPI, specific errors will inform you about mistakeswhich are otherwise hard to debug.
  • minimal footprint: transpiled from JavaScript to JavaScript withGoogle Closure Compiler.
  • pixel feedback loops: preserving movement in time on offscreen buffers with floating–point precision.
  • Shadertoy support: including multipass shaders
  • cross browser / cross device: on Chrome, Safari, Firefox or Edge, either with WebGL 1 or 2,on Linux, Windows, Mac, iPhone or Samsung phone — it will use optimal strategy to squeeze out what's possible from the browser and the hardware.

Adding shader-web-background to your projects

TL;DR:

<!DOCTYPE html><htmllang="en"><head><metacharset="utf-8"><title>Minimal shader</title><metaname="viewport"content="width=device-width, initial-scale=1"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><scriptsrc="https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js"></script><scripttype="x-shader/x-fragment"id="image">precisionhighpfloat;uniformfloatiTime;voidmain(){gl_FragColor=vec4(mod(gl_FragCoord.x/256.,1.),mod((gl_FragCoord.x+gl_FragCoord.y-iTime*40.)/256.,1.),mod(gl_FragCoord.y/256.,1.),1.);}</script><script>shaderWebBackground.shade({shaders:{image:{uniforms:{iTime:(gl,loc)=>gl.uniform1f(loc,performance.now()/1000)}}}});</script><style>    .shader-web-background-fallback {background:url("https://placekitten.com/666/666");background-position: center;background-size: cover;background-attachment: fixed;    }</style></head><body><h1>shader-web-background minimal example</h1></body></html>

ℹ️ If you prefer to learn by example, here is the list of demos displayedwith their highlighted source code:

https://xemantic.github.io/shader-web-background/#demo

There are several ways of adjusting this library to your needs:

Step 1 - Add library to your project

Option A - Embedded minified library directly in HTML

If you want your shaders to start rendering before any other resources are loaded,then go for this method. Just take the contents of:

https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js

and put it as<script> in the<head> of your HTML file.

Seeminimal demo for reference(live version).

Option B - Reference the minified library

Add this code to the<head> of your HTML:

<scriptsrc="https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js"></script>

Option C - Download distribution

In the future I will publishshader-web-background to npm. For now you can justdownload the latest minified distribution together with source map and sources.

Step 2 - Add your fragment shaders

You will need at least one fragment shader defined like this:

<scripttype="x-shader/x-fragment"id="image">precisionhighpfloat;voidmain(){// ...}</script>

Put it in the<head> of your HTML. Thetype should bex-shader/x-fragment andtheid attribute is arbitrary.

⚠️ Note: Remember to give uniqueid to each of your shaders if you aredefining more of them.

Step 3 - Start shading

<script>  shaderWebBackground.shade({shaders:{image:{}}});</script>

⚠️ Note: the shader nameimage should match the one defined asshader sourceid attribute.

Step 4 - Specify fallback styles

ℹ️ This step is not necessary, however adding it will improvethe experience for the small amount of users who still cannotrun shaders on their devices.

Define fallback CSS style, for example a static screenshot of your shader frame:

<style>  .shader-web-background-fallback {background:url("https://placekitten.com/666/666");background-position: center;background-size: cover;background-attachment: fixed;      }</style>

Theshader-web-background-fallback CSS class is applied to HTML document root andthe canvas.

⚠️ Note that in case of any errors the default canvas will not be attachedto HTML document at all. In case of shading a canvas which is already attachedto HTML, it might be tempting to provide a fallback canvas background based on theshader-web-background-fallback CSS class, however it might not work on some browsers.Custom error handler might be needed for cross compatibility.

SeeHandling errors section for details.

shader-web-background API

See the fullshader-web-background API

Configuring shading

Theconfiguration object passed to theshaderWebBackground.shade(config)call in the example above will result in a minimal rendering pipeline consisting of one fragmentshader namedimage. A new static<canvas> element covering the whole viewportwill be added to the page withz-index: -9999, to be displayed behind other page elements.

ℹ️ Note: the default<canvas> element will be attached to document<body> only when the whole DOM tree is constructed. Also the actual renderingof shader frames will not happen until the page is fully loaded, even though shadersare compiled immediately.

Adding shader uniforms

About uniforms

Uniforms provide shaders with the input from the world outside GPU.Describing this mechanism is out of scope of this documentation.I decided not to build abstraction over this part of WebGL, because it isalready quite concise. SeeWebGLRenderingContext.uniform documentation.

Let's assume that you want to provide your shader with a time value measuredin seconds since the moment the page was loaded. First define a uniform in theimage shader:

uniformfloat iTime;

TheiTime name is arbitrary, but it should match with what youspecify in the configuration:

shaderWebBackground.shade({shaders:{image:{uniforms:{iTime:(gl,loc)=>gl.uniform1f(loc,performance.now()/1000)}}}});

The(gl, loc) => gl.uniform1f(loc, performance.now() / 1000) function willbe invoked before rendering each shader frame. If you are not familiar withJavaScript arrow functions,it's an equivalent of:

function(gl,loc){gl.uniform1f(loc,performance.now()/1000)}

ℹ️ Check documentation of the standard JavaScriptperformance.now()function which returns the number of milliseconds since the page was loaded.Dividing it by1000 will result in floating-point value measured in seconds.

⚠️ During development check the console often. If you will forget to configurea uniform declared in the shader, then exception will be thrown (Seeerror-no-configuration-of-shader-uniformtest case). Also if you configure a uniform which does not exist in the shader,then a warning will pop up on console (seeerror-unnecessary-uniform-configuredtest case).

Summary: you can use this mechanism to adapt any API as an input of your shaders.Check projectdemos forexamples how to integrate input like:

  • mouse (fullscreen augmentation of the pointer)
  • scrolling position (parallax scrolling effect)
  • device orientation (fullscreen reaction to device tilting)
  • externally computed coefficients controlling the animation

Textures as uniforms

The declaration of "texture" uniform usessampler2D type:

uniformsampler2D iWebCam;

ℹ️ The uniform name is arbitrary. For exampleShadertoy isbinding textures under nameiChannel0,iChannel1, etc. and this is the conventionused mostly in this documentation.

Such a uniform can be set with:

shaderWebBackground.shade({onInit:(ctx)=>{ctx.iWebCam=initializeTexture(ctx.gl);},shaders:{image:{uniforms:{iWebCam:(gl,loc,ctx)=>ctx.texture(loc,ctx.iWebCam);}}}});

ℹ️ thetexture passed as a second argumenttoctx.texture can be either an instance ofWebGLTexture ora reference to the buffer of another shader in the pipeline. CheckComplex config example section andAPI - Context: buffers.

SeeAdding textures section for details on how to load a texture froman image.

Initializing shader texture

All the shaders, except for the last one in the pipeline, will have associated textures torender to. By default these textures are initialized as RGBAHALF_FLOAT (16bit) floating-pointwith linear interpolation and are clamped to the edge. The texture initialization can becustomized. SeeAPI - Shader: texture documentation for details.

⚠️ Note: the default settings will work on all the platforms while customizationcan easily break the compatibility, especially on older iOS devices. Consult the APIfor remedies.

Complex config example

Here is a comprehensive example of aconfiguration object withcomments. It is usingShadertoy conventions for naming buffers and uniformsbut keep in mind that the naming is arbitrary and might be adjusted to the needsof your project.

// mouse coordinates taken from from the mousemove event expressed in "CSS pixels"varmouseX;varmouseY;document.addEventListener("mousemove",(event)=>{mouseX=event.clientX;mouseY=event.clientY;});shaderWebBackground.shade({// supplied canvas to use for shadingcanvas:document.getElementById("my-canvas"),// called only once before the first runonInit:(ctx)=>{// we can center the mouse even before any "mousemove" event occurs// note, we aremouseX=ctx.cssWidth/2;mouseY=ctx.cssHeight/2;// for convenience you can store your attributes on contextctx.iFrame=0;},onResize:(width,height,ctx)=>{ctx.iMinDimension=Math.min(width,height);},onBeforeFrame:(ctx)=>{ctx.shaderMouseX=ctx.toShaderX(mouseX);ctx.shaderMouseY=ctx.toShaderY(mouseY);},shaders:{// the first buffer to be rendered in the pipelineBufferA:{// uniform setters, attribute names should match with those defined in the shaderuniforms:{// uniform value calculated in placeiTime:(gl,loc)=>gl.uniform1f(loc,performance.now()/1000),// uniform values taken from contextiFrame:(gl,loc)=>gl.uniform1i(loc,ctx.iFrame),iMinDimension:(gl,loc,ctx)=>gl.uniform1f(loc,ctx.iMinDimension),iResolution:(gl,loc,ctx)=>gl.uniform2f(loc,ctx.width,ctx.height),iMouse:(gl,loc,ctx)=>gl.uniform2f(loc,ctx.shaderMouseX,ctx.shaderMouseY),// inputing the previous output of itself - feedback loopiChannel0:(gl,loc,ctx)=>ctx.texture(loc,ctx.buffers.BufferA)// ... more uniforms}},// ... more shadersBufferD:{// optional custom initializer of buffer's texturetexture:(gl,ctx)=>{// initializing floating-point texture in custom way for WebGL 1 and 2ctx.initHalfFloatRGBATexture(ctx.width,ctx.height);// standard WebGL texture parametersgl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.REPEAT);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.REPEAT);},uniforms:{iChanel0:(gl,loc,ctx)=>ctx.texture(loc,ctx.buffers.BufferA)// ... more uniforms}},// the last shader will render to screenImage:{uniforms:{iChanel0:(gl,loc,ctx)=>ctx.texture(loc,ctx.buffers.BufferD)// ... more uniforms}}},onAfterFrame:(ctx)=>{ctx.iFrame++;},// custom error handleronError:(error,canvas)=>{canvas.remove();console.error(error);document.documentElement.classList.add("my-fallback");}});

The API is intended to be self explanatory. CheckAPI specification for details.There are several shaders defined in the example above. They will be processed in sequencecalledMultipass inShadertoy nomenclature. The last of defined shaders will render to screen.The output of previous shaders, including feedback loop of the previous frame rendered by the sameshader, can be easily passed to uniforms.

Handling errors

Several validations are being performed on supplied configuration to avoid common problemswhich are usually hard to debug otherwise. Thesrc/test/html/errors/folder contains all the error test cases which can be also checked onthelive demo of error handling.

All the errors and warnings will be visible on console.

See:

Shader GLSL version

⚠️ This library relays on WebGL 1 as a common denominator, therefore even if it will useWebGL 2 whenever it is supported in runtime, the shader code should be still compatible withGLSL ES 1.00

Adding mouse support

// mouse coordinates taken from from the mousemove eventvarmouseX;varmouseY;document.addEventListener("mousemove",(event)=>{mouseX=event.clientX;mouseY=event.clientY;});// mouse coordinates relative to the shader, you can also store them on the contextvarshaderMouseX;varshaderMouseY;shaderWebBackground.shade({onInit:(ctx)=>{// screen centermouseX=ctx.cssWidth/2;mouseY=ctx.cssHeight/2;},onBeforeFrame:(ctx)=>{shaderMouseX=ctx.toShaderX(mouseX);shaderMouseY=ctx.toShaderY(mouseY);},shaders:{image:{uniforms:{iMouse:(gl,loc)=>gl.uniform2f(loc,shaderMouseX,shaderMouseY)}}}});

ℹ️ Note: initial mouse coordinates are provided inonInit functionbecause the firstmousemove event can happen long after the shader is started. Shadercoordinates start at the bottom-left corner of the canvas and are aligned with the middleof the pixel -(0.5, 0.5).

API reference:

Demos:

Adding textures

⚠️ Working with textures locally will be limited by the same security mechanisms whichprevent them from being loaded from a different domain(explanation). Forlocal testing you might want to start local HTTP server. E.g.:python -m http.server 8000 ifit doesn't work on your latest ubuntu than runsudo apt install python-is-python3 first.

Seetexture: Blue Marble to Flat Earth mappingdemo

Textures can be set in the same way buffers are set as uniforms, but first we need to load them.For example by defining custom Promise which can be reused:

constloadImage=(src)=>newPromise((resolve,reject)=>{letimg=newImage();img.onload=()=>resolve(img);img.onerror=()=>{reject(newError("Failed to load image from: "+src));}img.src=src;});

TheonInit function is quite a convenient place for callingloadPicture:

shaderWebBackground.shade({onInit:(ctx)=>{loadImage("texture.jpg").then(image=>{constgl=ctx.gl;consttexture=gl.createTexture();gl.bindTexture(gl.TEXTURE_2D,texture);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR);gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,image);gl.bindTexture(gl.TEXTURE_2D,null);ctx.iTexture=texture;});},shaders:{image:{uniforms:{iTexture:(gl,loc,ctx)=>ctx.texture(loc,ctx.iTexture)}}}});

Shadertoy support

This library can utilizeShadertoy code with minimal effort - a simple shader wrapping:

<scripttype="x-shader/x-fragment"id="Image">precisionhighpfloat;uniformvec2iResolution;uniformfloatiTime;// ... other needed uniforms// -- Paste your Shadertoy code here:// ...// -- End of Shadertoy codevoidmain(){mainImage(gl_FragColor,gl_FragCoord.xy);}</script>

Theid attribute of the<script> is set to reflectShadertoy tab calledImage.Most shaders will use at least these 2 uniforms, and it's easy to provide theirvalues in the configuration:

shaderWebBackground.shade({shaders:{Image:{uniforms:{iResolution:(gl,loc,ctx)=>gl.uniform2f(loc,ctx.width,ctx.height),iTime:(gl,loc)=>gl.uniform1f(loc,performance.now()/1000),}}}});

Shadertoy demos:

What to do with Shadertoy "Common" tab?

There is no automated solution for that. You will have to copy theCommon part directlyinto your shaders, just above the otherShadertoy code.

What to do withtexture function?

InShadertoy textures are accessed with thetexture function while in WebGL 1 it istexture2D. Here is a simple workaround to be added before the original code:

#define texturetexture2D

Handling Shadertoy texture parameters

InShadertoy each "Channel" binding a texture can have separate sampler parameterslike interpolation or wrapping. This functionality cannot be easily ported to WebGL 1,but most shaders relaying on these features can be adjusted with code-based workarounds.For example if the texture is supposed to be repeated, then something like this might bea functional replacement of thetexture function in a given shader:

vec4 repeatedTexture(insampler2D channel,invec2 uv) {returntexture2D(channel,mod(uv,1.));}

⚠️ Mipmaps are not supported.

See alsoAPI - Shader: texture.

How to handle "Multipass" Shadertoy shaders?

You can name your shaders according toShadertoy buffer names:

  • BufferA
  • BufferB
  • BufferC
  • BufferD
  • Image

And then wire them together:

<!DOCTYPE html><htmllang="en"><head><title>Multipass Shadertoy shader</title><scripttype="x-shader/x-fragment"id="BufferA">precisionhighpfloat;uniformsampler2DiChannel0;// ... the code of BufferA tab with the uniforms and wrapping as above</script><scripttype="x-shader/x-fragment"id="Image">precisionhighpfloat;uniformsampler2DiChannel0;// ... the code of Image tab with the uniforms and wrapping as above</script><script>// ... your prefer method of loading shader-web-background as described above</script><script>shaderWebBackground.shade({shaders:{BufferA:{uniforms:{iChannel0:(gl,loc,ctx)=>ctx.texture(loc,ctx.buffers.BufferA)}},Image:{uniforms:{iChannel0:(gl,loc,ctx)=>ctx.texture(loc,ctx.buffers.BufferA)}}}});</script></head><body></body></html>

Own vertex shader

It's possible to alter default vertex shader for each fragment shader by providingthe following script in the<head>:

<scripttype="x-shader/x-vertex"id="shaderIdVertex">  attribute vec2 V;  varying vec2 uv;  void main(){gl_Position=vec4(V,0,1);}</script><scripttype="x-shader/x-fragment"id="shaderId">// ...varyingvec2uv;// ...</script>

ℹ️ Note: the scripttype is set tox-shader/x-vertex and theid attribute is prepended withVertex suffix. The vertex attribute should be namedV.

ℹ️ Note:varying vec2 uv can be specified to be shared between vertexand fragment shaders (not added by default).

General tips

  • set the html background color to the dominant color of your shader to avoid flickeringon page load

Building

git clone https://github.com/xemantic/shader-web-background.gitcd shader-web-background./gradlew compileJs

It will trigger Google Closure Compiler which will check sources using type informationand transpile them into minified JavaScript files:

Contributing

Code conventions

This project has been developed usingIntelliJ IDEA withgoogle-java-formatplugin enabled. The most noticeable element of this style are 2 spacesinstead of 4 for rendering tabs.

Adding your project to the list of project using this library

Either:

  • fork this repo
  • openindex.html and scroll to<section>
  • add your project to the list
  • create pull-request

Orsend me a link with description.

Tools and dependencies

TODO

  • remove h1 on iphone as an alternative to real fullscreen
  • add an option to install as a home app on android and iOS

About

Displays GLSL fragment shaders as a website background. Supports offscreen buffers and floating point textures on almost any browser and hardware. Compatible with Shadertoy.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

  •  

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp