# glslify [![stability][0]][1] [![npm version][2]][3] [![downloads][4]][5] [![travis][6]][7] A node.js-style module system for GLSL! This module contains: * glslify's command-line interface (CLI) * glslify node/electron interface * [browserify](http://browserify.org/) transform It forms one of the core components of the [stack.gl](http://stack.gl/) ecosystem, allowing you to install GLSL modules from [npm](http://npmjs.com) and use them in your shaders. This makes it trivial to piece together different effects and techniques from the community, including but certainly not limited to [fog](https://github.com/hughsk/glsl-fog), [noise](https://github.com/hughsk/glsl-noise), [film grain](https://github.com/mattdesl/glsl-film-grain), [raymarching helpers](https://github.com/stackgl/glsl-smooth-min), [easing functions](https://github.com/stackgl/glsl-easings) and [lighting models](https://github.com/stackgl/glsl-specular-cook-torrance). A full list can be found on the [stack.gl packages list](http://stack.gl/packages) under the "Shader Components" category. Because glslify just outputs a single shader file as a string, it's easy to use it with any WebGL framework of your choosing, provided they accept custom shaders. Integration is planned for [three.js](http://threejs.org/) and [pex](http://vorg.github.io/pex/), with more on the way! [Open an issue](https://github.com/stackgl/glslify/issues/new) here if you'd like to discuss integrating glslify with your platform of choice. *If you're interested in playing around with glslify, you should check out [glslb.in](http://glslb.in/): it's a fragment shader sandbox similar to [Shadertoy](http://shadertoy.com/) and [GLSL Sandbox](http://glslsandbox.com/) with built in support for glslify.* ## Example ``` javascript var glsl = require('glslify') console.log(glsl(` #pragma glslify: noise = require('glsl-noise/simplex/3d') precision mediump float; varying vec3 vpos; void main () { gl_FragColor = vec4(noise(vpos*25.0),1); } `)) ``` ## Module API ``` javascript var glsl = require('glslify') ``` ### var src = glsl\`shader source...\` Compile a shader inline using `glsl` as a [tagged template string function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals). ### var src = glsl(file, opts) ### var src = glsl(shaderSource, opts) Compile a shader using an inline shader string or a file name. These are convencience methods provided that call `glsl.compile()` or `glsl.file()` accordingly. These methods are also provided for backwards compatibility with the previous `< 6` interface. Optionally provide: * `opts.basedir` - directory to resolve relative paths * `opts.transform` - an array of transform functions, transform module name ### var src = glsl.compile(src, opts) Compile a shader string from a string `src`. * `opts.basedir` - directory to resolve relative paths in `src` * `opts.transform` - an array of transform functions, transform module name strings, or `[trname,tropts]` pairs ### var src = glsl.file(filename, opts) Compile a shader from a `filename`. * `opts.basedir` - directory to resolve relative paths in `src` * `opts.transform` - an array of transform functions, transform module name strings, or `[trname,tropts]` pairs ## Installation [![NPM](https://nodei.co/npm/glslify.png)](https://nodei.co/npm/glslify/) To install the command-line interface, install glslify globally like so: ``` bash npm install -g glslify ``` To install glslify for use as a browserify transform, you should install it locally instead: ``` bash npm install glslify ``` ## Getting Started ### CLI The CLI can take a file as its first argument, and output to a file using the `-o` flag: ``` bash glslify index.glsl -o output.glsl ``` It can also read input from stdin and output to stdout: ``` bash cat index.glsl | glslify > output.glsl ``` ### Browserify Transform If using browserify from the command-line, simply pass glslify in as a transform using the `-t`/`--transform` flag: ``` bash browserify -t glslify index.js -o bundle.js ``` Alternatively, you may include glslify as a `browserify.transform` in your `package.json` file: ``` json { "name": "my-app", "dependencies": { "glslify": "^2.0.0" }, "browserify": { "transform": ["glslify"] } } ``` When writing your app, you should be able to require and call glslify the same as the node/electron interface, like so: ``` javascript // index.js var glsl = require('glslify') var src = glsl.file('./shader.glsl') console.log(src) ``` or using tagged template strings: ``` javascript var glsl = require('glslify') console.log(glsl` #pragma glslify: noise = require('glsl-noise/simplex/3d') precision mediump float; varying vec3 vpos; void main () { gl_FragColor = vec4(noise(vpos*25.0),1); } `) ``` Your glslify calls will be replaced with bundled GLSL strings at build time automatically for you! ``` javascript // index.js var src = "#define GLSLIFY 1\n\nprecision mediump float; ..." console.log(src) ``` ### [Webpack](http://webpack.github.io/) Loader You can use the [glslify-loader](https://github.com/stackgl/glslify-loader) module to bundle shaders through glslify with Webpack. Check out [the repository](https://github.com/stackgl/glslify-loader) for further information. ### [Babel](https://babeljs.io) Plugin You can use [glslify-babel](https://github.com/stackgl/glslify-babel) as a Babel plugin. This allows you to use all ES6 features with glslify, including `import` statements and tagged template strings. Check out [the repository](https://github.com/stackgl/glslify-babel) to learn more. #### :bulb: A Note on Babel Import/Export If you are using Babel presets to transpile ES6 import/export to CommonJS `require()` statements, you may run into issues with glslify. This is because Babel mangles the output into source code that isn't easy to statically analyze. One solution is to directly map `glslify` to CommonJS statements, using [babel-plugin-import-to-require](https://github.com/mattdesl/babel-plugin-import-to-require) in your `.babelrc`. ## Usage ### Installing a GLSL Module Much like plain JavaScript modules, GLSL modules are stored on npm. The main difference is that GLSL modules contain an `index.glsl` file instead of an `index.js`. Generally, these modules start with `glsl-` in their name. To install [glsl-noise](https://github.com/hughsk/glsl-noise) in your current directory: ``` bash npm install glsl-noise ``` This will download glsl-noise and any of its dependencies, placing them in a `node_modules` directory for glslify to use. ### Importing a GLSL Module You can import a module using the following `#pragma` syntax: ``` glsl #pragma glslify: noise = require(glsl-noise/simplex/2d) void main() { float brightness = noise(gl_FragCoord.xy); gl_FragColor = vec4(vec3(brightness), 1.); } ``` Shader dependencies are resolved using the same algorithm as node, so the above will load `./node_modules/simplex/2d.glsl` from the shader's directory. The above example would result in the following output: ``` glsl #define GLSLIFY 1 // // Description : Array and textureless GLSL 2D simplex noise function. // Author : Ian McEwan, Ashima Arts. // Maintainer : ijm // Lastmod : 20110822 (ijm) // License : Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // https://github.com/ashima/webgl-noise // vec3 mod289_1_0(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec2 mod289_1_0(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec3 permute_1_1(vec3 x) { return mod289_1_0(((x*34.0)+1.0)*x); } float snoise_1_2(vec2 v) { const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) -0.577350269189626, // -1.0 + 2.0 * C.x 0.024390243902439); // 1.0 / 41.0 // First corner vec2 i = floor(v + dot(v, C.yy) ); vec2 x0 = v - i + dot(i, C.xx); // Other corners vec2 i1; //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 //i1.y = 1.0 - i1.x; i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); // x0 = x0 - 0.0 + 0.0 * C.xx ; // x1 = x0 - i1 + 1.0 * C.xx ; // x2 = x0 - 1.0 + 2.0 * C.xx ; vec4 x12 = x0.xyxy + C.xxzz; x12.xy -= i1; // Permutations i = mod289_1_0(i); // Avoid truncation effects in permutation vec3 p = permute_1_1( permute_1_1( i.y + vec3(0.0, i1.y, 1.0 )) + i.x + vec3(0.0, i1.x, 1.0 )); vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); m = m*m ; m = m*m ; // Gradients: 41 points uniformly over a line, mapped onto a diamond. // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) vec3 x = 2.0 * fract(p * C.www) - 1.0; vec3 h = abs(x) - 0.5; vec3 ox = floor(x + 0.5); vec3 a0 = x - ox; // Normalise gradients implicitly by scaling m // Approximation of: m *= inversesqrt( a0*a0 + h*h ); m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h ); // Compute final noise value at P vec3 g; g.x = a0.x * x0.x + h.x * x0.y; g.yz = a0.yz * x12.xz + h.yz * x12.yw; return 130.0 * dot(m, g); } void main() { float brightness = snoise_1_2(gl_FragCoord.xy); gl_FragColor = vec4(vec3(brightness), 1.); } ``` ### Exporting a GLSL Module You can export a token from a module using the `glslify: export` pragma, like so: ``` glsl float myFunction(vec3 normal) { return dot(vec3(0, 1, 0), normal); } #pragma glslify: export(myFunction) ``` This means that when you import this module file elsewhere, you'll get `myFunction` in return: ``` glsl #pragma glslify: topDot = require(./my-function.glsl) topDot(vec3(0, 1, 0)); // 1 ``` If you check the output shader source, you'll notice that variables have been renamed to avoid conflicts between multiple shader files. You're not limited to exporting functions either: you should be able to export any GLSL token, such as a struct for reuse between your modules: ``` glsl struct Light { vec3 position; vec3 color; }; #pragma glslify: export(Light) ``` ### Passing references between modules Normally, glslify renames tokens to avoid conflicts across contexts. Sometimes, however, you want to reference the same thing from different contexts. The `require` function lets you explicitly fix reference names in order to guarantee that two different modules are talking about the same reference. Give `some-module` access to locally declared `bar` whenever it looks for `foo` internally: ``` glsl int bar; #pragma glslify: require('some-module',foo=bar,...) ``` It's important to make sure that `bar` has already been declared when you invoke `#pragma glslify: require(...)`. Now time for some imagination. Let's pretend that we have some `float[500]` arrays that we'd like to be summed up. Here's a module that performs a reduction using a function `map`. ``` glsl float accumulate(float list[N]) { float z = 0; for (int i = 0; i