• Stars
    star
    284
  • Rank 145,616 (Top 3 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created almost 7 years ago
  • Updated about 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An interface for reloading GLSL shaders on the fly.

shader-reload

experimental

This is an experimental interface for live shader reloading in ThreeJS, regl, and other WebGL frameworks. This means you can edit your GLSL shader files without re-starting your entire application state. Works with regular strings, template strings, and/or transforms like brfs and glslify. Handles errors with a client-side popup that disappears on subsequent reloads.

screenshot

See this tweet for a longer video.

You might also be interested in shader-reload-cli, a development server (drop-in replacement for budo) that supports live-reloading GLSL with glslify built-in.

The code here could probably be adapted to work with other environments, e.g. Webpack/Express.

Quick Start

A quick way to test this is with the CLI version of this module, shader-reload-cli. This is a simple development server to get you up and running. For advanced projects, you may choose to use another development tool.

From your project folder using [email protected] and [email protected] or higher:

npm install shader-reload-cli -g

Add a simple index.js script like this:

index.js

const shader = require('./foo.shader');

// Initial source
console.log(shader.vertex, shader.fragment);

shader.on('change', () => {
  // New source
  console.log('Shader updated:', shader.vertex, shader.fragment);
});

It requires a shader module (which must have a .shader.js extension) with the following syntax.

foo.shader.js

module.exports = require('shader-reload')({
  vertex: '... shader source string ...',
  fragment: '... shader source string ...'
});

Now you can start the development server and begin editing & developing your application. Saving the shader modules will trigger a 'change' event without a hard page reload, but saving any other modules will reload the page as usual.

# opens the browser to localhost:9966/
shader-reload-cli src/index.js --open

πŸ’‘ Under the hood, the shader-reload-cli script is running budo with glslify, so you can pass other options like --dir and --port. You can also add glslify transforms like glslify-hex to your package.json and they will get picked up by shader-reload-cli.

Details

Shader Files (.shader.js)

You will need to separate your shader source into its own module, which must have the extension .shader.js and require the shader-reload function.

Pass statically analyzable GLSL source code to the function like this:

module.exports = require('shader-reload')({
  vertex: '... shader source string ...',
  fragment: '... shader source string ...'
});

The return value of the shader-reload function is a Shader object, which has the same vertex and fragment properties (which are mutated on file change). You can also attach a shader.on('change', fn) event to react to changes.

Here is an example with inline shader source, using template strings.

blue.shader.js

module.exports = require('shader-reload')({
  fragment: `
  void main () {
    gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
  }`,
  vertex: `
  void main () {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(pos.xyz, 1.0);
  }`
});

Then your ThreeJS source might look like this:

main.js

const shader = require('./blue.shader');

const material = new THREE.ShaderMaterial({
  vertexShader: shader.vertex,
  fragmentShader: shader.fragment
});

shader.on('change', () => {
  // Mark shader for recompilation
  material.vertexShader = shader.vertex;
  material.fragmentShader = shader.fragment;
  material.needsUpdate = true;
});

const mesh = new THREE.Mesh(geometry, material);
...

The examples include a LiveShaderMaterial which is a bit more robust for large applications.

Development Tool

Other than the .shader.js modules, you also need to have this set up with your development tool. You have a few options:

  • Use shader-reload-cli, it already includes glslify and shader reloading out of the box
  • Attach shader reloading to budo, see this gist for instructions
  • Attach shader reloading to your existing development environment using WebSockets and broadcasting 'shader-reload' events to clients

Browserify Transform

If you are using shader-reload-cli, it already includes the transforms needed for shader reloading and glslify.

If you are using budo directly or your own browserify scripts, you will need to include a source transform, e.g. -t shader-reload/transform, or in options:

...
  browserify: {
    transform: [ 'shader-reload/transform' ]
  }

Use with glslify

The shader-reload-cli script already includes glslify support out of the box, so you can organize your shaders into their own files and require glsl modules from npm:

blue.shader.js

const glslify = require('glslify');
const path = require('path');

module.exports = require('shader-reload')({
  vertex: glslify(path.resolve(__dirname, 'blue.vert')),
  fragment: glslify(path.resolve(__dirname, 'blue.frag'))
});

If you are using budo directly or your own development server, make sure to include glslify as a source transform before the shader-reload transform.

⚠️ Babel and ES6 import

Babel will replace import statements with code that isn't easy to statically analyze, causing problems with this module. Instead of using import for 'shader-reload', you should require() it.

The same goes for requiring glslify.

Production Bundling

During production or when publishing the source to a non-development environment (i.e. without WebSockets), simply omit the shader-reload transform. Shaders will not change after construction.

If you are using shader-reload-cli and looking for a final JavaScript file for your static site, you can use browserify:

# install browserify
npm i browserify --save-dev

# bundle your index, with glslify if you need it
npx browserify index.js -t glslify > bundle.js

Use with ThreeJS

This module includes two Three.js utility classes for convenience in the three folder, LiveShaderMaterial and LiveRawShaderMaterial.

Read more about it here.

API Doc

shader = require('reload-shader')(shaderSource)

Pass in a shaderSource with { vertex, fragment } strings, and the Shader emitter returned will contain the following:

shader.vertex   // the latest vertex source
shader.fragment // the latest fragment source
shader.version  // an integer, starts at 0, increased with each change
shader.on('touch', fn)  // file was touched by fs file watcher
shader.on('change', fn) // vertex or fragment source was changed

require('reload-shader/receiver').on('touch', fn)

require('reload-shader/receiver').on('change', fn)

This event is triggered after all shaders have been updated, allowing you to react to the event application-wide instead of on a per-shader basis.

Running from Source

Clone this repo and npm install, then npm run example-three (ThreeJS) or npm run example-regl (regl). Edit the files inside the example/shaders/ folder and the shader will update without reloading the page. Saving other frontend files will reload the page as usual, restarting the application state.

Why not Webpack/Parcel HMR?

In my experience, trying to apply Hot Module Replacement to an entire WebGL application leads to a lot of subtle issues because GL relies so heavily on state, GPU memory, performance, etc.

However, shaders are easy to "hot replace" since they are really just strings. I wanted a workflow that provides lightning fast GLSL reloads, works smoothly with glslify, and does not rely on a bundle-wide HMR solution (which would be overkill). This module also handles some special edge cases like handling shader errors with a client-side popup.

License

MIT, see LICENSE.md for details.

More Repositories

1

canvas-sketch

[beta] A framework for making generative artwork in JavaScript and the browser.
JavaScript
5,019
star
2

budo

🎬 a dev server for rapid prototyping
JavaScript
2,174
star
3

lwjgl-basics

πŸ”§ LibGDX/LWJGL tutorials and examples
Java
1,841
star
4

graphics-resources

πŸ“ a list of graphic programming resources
1,748
star
5

color-wander

🎨 Generative artwork in node/browser based on a seeded random
JavaScript
1,615
star
6

promise-cookbook

πŸ“™ a brief introduction to using Promises in JavaScript
1,603
star
7

module-best-practices

πŸ“š some best practices for JS modules
JavaScript
1,521
star
8

workshop-generative-art

A workshop on creative coding & generative art
JavaScript
1,362
star
9

svg-mesh-3d

πŸš€ converts a SVG path to a 3D mesh
JavaScript
1,169
star
10

workshop-webgl-glsl

A workshop on WebGL and GLSL
JavaScript
1,032
star
11

webgl-wireframes

Stylized Wireframe Rendering in WebGL
JavaScript
713
star
12

workshop-p5-intro

Intro to Creative Coding workshop with p5.js and Tone.js
711
star
13

canvas-sketch-util

Utilities for sketching in Canvas, WebGL and generative art
JavaScript
661
star
14

threejs-app

Some opinionated structure for a complex/scalable ThreeJS app
JavaScript
444
star
15

bellwoods

JavaScript
395
star
16

webgl-lines

some interactive content for a blog post
JavaScript
385
star
17

eases

a grab-bag of modular easing equations
JavaScript
372
star
18

audiograph.xyz

A visual exploration of Pilotpriest's 2016 album, TRANS.
JavaScript
335
star
19

jsconfeu-generative-visuals

Code for the generative projection mapped animations during JSConf EU 2018 in Berlin.
JavaScript
334
star
20

load-asset

Loads a single or multiple assets and returns a promise.
JavaScript
311
star
21

glsl-fxaa

FXAA implementation for glslify in WebGL
GLSL
310
star
22

dictionary-of-colour-combinations

palettes from A Dictionary of Colour Combinations
Python
290
star
23

penplot

[DEPRECATED] see canvas-sketch
JavaScript
262
star
24

mp4-wasm

[proof-of-concept] fast MP4 mux / demux using WASM
C
258
star
25

gifenc

fast GIF encoding
JavaScript
246
star
26

codevember

codevember
JavaScript
242
star
27

impressionist

🎨 generative painting using perlin noise for motion
JavaScript
242
star
28

three-line-2d

lines expanded in a vertex shader
JavaScript
224
star
29

three-orbit-controls

orbit controls for ThreeJS
JavaScript
216
star
30

physical-text

πŸŒ‚ simulating text in the physical world
JavaScript
216
star
31

mp4-h264

[project suspended] MP4 + H264 encoding for the browser with WASM
C
212
star
32

prot

highly opinionated dev environment [Proof of concept]
JavaScript
201
star
33

template-electron-installation

a template for media art installations using Electron in kiosk mode
JavaScript
199
star
34

workshop-web-audio

Web Audio workshop with Frontend Masters
JavaScript
189
star
35

yyz

JavaScript
187
star
36

parametric-curves

JavaScript
185
star
37

fontpath

Font to vector path tools
JavaScript
183
star
38

ghrepo

:octocat: create a new GitHub repo from your current folder
JavaScript
177
star
39

google-panorama-equirectangular

gets equirectangular images from Google StreetView
JavaScript
172
star
40

image-sdf

generate a signed distance field from an image
JavaScript
171
star
41

glsl-film-grain

natural looking film grain using noise functions
JavaScript
171
star
42

subscapes

generative artwork hosted on Ethereum
JavaScript
169
star
43

pack-spheres

Brute force circle/sphere packing in 2D or 3D
JavaScript
161
star
44

polartone

experimental audio visualizer
JavaScript
154
star
45

dom-css

fast dom CSS styling
JavaScript
153
star
46

tiny-artblocks

Toolkit for small ArtBlocks projects
JavaScript
152
star
47

adaptive-bezier-curve

adaptive and scalable 2D bezier curves
JavaScript
138
star
48

atcq

An implementation of Ant-Tree Color Quantization
JavaScript
136
star
49

workshop-data-artwork

material & notes for a workshop on data artwork & creative coding
JavaScript
125
star
50

kami-demos

🚧 Some demos for the Kami WebGL renderer
JavaScript
122
star
51

rust

experiments
JavaScript
122
star
52

kami

🚧 Rendering ecosystem using Node style packaging
JavaScript
120
star
53

looom-tools

Svelte
115
star
54

esmify

parse and handle import/export for browserify
JavaScript
112
star
55

polyline-normals

gets miter normals for a 2D polyline
JavaScript
112
star
56

three-vignette-background

a simple ThreeJS vignette background
JavaScript
111
star
57

simple-input-events

Unified mouse & touch events for desktop and mobile
JavaScript
105
star
58

tweenr

minimal tweening engine
JavaScript
105
star
59

text-modules

✏️ a list of text/font modules
104
star
60

spectrum

a small tool to visualize the frequencies of an audio file
JavaScript
104
star
61

three-shader-fxaa

optimized FXAA shader for ThreeJS
JavaScript
102
star
62

lerp

bare-bones linear interpolation function
JavaScript
101
star
63

canvas-sketch-cli

A CLI used alongside canvas-sketch
JavaScript
92
star
64

svg-path-contours

gets a discrete list of points from svg
JavaScript
90
star
65

pen-plotter-blog-post

JavaScript
90
star
66

simplify-path

simplify 2D polyline of arrays
JavaScript
83
star
67

garnish

🍸 prettifies ndjson from wzrd and similar tools
JavaScript
81
star
68

get-rgba-palette

gets a palette of prominent colors from an array of pixels
JavaScript
81
star
69

keytime

[EXPERIMENT] keyframe animation tools
JavaScript
79
star
70

three-glslify-example

a simple example of ThreeJS with glslify
GLSL
77
star
71

canvas-text

[experiment] better Canvas2D text rendering
JavaScript
77
star
72

raylight

Experimental WebGL Music Visualizer
JavaScript
76
star
73

verlet-system

2D and 3D verlet integration
JavaScript
75
star
74

word-wrapper

wraps words based on arbitrary 2D glyphs
JavaScript
71
star
75

mp4-wasm-encoder

JavaScript
70
star
76

gl-sprite-text

bitmap font rendering for stackgl
JavaScript
69
star
77

tendril-webtoy-blog-post

A blog post for an interactive Tendril web toy
68
star
78

paper-colors

A small set of pastel and off-white paper colors
JavaScript
68
star
79

threejs-tree-shake

Tree-shakes and optimizes ThreeJS apps
JavaScript
66
star
80

gh-readme-scrape

a CLI to bulk download URLs (images/pdfs/etc) from GitHub readmes
JavaScript
65
star
81

fika

A figma plugin generator
JavaScript
60
star
82

shadertoy-export

render ShaderToy demos to PNG
JavaScript
59
star
83

glsl-random

pseudo-random 2D noise for glslify
C
59
star
84

electron-canvas-to-buffer

in Electron, turns a Canvas into a Buffer
JavaScript
55
star
85

gl-vignette-background

a soft gradient background in WebGL
JavaScript
55
star
86

webpack-three-hmr-test

test of ThreeJS + Webpack + HMR
JavaScript
53
star
87

workshop-generative-color

a workshop on color science for generative art and creative coding
JavaScript
52
star
88

filmic-gl

filmic GLSL shaders in ThreeJS
JavaScript
51
star
89

riso-colors

A list of Risograph printer colors
51
star
90

gsx-pdf-optimize

Optimize PDFs with Ghostscript command
JavaScript
50
star
91

raf-loop

a minimal requestAnimationFrame render loop
JavaScript
49
star
92

gdx-swiper

An example of a "Fruit Ninja" style swipe in LibGDX
Java
47
star
93

gsap-promise

promise wrapper for gsap (TweenLite)
JavaScript
47
star
94

browserify-example

a bare-bones, no-bullshit example of using browserify to dev + build a static demo
JavaScript
45
star
95

extract-svg-path

extracts a string of subpaths from an svg file
JavaScript
45
star
96

figma-plugin-palette

"Image Palette" Plugin in Figma
JavaScript
42
star
97

adaptive-quadratic-curve

adaptive and scalable 2D quadratic curves
JavaScript
42
star
98

three-geometry-data

Get vertex and face data from THREE.Geometry
JavaScript
40
star
99

budo-chrome

an extension of budo dev server that supports live script injection
JavaScript
39
star
100

three-tube-wireframe

Builds a tube-based wireframe geometry in ThreeJS
JavaScript
39
star