Realish-time in-browser video effects using vanilla Javascript.
You'll need node
(v13.8.9 or compatible) and npm
(v6.13.6 or compatible) installed.
I recommend using nvm to install/manage your node versions.
npm install
npm run dev
npm run build
You'll find the result at: build/dist/index.html
Each filter parameter textarea input supports arbitrary Javascript expressions and is eval()
'd to produce a number
before passing the value to the underlying filter function. If the expression does not produce a number
, the video stream will pause until you give it what it wants.
This means that you have the entire browser Javascript API at your disposal, allowing you to specify dynamic values like Date.now()
and Math.random()
in your filter params.
The following application-specific variables (created by getAudioParams()) are also supported in the filter params:
loudness
- The loudness of the audio in the range0.0 - 1.0
samples
- The array of 8-bit audio samples for the current frame (not really useful for most filters but is implicitly used as the sole argument to the Audio Plot filter)
The whole point of this project is to make it easy to write vanilla Javascript functions to process video frame pixels.
To create a new filter:
-
Create your new filter function in filters.js. I suggest using invert as a template for a parameterless function, and brightness for one that takes one or more parameters.
-
Add a gpu.js wrapper function for your filter in gpuFilters.js. I also recommend using
invert
andbrightness
as templates here. -
Add your filter's dropdown label to constants.FILTER_NAME_DISPLAYNAME_MAP
-
Add your filter's default params to constants.FILTER_NAME_PARAM_DEFAULT_MAP
-
Add your filter function's positional
params
argument info to constants.FILTER_NAME_PARAM_KEY_ARR_POS_MAP. Within the application, the filter params are represented using an object with human-friendly keys and values, but when it comes time to actually invoke the filter function, for compatibility withgpu.js
, this params object needs to be converted to an array of numbers andFILTER_NAME_PARAM_KEY_ARR_POS_MAP
is where you specify the position in the final array for each param.
Note that if your filter function needs to access the original ImageData
array (passed to the filter function as data
), for example to read pixels other than its own to implement something like Horizontal Mirror
, you need to:
- Define your non-GPU filter function in
filters.js
- Add your filter to the filters.FRAME_BUFFER_FILTERS array
- Define your GPU filter function in
gpuFilters.js
that includes all of the filter logic / does not invokeFILTERS.<yourNonGPUFunction>
Here are some examples of filters that are implemented in this way:
- Flip Horizontal
- Horizontal Mirror
- Vertical Mirror
- Blur
- Pan / Zoom