mesh-gradient.js
Version:
A tiny utility to generate mesh gradients in a HTML canvas.
406 lines (405 loc) • 23.2 kB
JavaScript
"use strict";
/*
* Stripe WebGl Gradient Animation
* All Credits to Stripe.com
* ScrollObserver functionality to disable animation when not scrolled into view has been disabled and
* commented out for now.
* https://kevinhufnagl.com
*/
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MiniGl = exports.normalizeColor = void 0;
//Converting colors to proper format
function normalizeColor(hexCode) {
return [((hexCode >> 16) & 255) / 255, ((hexCode >> 8) & 255) / 255, (255 & hexCode) / 255];
}
exports.normalizeColor = normalizeColor;
['SCREEN', 'LINEAR_LIGHT'].reduce(function (hexCode, t, n) {
var _a;
return Object.assign(hexCode, (_a = {},
_a[t] = n,
_a));
}, {});
//Essential functionality of WebGl
//t = width
//n = height
var MiniGl = /** @class */ (function () {
function MiniGl(canvas, width, height, debug) {
if (debug === void 0) { debug = false; }
var _miniGl = this, debug_output = -1 !== document.location.search.toLowerCase().indexOf('debug=webgl');
(_miniGl.canvas = canvas),
(_miniGl.gl = _miniGl.canvas.getContext('webgl', {
antialias: true,
preserveDrawingBuffer: true,
})),
(_miniGl.meshes = []);
var context = _miniGl.gl;
width && height && this.setSize(width, height),
_miniGl.lastDebugMsg,
(_miniGl.debug =
debug && debug_output
? function (e) {
var t = new Date();
t - _miniGl.lastDebugMsg > 1e3 && console.log('---'), console.log.apply(console, __spreadArray([t.toLocaleTimeString() + Array(Math.max(0, 32 - e.length)).join(' ') + e + ': '], Array.from(arguments).slice(1), false)),
(_miniGl.lastDebugMsg = t);
}
: function () { }),
Object.defineProperties(_miniGl, {
Material: {
enumerable: false,
value: /** @class */ (function () {
function value(vertexShaders, fragments, uniforms) {
if (uniforms === void 0) { uniforms = {}; }
var material = this;
function getShaderByType(type, source) {
var shader = context.createShader(type);
return (context.shaderSource(shader, source),
context.compileShader(shader),
context.getShaderParameter(shader, context.COMPILE_STATUS) ||
console.error(context.getShaderInfoLog(shader)),
_miniGl.debug('Material.compileShaderSource', {
source: source,
}),
shader);
}
function getUniformVariableDeclarations(uniforms, type) {
return Object.entries(uniforms)
.map(function (_a) {
var uniform = _a[0], value = _a[1];
return value.getDeclaration(uniform, type);
})
.join('\n');
}
(material.uniforms = uniforms), (material.uniformInstances = []);
var prefix = '\n precision highp float;\n ';
(material.vertexSource = "\n ".concat(prefix, "\n attribute vec4 position;\n attribute vec2 uv;\n attribute vec2 uvNorm;\n ").concat(getUniformVariableDeclarations(_miniGl.commonUniforms, 'vertex'), "\n ").concat(getUniformVariableDeclarations(uniforms, 'vertex'), "\n ").concat(vertexShaders, "\n ")),
(material.Source = "\n ".concat(prefix, "\n ").concat(getUniformVariableDeclarations(_miniGl.commonUniforms, 'fragment'), "\n ").concat(getUniformVariableDeclarations(uniforms, 'fragment'), "\n ").concat(fragments, "\n ")),
(material.vertexShader = getShaderByType(context.VERTEX_SHADER, material.vertexSource)),
(material.fragmentShader = getShaderByType(context.FRAGMENT_SHADER, material.Source)),
(material.program = context.createProgram()),
context.attachShader(material.program, material.vertexShader),
context.attachShader(material.program, material.fragmentShader),
context.linkProgram(material.program),
context.getProgramParameter(material.program, context.LINK_STATUS) ||
console.error(context.getProgramInfoLog(material.program)),
context.useProgram(material.program),
material.attachUniforms(void 0, _miniGl.commonUniforms),
material.attachUniforms(void 0, material.uniforms);
}
//t = uniform
value.prototype.attachUniforms = function (name, uniforms) {
//n = material
var material = this;
void 0 === name
? Object.entries(uniforms).forEach(function (_a) {
var name = _a[0], uniform = _a[1];
material.attachUniforms(name, uniform);
})
: 'array' == uniforms.type
? uniforms.value.forEach(function (uniform, i) { return material.attachUniforms("".concat(name, "[").concat(i, "]"), uniform); })
: 'struct' == uniforms.type
? Object.entries(uniforms.value).forEach(function (_a) {
var uniform = _a[0], i = _a[1];
return material.attachUniforms("".concat(name, ".").concat(uniform), i);
})
: (_miniGl.debug('Material.attachUniforms', {
name: name,
uniform: uniforms,
}),
material.uniformInstances.push({
uniform: uniforms,
location: context.getUniformLocation(material.program, name),
}));
};
return value;
}()),
},
Uniform: {
enumerable: !1,
value: /** @class */ (function () {
function value(e) {
(this.type = 'float'), Object.assign(this, e);
(this.typeFn =
{
float: '1f',
int: '1i',
vec2: '2fv',
vec3: '3fv',
vec4: '4fv',
mat4: 'Matrix4fv',
}[this.type] || '1f'),
this.update();
}
value.prototype.update = function (value) {
void 0 !== this.value &&
context["uniform".concat(this.typeFn)](value, 0 === this.typeFn.indexOf('Matrix') ? this.transpose : this.value, 0 === this.typeFn.indexOf('Matrix') ? this.value : null);
};
//e - name
//t - type
//n - length
value.prototype.getDeclaration = function (name, type, length) {
var uniform = this;
if (uniform.excludeFrom !== type) {
if ('array' === uniform.type)
return (uniform.value[0].getDeclaration(name, type, uniform.value.length) +
"\nconst int ".concat(name, "_length = ").concat(uniform.value.length, ";"));
if ('struct' === uniform.type) {
var name_no_prefix = name.replace('u_', '');
return ((name_no_prefix = name_no_prefix.charAt(0).toUpperCase() + name_no_prefix.slice(1)),
"uniform struct ".concat(name_no_prefix, " \n {\n") +
Object.entries(uniform.value)
.map(function (_a) {
var name = _a[0], uniform = _a[1];
return uniform.getDeclaration(name, type).replace(/^uniform/, '');
})
.join('') +
"\n} ".concat(name).concat(length > 0 ? "[".concat(length, "]") : '', ";"));
}
return "uniform ".concat(uniform.type, " ").concat(name).concat(length > 0 ? "[".concat(length, "]") : '', ";");
}
};
return value;
}()),
},
PlaneGeometry: {
enumerable: !1,
value: /** @class */ (function () {
function value(width, height, n, i, orientation) {
context.createBuffer(),
(this.attributes = {
position: new _miniGl.Attribute({
target: context.ARRAY_BUFFER,
size: 3,
}),
uv: new _miniGl.Attribute({
target: context.ARRAY_BUFFER,
size: 2,
}),
uvNorm: new _miniGl.Attribute({
target: context.ARRAY_BUFFER,
size: 2,
}),
index: new _miniGl.Attribute({
target: context.ELEMENT_ARRAY_BUFFER,
size: 3,
type: context.UNSIGNED_SHORT,
}),
}),
this.setTopology(n, i),
this.setSize(width, height, orientation);
}
value.prototype.setTopology = function (e, t) {
if (e === void 0) { e = 1; }
if (t === void 0) { t = 1; }
var n = this;
(n.xSegCount = e),
(n.ySegCount = t),
(n.vertexCount = (n.xSegCount + 1) * (n.ySegCount + 1)),
(n.quadCount = n.xSegCount * n.ySegCount * 2),
(n.attributes.uv.values = new Float32Array(2 * n.vertexCount)),
(n.attributes.uvNorm.values = new Float32Array(2 * n.vertexCount)),
(n.attributes.index.values = new Uint16Array(3 * n.quadCount));
for (var e_1 = 0; e_1 <= n.ySegCount; e_1++)
for (var t_1 = 0; t_1 <= n.xSegCount; t_1++) {
var i = e_1 * (n.xSegCount + 1) + t_1;
if (((n.attributes.uv.values[2 * i] = t_1 / n.xSegCount),
(n.attributes.uv.values[2 * i + 1] = 1 - e_1 / n.ySegCount),
(n.attributes.uvNorm.values[2 * i] = (t_1 / n.xSegCount) * 2 - 1),
(n.attributes.uvNorm.values[2 * i + 1] = 1 - (e_1 / n.ySegCount) * 2),
t_1 < n.xSegCount && e_1 < n.ySegCount)) {
var s = e_1 * n.xSegCount + t_1;
(n.attributes.index.values[6 * s] = i),
(n.attributes.index.values[6 * s + 1] = i + 1 + n.xSegCount),
(n.attributes.index.values[6 * s + 2] = i + 1),
(n.attributes.index.values[6 * s + 3] = i + 1),
(n.attributes.index.values[6 * s + 4] = i + 1 + n.xSegCount),
(n.attributes.index.values[6 * s + 5] = i + 2 + n.xSegCount);
}
}
n.attributes.uv.update(),
n.attributes.uvNorm.update(),
n.attributes.index.update(),
_miniGl.debug('Geometry.setTopology', {
uv: n.attributes.uv,
uvNorm: n.attributes.uvNorm,
index: n.attributes.index,
});
};
value.prototype.setSize = function (width, height, orientation) {
if (width === void 0) { width = 1; }
if (height === void 0) { height = 1; }
if (orientation === void 0) { orientation = 'xz'; }
var geometry = this;
(geometry.width = width),
(geometry.height = height),
(geometry.orientation = orientation),
(geometry.attributes.position.values &&
geometry.attributes.position.values.length === 3 * geometry.vertexCount) ||
(geometry.attributes.position.values = new Float32Array(3 * geometry.vertexCount));
var o = width / -2, r = height / -2, segment_width = width / geometry.xSegCount, segment_height = height / geometry.ySegCount;
for (var yIndex = 0; yIndex <= geometry.ySegCount; yIndex++) {
var t = r + yIndex * segment_height;
for (var xIndex = 0; xIndex <= geometry.xSegCount; xIndex++) {
var r_1 = o + xIndex * segment_width, l = yIndex * (geometry.xSegCount + 1) + xIndex;
(geometry.attributes.position.values[3 * l + 'xyz'.indexOf(orientation[0])] = r_1),
(geometry.attributes.position.values[3 * l + 'xyz'.indexOf(orientation[1])] = -t);
}
}
geometry.attributes.position.update(),
_miniGl.debug('Geometry.setSize', {
position: geometry.attributes.position,
});
};
return value;
}()),
},
Mesh: {
enumerable: !1,
value: /** @class */ (function () {
function value(geometry, material) {
var mesh = this;
(mesh.geometry = geometry),
(mesh.material = material),
(mesh.wireframe = !1),
(mesh.attributeInstances = []),
Object.entries(mesh.geometry.attributes).forEach(function (_a) {
var e = _a[0], attribute = _a[1];
mesh.attributeInstances.push({
attribute: attribute,
location: attribute.attach(e, mesh.material.program),
});
}),
_miniGl.meshes.push(mesh),
_miniGl.debug('Mesh.constructor', {
mesh: mesh,
});
}
value.prototype.draw = function () {
context.useProgram(this.material.program),
this.material.uniformInstances.forEach(function (_a) {
var e = _a.uniform, t = _a.location;
return e.update(t);
}),
this.attributeInstances.forEach(function (_a) {
var e = _a.attribute, t = _a.location;
return e.use(t);
}),
context.drawElements(this.wireframe ? context.LINES : context.TRIANGLES, this.geometry.attributes.index.values.length, context.UNSIGNED_SHORT, 0);
};
value.prototype.remove = function () {
var _this = this;
_miniGl.meshes = _miniGl.meshes.filter(function (e) { return e != _this; });
};
return value;
}()),
},
Attribute: {
enumerable: !1,
value: /** @class */ (function () {
function value(e) {
(this.type = context.FLOAT),
(this.normalized = !1),
(this.buffer = context.createBuffer()),
Object.assign(this, e),
this.update();
}
value.prototype.update = function () {
void 0 !== this.values &&
(context.bindBuffer(this.target, this.buffer),
context.bufferData(this.target, this.values, context.STATIC_DRAW));
};
value.prototype.attach = function (e, t) {
var n = context.getAttribLocation(t, e);
return (this.target === context.ARRAY_BUFFER &&
(context.enableVertexAttribArray(n),
context.vertexAttribPointer(n, this.size, this.type, this.normalized, 0, 0)),
n);
};
value.prototype.use = function (e) {
context.bindBuffer(this.target, this.buffer),
this.target === context.ARRAY_BUFFER &&
(context.enableVertexAttribArray(e),
context.vertexAttribPointer(e, this.size, this.type, this.normalized, 0, 0));
};
return value;
}()),
},
});
var a = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
_miniGl.commonUniforms = {
projectionMatrix: new _miniGl.Uniform({
type: 'mat4',
value: a,
}),
modelViewMatrix: new _miniGl.Uniform({
type: 'mat4',
value: a,
}),
resolution: new _miniGl.Uniform({
type: 'vec2',
value: [1, 1],
}),
aspectRatio: new _miniGl.Uniform({
type: 'float',
value: 1,
}),
};
}
MiniGl.prototype.setSize = function (e, t, e1, t1) {
if (e === void 0) { e = 640; }
if (t === void 0) { t = 480; }
if (e1 === void 0) { e1 = 640; }
if (t1 === void 0) { t1 = 480; }
(this.width = e),
(this.height = t),
(this.canvas.width = e1),
(this.canvas.height = t1),
this.gl.viewport(0, 0, e1, t1),
(this.commonUniforms.resolution.value = [e1, t1]),
(this.commonUniforms.aspectRatio.value = e1 / t1),
this.debug('MiniGL.setSize', {
width: e,
height: t,
});
};
//left, right, top, bottom, near, far
MiniGl.prototype.setOrthographicCamera = function (e, t, n, i, s) {
if (e === void 0) { e = 0; }
if (t === void 0) { t = 0; }
if (n === void 0) { n = 0; }
if (i === void 0) { i = -2e3; }
if (s === void 0) { s = 2e3; }
(this.commonUniforms.projectionMatrix.value = [
2 / this.width,
0,
0,
0,
0,
2 / this.height,
0,
0,
0,
0,
2 / (i - s),
0,
e,
t,
n,
1,
]),
this.debug('setOrthographicCamera', this.commonUniforms.projectionMatrix.value);
};
MiniGl.prototype.render = function () {
this.gl.clearColor(0, 0, 0, 0), this.gl.clearDepth(1), this.meshes.forEach(function (e) { return e.draw(); });
};
return MiniGl;
}());
exports.MiniGl = MiniGl;