Comparing version 0.2.2 to 0.3.0
@@ -1,3 +0,36 @@ | ||
import './utils'; | ||
import './disp'; | ||
import './hue-fade'; | ||
function updatePreview (iframe, example, videos) { | ||
iframe.setAttribute('srcdoc', getIFrameHTML({example, videos})) | ||
} | ||
function getIFrameHTML ({example, videos}) { | ||
return `<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<style> | ||
body, html {margin: 0; height: 100%; overflow: hidden;} | ||
canvas {width: 100%; height: 100%;} | ||
video {display: none;} | ||
</style> | ||
<script src="../index.js"></script> | ||
<script src="./utils.js"></script> | ||
</head> | ||
<body> | ||
${videos} | ||
<canvas id="target"></canvas> | ||
<script> | ||
${example} | ||
</script> | ||
</body> | ||
</html>`; | ||
} | ||
window.updatePreview = updatePreview; | ||
const navOffHandler = () => document.body.classList.remove('nav-open'); | ||
document.querySelector('#nav-on') | ||
.addEventListener('click', () => { | ||
document.body.classList.add('nav-open'); | ||
setTimeout(() => document.body.addEventListener('click', navOffHandler, {once: true}), 0); | ||
}); |
@@ -41,2 +41,3 @@ const {Kampos, transitions} = window.kampos; | ||
// try playing with the x/y and +/- for different transition effects | ||
this.transition.sourceScale = {x: this.dispScale}; | ||
@@ -85,2 +86,3 @@ this.transition.toScale = {x: -this.dispScale}; | ||
// dividing by 500 is just enough to slow down the effect | ||
// you can change the sin() function with a different one for a different easing | ||
let p = Math.abs(Math.sin(now / 500)); | ||
@@ -112,3 +114,3 @@ p = this.direction ? p : 1 - p; | ||
const video2 = document.querySelector('#video2'); | ||
const target1 = document.querySelector('#target1'); | ||
const target = document.querySelector('#target'); | ||
@@ -118,4 +120,9 @@ const trans = new Transition({ | ||
vid2: video2, | ||
target: target1, | ||
target, | ||
// switch between the different displacement-map images and refresh to see different effects | ||
//disp: 'disp-cloud.png', | ||
//disp: 'disp-liquid.jpg', | ||
//disp: 'disp-tri.jpg', | ||
disp: 'disp-snow.jpg', | ||
// change this value and refresh to see how it affects the transition | ||
dispScale: 1.0 | ||
@@ -127,3 +134,3 @@ }); | ||
*/ | ||
target1.addEventListener('mouseenter', () => trans.forward()); | ||
target1.addEventListener('mouseleave', () => trans.backward()); | ||
target.addEventListener('mouseenter', () => trans.forward()); | ||
target.addEventListener('mouseleave', () => trans.backward()); |
@@ -5,3 +5,3 @@ const {Kampos, effects, transitions} = window.kampos; | ||
const media2 = document.querySelector('#video4'); | ||
const target = document.querySelector('#target2'); | ||
const target = document.querySelector('#target'); | ||
@@ -8,0 +8,0 @@ // create the effects/transitions we need |
(function () { | ||
'use strict'; | ||
/* | ||
* Most simple image loader | ||
* You'll probably have something like this already | ||
*/ | ||
function loadImage$1 (src) { | ||
return new Promise(resolve => { | ||
const img = new Image(); | ||
img.onload = function () { | ||
resolve(this); | ||
}; | ||
img.src = src; | ||
}); | ||
function updatePreview (iframe, example, videos) { | ||
iframe.setAttribute('srcdoc', getIFrameHTML({example, videos})); | ||
} | ||
window.loadImage = loadImage$1; | ||
/* | ||
* Minimal, cross-browser logic for playing videos and making sure | ||
* they are ready to work with | ||
*/ | ||
function prepareVideos$1 (videos) { | ||
return new Promise(resolve => { | ||
let playing = 0; | ||
let timeupdate = 0; | ||
function canPlay (e) { | ||
e.target.play(); | ||
} | ||
const isPlaying = e => { | ||
playing += 1; | ||
e.target.removeEventListener('playing', isPlaying, true); | ||
check(); | ||
}; | ||
const isTimeupdate = (e) => { | ||
timeupdate += 1; | ||
e.target.removeEventListener('timeupdate', isTimeupdate, true); | ||
check(); | ||
}; | ||
const check = () => { | ||
if (playing === videos.length && timeupdate === videos.length) { | ||
videos.forEach(vid => { | ||
vid.removeEventListener('canplay', canPlay, true); | ||
}); | ||
resolve(); | ||
} | ||
}; | ||
videos.forEach(vid => { | ||
vid.addEventListener('playing', isPlaying, true); | ||
vid.addEventListener('timeupdate', isTimeupdate, true); | ||
vid.addEventListener('canplay', canPlay, true); | ||
}); | ||
}); | ||
function getIFrameHTML ({example, videos}) { | ||
return `<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<style> | ||
body, html {margin: 0; height: 100%; overflow: hidden;} | ||
canvas {width: 100%; height: 100%;} | ||
video {display: none;} | ||
</style> | ||
<script src="../index.js"></script> | ||
<script src="./utils.js"></script> | ||
</head> | ||
<body> | ||
${videos} | ||
<canvas id="target"></canvas> | ||
<script> | ||
${example} | ||
</script> | ||
</body> | ||
</html>`; | ||
} | ||
window.prepareVideos = prepareVideos$1; | ||
window.updatePreview = updatePreview; | ||
const {Kampos, transitions} = window.kampos; | ||
const transitionDisplacement = transitions.displacement; | ||
const navOffHandler = () => document.body.classList.remove('nav-open'); | ||
/* | ||
* Wrapper class for transition logic. | ||
* This is a simple vanilla implementation | ||
*/ | ||
class Transition { | ||
constructor ({vid1, vid2, target, disp, dispScale}) { | ||
/* | ||
* prepare here everything we need | ||
*/ | ||
this.vid1 = vid1; | ||
this.vid2 = vid2; | ||
this.target = target; | ||
this.dispScale = dispScale; | ||
this.transition = transitionDisplacement(); | ||
document.querySelector('#nav-on') | ||
.addEventListener('click', () => { | ||
document.body.classList.add('nav-open'); | ||
this.direction = 1; | ||
this.startTime = 0; | ||
// init kampos | ||
this.kampos = new Kampos({target, effects: [this.transition]}); | ||
// load the displacement map image | ||
const dispReady = loadImage(disp); | ||
// make sure videos are loaded and playing | ||
prepareVideos([this.vid1, this.vid2]) | ||
.then(() => { | ||
const width = this.vid1.videoWidth; | ||
const height = this.vid1.videoHeight; | ||
dispReady.then(img => { | ||
/* | ||
* set transition values | ||
*/ | ||
this.transition.map = img; | ||
this.transition.to = this.vid2; | ||
this.transition.sourceScale = {x: this.dispScale}; | ||
this.transition.toScale = {x: -this.dispScale}; | ||
// set media source | ||
this.kampos.setSource({media: this.vid1, width, height}); | ||
// start kampos | ||
this.kampos.play(); | ||
}); | ||
}); | ||
} | ||
/* | ||
* start animation playback forward | ||
*/ | ||
forward () { | ||
this.direction = 1; | ||
this.startTime = Date.now(); | ||
this.loop(); | ||
} | ||
/* | ||
* start animation playback backwards | ||
*/ | ||
backward () { | ||
this.direction = 0; | ||
this.startTime = Date.now(); | ||
this.loop(); | ||
} | ||
/* | ||
* This will probably be a callback you'll provide to your animation library | ||
*/ | ||
tick (p) { | ||
this.transition.progress = p; | ||
} | ||
/* | ||
* This will usually be implemented by an animation library you may already have in your project | ||
*/ | ||
loop () { | ||
const now = Date.now() - this.startTime; | ||
// dividing by 500 is just enough to slow down the effect | ||
let p = Math.abs(Math.sin(now / 500)); | ||
p = this.direction ? p : 1 - p; | ||
this.tick(p); | ||
let nextTick = () => this.loop(); | ||
// we choose a cutoff value where the progress value | ||
// is almost 0/1, depending on direction | ||
// and then stop the animation by just rendering | ||
// 1 extra tick with the final value (0 or 1 respectively). | ||
if (this.direction) { | ||
if (p * 100 >= 99) { | ||
nextTick = () => this.tick(1); | ||
} | ||
} | ||
else if (p * 100 <= 1) { | ||
nextTick = () => this.tick(0); | ||
} | ||
window.requestAnimationFrame(nextTick); | ||
} | ||
} | ||
const video1 = document.querySelector('#video1'); | ||
const video2 = document.querySelector('#video2'); | ||
const target1 = document.querySelector('#target1'); | ||
const trans = new Transition({ | ||
vid1: video1, | ||
vid2: video2, | ||
target: target1, | ||
disp: 'disp-snow.jpg', | ||
dispScale: 1.0 | ||
}); | ||
/* | ||
* register event handlers for interaction | ||
*/ | ||
target1.addEventListener('mouseenter', () => trans.forward()); | ||
target1.addEventListener('mouseleave', () => trans.backward()); | ||
const {Kampos: Kampos$1, effects, transitions: transitions$1} = window.kampos; | ||
const media1 = document.querySelector('#video3'); | ||
const media2 = document.querySelector('#video4'); | ||
const target = document.querySelector('#target2'); | ||
// create the effects/transitions we need | ||
const hueSat = effects.hueSaturation(); | ||
const fade = transitions$1.fade(); | ||
// init kampos | ||
const instance = new Kampos$1({target, effects:[fade, hueSat]}); | ||
// make sure videos are loaded and playing | ||
prepareVideos([media1, media2]) | ||
.then(() => { | ||
const width = media1.videoWidth; | ||
const height = media1.videoHeight; | ||
// set media source | ||
instance.setSource({media: media1, width, height}); | ||
// set media to transition into | ||
fade.to = media2; | ||
// start kampos | ||
instance.play(); | ||
setTimeout(() => document.body.addEventListener('click', navOffHandler, {once: true}), 0); | ||
}); | ||
let x, y, rect; | ||
let drawing = false; | ||
// this is invoked once in every animation frame, while there's a mouse move over the canvas | ||
function tick () { | ||
fade.progress = Math.max(0, Math.min(1, (y - rect.y) / rect.height)); | ||
hueSat.hue = Math.max(0, Math.min(1, (x - rect.x) / rect.width)) * 360 - 180; | ||
drawing = false; | ||
} | ||
// handler for detecting mouse move | ||
const moveHandler = e => { | ||
const {clientX, clientY} = e; | ||
// cache mouse location | ||
x = clientX; | ||
y = clientY; | ||
// only once! a frame | ||
if (!drawing) { | ||
drawing = true; | ||
// read here | ||
rect = target.getBoundingClientRect(); | ||
// write on next frame | ||
requestAnimationFrame(tick); | ||
} | ||
}; | ||
/* | ||
* register event handlers for interaction | ||
*/ | ||
target.addEventListener('mouseenter', () => { | ||
target.addEventListener('mousemove', moveHandler); | ||
}); | ||
target.addEventListener('mouseleave', () => { | ||
target.removeEventListener('mousemove', moveHandler); | ||
}); | ||
}()); |
{ | ||
"name": "kampos", | ||
"version": "0.2.2", | ||
"version": "0.3.0", | ||
"description": "Tiny and fast effects compositor on WebGL", | ||
@@ -5,0 +5,0 @@ "registry": "https://registry.npmjs.org/", |
@@ -1,2 +0,6 @@ | ||
# kampos | ||
<p align="center"> | ||
<img width="100" src="./kampos.svg?sanitize=true"> | ||
</p> | ||
# kampos [![Build Status](https://travis-ci.com/wix-incubator/kampos.svg?branch=master)](https://travis-ci.com/wix-incubator/kampos) | ||
### Tiny and fast effects compositor on WebGL | ||
@@ -6,9 +10,9 @@ | ||
Just like [SVG filter effects](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Filter_effects), | ||
only using WebGL, and hence works everywhere! | ||
only using WebGL, which means it works everywhere! | ||
## Demo | ||
Watch a [live demo](https://wix-incubator.github.io/kampos/demo/). | ||
Check out the [live demo](https://wix-incubator.github.io/kampos/demo/). | ||
## Documentation | ||
For API reference and examples read [the docs](https://wix-incubator.github.io/kampos/docs/). | ||
For API reference and examples, read [the docs](https://wix-incubator.github.io/kampos/docs/). | ||
@@ -24,3 +28,3 @@ ## Features | ||
Here's a simple example for using kampos: | ||
``` | ||
```javascript | ||
import {Kampos, effects} from 'kampos'; | ||
@@ -44,3 +48,3 @@ | ||
### npm example: | ||
``` | ||
```bash | ||
npm install kampos | ||
@@ -50,9 +54,9 @@ ``` | ||
Import the default build: | ||
``` | ||
```javascript | ||
import {Kampos, Ticker, effects, transitions} from 'kampos'; | ||
``` | ||
Or just what you need: | ||
``` | ||
import {Kampos} from './node_modules/kampos/src/kampos'; | ||
Or take just what you need: | ||
```javascript | ||
import Kampos from './node_modules/kampos/src/kampos'; | ||
import duotone from './node_modules/kampos/src/effects/duotone'; | ||
@@ -63,3 +67,3 @@ import displacement from './node_modules/kampos/src/effects/displacement'; | ||
## Building locally | ||
``` | ||
```bash | ||
npm install | ||
@@ -70,3 +74,3 @@ npm run build | ||
## Running tests | ||
``` | ||
```bash | ||
npm run test | ||
@@ -73,0 +77,0 @@ ``` |
177
src/core.js
@@ -10,3 +10,3 @@ export default { | ||
const vertexTemplate = ({ | ||
const vertexSimpleTemplate = ({ | ||
uniform = '', | ||
@@ -21,2 +21,22 @@ attribute = '', | ||
${attribute} | ||
attribute vec2 a_position; | ||
${varying} | ||
const vec3 lumcoeff = vec3(0.2125, 0.7154, 0.0721); | ||
${constant} | ||
void main() { | ||
${main} | ||
gl_Position = vec4(a_position.xy, 0.0, 1.0); | ||
}`; | ||
const vertexMediaTemplate = ({ | ||
uniform = '', | ||
attribute = '', | ||
varying = '', | ||
constant = '', | ||
main = '' | ||
}) => ` | ||
precision mediump float; | ||
${uniform} | ||
${attribute} | ||
attribute vec2 a_texCoord; | ||
@@ -35,3 +55,3 @@ attribute vec2 a_position; | ||
const fragmentTemplate = ({ | ||
const fragmentSimpleTemplate = ({ | ||
uniform = '', | ||
@@ -45,2 +65,23 @@ varying = '', | ||
${varying} | ||
${uniform} | ||
const vec3 lumcoeff = vec3(0.2125, 0.7154, 0.0721); | ||
${constant} | ||
void main() { | ||
${source} | ||
vec3 color = vec3(0.0); | ||
float alpha = 1.0; | ||
${main} | ||
gl_FragColor = vec4(color, 1.0) * alpha; | ||
}`; | ||
const fragmentMediaTemplate = ({ | ||
uniform = '', | ||
varying = '', | ||
constant = '', | ||
main = '', | ||
source = '' | ||
}) => ` | ||
precision mediump float; | ||
${varying} | ||
varying vec2 v_texCoord; | ||
@@ -66,10 +107,12 @@ ${uniform} | ||
* @private | ||
* @param {WebGLRenderingContext} gl | ||
* @param effects | ||
* @param dimensions | ||
* @param {Object} config | ||
* @param {WebGLRenderingContext} config.gl | ||
* @param {Object[]} config.effects | ||
* @param {{width: number, heignt: number}} [config.dimensions] | ||
* @param {boolean} [config.noSource] | ||
* @return {{gl: WebGLRenderingContext, data: kamposSceneData, [dimensions]: {width: number, height: number}}} | ||
*/ | ||
function init (gl, effects, dimensions) { | ||
function init ({gl, effects, dimensions, noSource}) { | ||
const programData = _initProgram(gl, effects); | ||
const programData = _initProgram(gl, effects, noSource); | ||
@@ -163,7 +206,9 @@ return {gl, data: programData, dimensions: dimensions || {}}; | ||
// bind the source texture | ||
gl.bindTexture(gl.TEXTURE_2D, source.texture); | ||
if ( media && source && source.texture ) { | ||
// bind the source texture | ||
gl.bindTexture(gl.TEXTURE_2D, source.texture); | ||
// read source data into texture | ||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, media); | ||
// read source data into texture | ||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, media); | ||
} | ||
@@ -215,3 +260,4 @@ // Tell it to use our program (pair of shaders) | ||
// delete texture | ||
gl.deleteTexture(source.texture); | ||
if ( source && source.texture ) | ||
gl.deleteTexture(source.texture); | ||
@@ -226,4 +272,4 @@ // delete program | ||
function _initProgram (gl, effects) { | ||
const source = { | ||
function _initProgram (gl, effects, noSource=false) { | ||
const source = noSource || { | ||
texture: createTexture(gl).texture, | ||
@@ -233,9 +279,11 @@ buffer: null | ||
// flip Y axis for source texture | ||
gl.bindTexture(gl.TEXTURE_2D, source.texture); | ||
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); | ||
if ( source ) { | ||
// flip Y axis for source texture | ||
gl.bindTexture(gl.TEXTURE_2D, source.texture); | ||
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); | ||
} | ||
const data = _mergeEffectsData(effects); | ||
const vertexSrc = _stringifyShaderSrc(data.vertex, vertexTemplate); | ||
const fragmentSrc = _stringifyShaderSrc(data.fragment, fragmentTemplate); | ||
const data = _mergeEffectsData(effects, noSource); | ||
const vertexSrc = _stringifyShaderSrc(data.vertex, noSource ? vertexSimpleTemplate : vertexMediaTemplate); | ||
const fragmentSrc = _stringifyShaderSrc(data.fragment, noSource ? fragmentSimpleTemplate : fragmentMediaTemplate); | ||
@@ -266,6 +314,6 @@ // compile the GLSL program | ||
function _mergeEffectsData (effects) { | ||
function _mergeEffectsData (effects, noSource=false) { | ||
return effects.reduce((result, config) => { | ||
const {attributes = [], uniforms = [], textures = [], varying = {}} = config; | ||
const merge = shader => Object.keys(config[shader]).forEach(key => { | ||
const merge = shader => Object.keys(config[shader] || {}).forEach(key => { | ||
if ( key === 'constant' || key === 'main' || key === 'source' ) { | ||
@@ -302,3 +350,47 @@ result[shader][key] += config[shader][key] + '\n'; | ||
return result; | ||
}, { | ||
}, getEffectDefaults(noSource)); | ||
} | ||
function getEffectDefaults (noSource) { | ||
/* | ||
* Default uniforms | ||
*/ | ||
const uniforms = noSource ? [] : [ | ||
{ | ||
name: 'u_source', | ||
type: 'i', | ||
data: [0] | ||
} | ||
]; | ||
/* | ||
* Default attributes | ||
*/ | ||
const attributes = [ | ||
{ | ||
name: 'a_position', | ||
data: new Float32Array([ | ||
-1.0, -1.0, | ||
-1.0, 1.0, | ||
1.0, -1.0, | ||
1.0, 1.0]), | ||
size: 2, | ||
type: 'FLOAT' | ||
} | ||
]; | ||
if ( ! noSource ) { | ||
attributes.push({ | ||
name: 'a_texCoord', | ||
data: new Float32Array([ | ||
0.0, 0.0, | ||
0.0, 1.0, | ||
1.0, 0.0, | ||
1.0, 1.0]), | ||
size: 2, | ||
type: 'FLOAT' | ||
}); | ||
} | ||
return { | ||
vertex: { | ||
@@ -318,42 +410,9 @@ uniform: {}, | ||
}, | ||
attributes, | ||
uniforms, | ||
/* | ||
* Default attributes | ||
*/ | ||
attributes: [ | ||
{ | ||
name: 'a_position', | ||
data: new Float32Array([ | ||
-1.0, -1.0, | ||
-1.0, 1.0, | ||
1.0, -1.0, | ||
1.0, 1.0]), | ||
size: 2, | ||
type: 'FLOAT' | ||
}, | ||
{ | ||
name: 'a_texCoord', | ||
data: new Float32Array([ | ||
0.0, 0.0, | ||
0.0, 1.0, | ||
1.0, 0.0, | ||
1.0, 1.0]), | ||
size: 2, | ||
type: 'FLOAT' | ||
} | ||
], | ||
/* | ||
* Default uniforms | ||
*/ | ||
uniforms: [ | ||
{ | ||
name: 'u_source', | ||
type: 'i', | ||
data: [0] | ||
} | ||
], | ||
/* | ||
* Default textures | ||
*/ | ||
textures: [] | ||
}); | ||
}; | ||
} | ||
@@ -360,0 +419,0 @@ |
@@ -11,4 +11,7 @@ /** | ||
* @property {boolean} disabled | ||
* @property {boolean} isLuminance | ||
* | ||
* @example | ||
* @description Multiplies `alpha` value with values read from `mask` media source. | ||
* | ||
* @example | ||
* const img = new Image(); | ||
@@ -30,2 +33,3 @@ * img.src = 'picture.png'; | ||
u_alphaMaskEnabled: 'bool', | ||
u_alphaMaskIsLuminance: 'bool', | ||
u_mask: 'sampler2D' | ||
@@ -35,3 +39,10 @@ }, | ||
if (u_alphaMaskEnabled) { | ||
alpha *= texture2D(u_mask, v_alphaMaskTexCoord).a; | ||
vec4 alphaMaskPixel = texture2D(u_mask, v_alphaMaskTexCoord); | ||
if (u_alphaMaskIsLuminance) { | ||
alpha *= dot(lumcoeff, alphaMaskPixel.rgb) * alphaMaskPixel.a; | ||
} | ||
else { | ||
alpha *= alphaMaskPixel.a; | ||
} | ||
}` | ||
@@ -51,2 +62,9 @@ }, | ||
}, | ||
get isLuminance () { | ||
return !!this.uniforms[2].data[0]; | ||
}, | ||
set isLuminance (toggle) { | ||
this.uniforms[2].data[0] = +toggle; | ||
this.textures[0].format = toggle ? 'RGBA' : 'ALPHA'; | ||
}, | ||
varying: { | ||
@@ -65,2 +83,7 @@ v_alphaMaskTexCoord: 'vec2' | ||
data: [1] | ||
}, | ||
{ | ||
name: 'u_alphaMaskIsLuminance', | ||
type: 'i', | ||
data: [0] | ||
} | ||
@@ -67,0 +90,0 @@ ], |
@@ -20,3 +20,2 @@ /** | ||
return { | ||
vertex: {}, | ||
fragment: { | ||
@@ -23,0 +22,0 @@ uniform: { |
@@ -10,3 +10,3 @@ /** | ||
* @property {ArrayBufferView|ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|ImageBitmap} map | ||
* @property {{x: number, y: number}} scale | ||
* @property {{x: number?, y: number?}} scale | ||
* @property {boolean} disabled | ||
@@ -13,0 +13,0 @@ * |
@@ -9,4 +9,4 @@ /** | ||
* @typedef {Object} duotoneEffect | ||
* @property {number[]} light Array of 4 numbers normalized (0.0 - 1.0) | ||
* @property {number[]} dark Array of 4 numbers normalized (0.0 - 1.0) | ||
* @property {number[]} light Array of 4 numbers, normalized (0.0 - 1.0) | ||
* @property {number[]} dark Array of 4 numbers, normalized (0.0 - 1.0) | ||
* @property {boolean} disabled | ||
@@ -19,3 +19,2 @@ * | ||
return { | ||
vertex: {}, | ||
fragment: { | ||
@@ -22,0 +21,0 @@ uniform: { |
@@ -6,2 +6,4 @@ import alphaMask from './effects/alpha-mask'; | ||
import displacement from './effects/displacement'; | ||
import perlinNoise from './noise/perlin-noise-3d'; | ||
import turbulence from './effects/turbulence'; | ||
import fade from './transitions/fade'; | ||
@@ -18,3 +20,4 @@ import displacementTransition from './transitions/displacement'; | ||
duotone, | ||
displacement | ||
displacement, | ||
turbulence | ||
}, | ||
@@ -25,4 +28,7 @@ transitions: { | ||
}, | ||
noise: { | ||
perlinNoise | ||
}, | ||
Kampos, | ||
Ticker | ||
}; |
import core from './core'; | ||
/** | ||
* Initialize a webgl target with effects. | ||
* Initialize a WebGL target with effects. | ||
* | ||
@@ -9,7 +9,7 @@ * @class Kampos | ||
* @example | ||
* import {Ticker, Kampos, effects} from 'kampos'; | ||
* const ticker = new Ticker(); | ||
* import { Kampos, effects} from 'kampos'; | ||
* | ||
* const target = document.querySelector('#canvas'); | ||
* const hueSat = effects.hueSaturation(); | ||
* const kampos = new Kampos({ticker, target, effects: [hueSat]}); | ||
* const kampos = new Kampos({target, effects: [hueSat]}); | ||
*/ | ||
@@ -87,6 +87,6 @@ export default class Kampos { | ||
/** | ||
* Initializes an Kampos instance. | ||
* Initializes a Kampos instance. | ||
* This is called inside the constructor, | ||
* but can be called again after effects have changed | ||
* or after {@link Kampos#desotry()}. | ||
* or after {@link Kampos#destroy}. | ||
* | ||
@@ -98,3 +98,3 @@ * @param {kamposConfig} [config] defaults to `this.config` | ||
config = config || this.config; | ||
let {target, effects, ticker} = config; | ||
let {target, effects, ticker, noSource} = config; | ||
@@ -124,3 +124,3 @@ if ( Kampos.preventContextCreation ) | ||
const {data} = core.init(gl, effects, this.dimensions); | ||
const {data} = core.init({gl, effects, dimensions: this.dimensions, noSource}); | ||
@@ -189,2 +189,7 @@ this.gl = gl; | ||
const cb = this.config.beforeDraw; | ||
if ( cb && cb() === false ) | ||
return; | ||
core.draw(this.gl, this.media, this.data, this.dimensions); | ||
@@ -196,5 +201,9 @@ } | ||
* | ||
* If using a {@see Ticker} this instance will be added to that {@see Ticker}. | ||
* If a {@link Ticker} is used, this instance will be added to that {@link Ticker}. | ||
* | ||
* @param {function} beforeDraw function to run before each draw call | ||
*/ | ||
play () { | ||
play (beforeDraw) { | ||
this.config.beforeDraw = beforeDraw; | ||
if ( this.ticker ) { | ||
@@ -224,3 +233,3 @@ if ( this.animationFrameId ) { | ||
* | ||
* If using a {@see Ticker} this instance will be removed from that {@see Ticker}. | ||
* If a {@link Ticker} is used, this instance will be removed from that {@link Ticker}. | ||
*/ | ||
@@ -240,5 +249,5 @@ stop () { | ||
/** | ||
* Stops animation loop and frees all resources. | ||
* Stops the animation loop and frees all resources. | ||
* | ||
* @param {boolean} keepState for internal use. | ||
* @param {boolean} keepState for internal use. | ||
*/ | ||
@@ -329,2 +338,4 @@ destroy (keepState) { | ||
* @property {Ticker} [ticker] | ||
* @property {boolean} [noSource] | ||
* @property {function} [beforeDraw] function to run before each draw call. If it returns `false` {@link kampos#draw} will not be called. | ||
* @property {function} [onContextLost] | ||
@@ -357,4 +368,4 @@ * @property {function} [onContextRestored] | ||
* @property {string} [constant] | ||
* @property {Object} [uniform] mapping name of variable to type | ||
* @property {Object} [attribute] mapping name of variable to type | ||
* @property {Object} [uniform] mapping variable name to type | ||
* @property {Object} [attribute] mapping variable name to type | ||
*/ | ||
@@ -361,0 +372,0 @@ |
/** | ||
* Initialize a ticker instance for batching animation of multiple Kampos instances. | ||
* Initialize a ticker instance for batching animation of multiple {@link Kampos} instances. | ||
* | ||
@@ -34,3 +34,3 @@ * @class Ticker | ||
/** | ||
* Invoke draw() on all instances in the pool. | ||
* Invoke `.draw()` on all instances in the pool. | ||
*/ | ||
@@ -37,0 +37,0 @@ draw () { |
@@ -12,4 +12,4 @@ /** | ||
* @property {number} progress number between 0.0 and 1.0 | ||
* @property {{x: number, y: number}} sourceScale | ||
* @property {{x: number, y: number}} toScale | ||
* @property {{x: number?, y: number?}} sourceScale | ||
* @property {{x: number?, y: number?}} toScale | ||
* @property {boolean} disabled | ||
@@ -16,0 +16,0 @@ * |
@@ -25,3 +25,3 @@ const core = require('./src/core'); | ||
const canvas = document.createElement('canvas'); | ||
const {gl, data} = core.init(core.getWebGLContext(canvas), [brightnessContrast]); | ||
const {gl, data} = core.init({gl: core.getWebGLContext(canvas), effects: [brightnessContrast]}); | ||
@@ -36,3 +36,3 @@ assert(gl); | ||
const canvas = document.createElement('canvas'); | ||
const {gl, data} = core.init(core.getWebGLContext(canvas), [brightnessContrast]); | ||
const {gl, data} = core.init({gl: core.getWebGLContext(canvas), effects: [brightnessContrast]}); | ||
@@ -70,3 +70,3 @@ assert(gl); | ||
const initData = core.init(core.getWebGLContext(canvas), [brightnessContrast]); | ||
const initData = core.init({gl: core.getWebGLContext(canvas), effects: [brightnessContrast]}); | ||
@@ -92,3 +92,3 @@ gl = initData.gl; | ||
const initData = core.init(core.getWebGLContext(canvas), [brightnessContrast]); | ||
const initData = core.init({gl: core.getWebGLContext(canvas), effects: [brightnessContrast]}); | ||
@@ -134,3 +134,3 @@ gl = initData.gl; | ||
core.destroy(gl, scene); | ||
const initData2fx = core.init(core.getWebGLContext(canvas), [brightnessContrast]); | ||
const initData2fx = core.init({gl: core.getWebGLContext(canvas), effects: [brightnessContrast]}); | ||
@@ -161,3 +161,3 @@ gl = initData2fx.gl; | ||
const initData = core.init(core.getWebGLContext(canvas), [brightnessContrast]); | ||
const initData = core.init({gl: core.getWebGLContext(canvas), effects: [brightnessContrast]}); | ||
@@ -164,0 +164,0 @@ gl = initData.gl; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
11817558
168
17147
78
22