Skip to content

Commit

Permalink
Support OffscreenCanvas (#31)
Browse files Browse the repository at this point in the history
* Bump deps and added support for using OffscreenCanvas

* Updated docs

* Updated CHANGELOG

* Fixed test that is not failing
  • Loading branch information
ydaniv authored Aug 13, 2024
1 parent 384dc85 commit 21a4287
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20.13.1
20.16.0
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
### 0.9.0 (2024-08-13)

*New:*

- Added `afterDraw` callback to kampos config. Used to pass a function that will be called after each draw call.
- Added optional function argument `afterDraw` to `kampos#play()` method to be dynamically set to `kampos.config.afterDraw`.
- Added optional boolean argument `skipTextureCreation` to `kampos#setSource()` method to skip texture creation for the source
media. useful for cases where using an OffscreenCanvas as a source for multiple programs and need to switch between them.

### 0.8.0 (2023-04-01)

*Breaking:*
Expand Down
38 changes: 32 additions & 6 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset='utf-8'>
<title>kampos 0.8.0 | Documentation</title>
<title>kampos 0.9.0 | Documentation</title>
<meta name='description' content='Tiny and fast effects compositor on WebGL'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<link href='assets/bass.css' rel='stylesheet'>
Expand All @@ -15,7 +15,7 @@
<div id='split-left' class='overflow-auto fs0 height-viewport-100'>
<div class='py1 px2'>
<h3 class='mb0 no-anchor'>kampos</h3>
<div class='mb1'><code>0.8.0</code></div>
<div class='mb1'><code>0.9.0</code></div>
<input
placeholder='Filter'
id='filter-input'
Expand Down Expand Up @@ -613,7 +613,7 @@ <h3 class='fl m0' id='kampos'>
<div class="clearfix small pointer toggle-sibling">
<div class="py1 contain">
<a class='icon pin-right py1 dark-link caret-right'></a>
<span class='code strong strong truncate'>setSource(source)</span>
<span class='code strong strong truncate'>setSource(source, skipTextureCreation?)</span>
</div>
</div>
<div class="clearfix display-none toggle-target">
Expand All @@ -623,7 +623,7 @@ <h3 class='fl m0' id='kampos'>

<p>Set the source config.</p>

<div class='pre p1 fill-light mt0'>setSource(source: (ArrayBufferView | ImageData | <a href="https://developer.mozilla.org/docs/Web/API/HTMLImageElement">HTMLImageElement</a> | <a href="https://developer.mozilla.org/docs/Web/API/HTMLCanvasElement">HTMLCanvasElement</a> | <a href="https://developer.mozilla.org/docs/Web/API/HTMLVideoElement">HTMLVideoElement</a> | ImageBitmap | <a href="#kampossource">kamposSource</a>))</div>
<div class='pre p1 fill-light mt0'>setSource(source: (ArrayBufferView | ImageData | <a href="https://developer.mozilla.org/docs/Web/API/HTMLImageElement">HTMLImageElement</a> | <a href="https://developer.mozilla.org/docs/Web/API/HTMLCanvasElement">HTMLCanvasElement</a> | <a href="https://developer.mozilla.org/docs/Web/API/HTMLVideoElement">HTMLVideoElement</a> | ImageBitmap | <a href="#kampossource">kamposSource</a>), skipTextureCreation: <a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean">boolean</a>?)</div>



Expand All @@ -646,6 +646,16 @@ <h3 class='fl m0' id='kampos'>

</div>

<div class='space-bottom0'>
<div>
<span class='code bold'>skipTextureCreation</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean">boolean</a>?)</code>
defaults to
<code>false</code>

</div>

</div>

</div>


Expand Down Expand Up @@ -744,7 +754,7 @@ <h3 class='fl m0' id='kampos'>
<div class="clearfix small pointer toggle-sibling">
<div class="py1 contain">
<a class='icon pin-right py1 dark-link caret-right'></a>
<span class='code strong strong truncate'>play(beforeDraw)</span>
<span class='code strong strong truncate'>play(beforeDraw, afterDraw)</span>
</div>
</div>
<div class="clearfix display-none toggle-target">
Expand All @@ -755,7 +765,7 @@ <h3 class='fl m0' id='kampos'>
<p>Starts the animation loop.</p>
<p>If a <a href="#ticker">Ticker</a> is used, this instance will be added to that <a href="#ticker">Ticker</a>.</p>

<div class='pre p1 fill-light mt0'>play(beforeDraw: <a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function">function</a>)</div>
<div class='pre p1 fill-light mt0'>play(beforeDraw: <a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function">function</a>, afterDraw: <a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function">function</a>)</div>



Expand All @@ -779,6 +789,15 @@ <h3 class='fl m0' id='kampos'>

</div>

<div class='space-bottom0'>
<div>
<span class='code bold'>afterDraw</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function">function</a>)</code>
function to run after each draw call

</div>

</div>

</div>


Expand Down Expand Up @@ -1402,6 +1421,13 @@ <h3 class='fl m0' id='kamposconfig'>
will not be called.


</div>

<div class='space-bottom0'>
<span class='code bold'>afterDraw</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function">function</a>?)</code>
: function to run after each draw call.


</div>

<div class='space-bottom0'>
Expand Down
222 changes: 165 additions & 57 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,40 @@
right: 50px;
}

#target {
.target-canvas {
position: fixed;
top: 0;
left: 0;
z-index: -2;
pointer-events: none;
}

#target2 {
left: 50%;
}

#target3 {
position: fixed;
top: 10vh;
left: 5vw;
z-index: -1;
pointer-events: none;
}

#target4 {
position: fixed;
bottom: 10vh;
right: 5vw;
z-index: -1;
pointer-events: none;
}

#video, #video2 {
position: fixed;
top: 0;
content-visibility: hidden;
}

@media (min-width: 641px) {
html, body {
margin: 0;
Expand Down Expand Up @@ -137,80 +163,162 @@
</nav>
</header>
<main>
<canvas id="target"></canvas>
<canvas class="target-canvas" id="target"></canvas>
<canvas class="target-canvas" id="target2"></canvas>
<canvas id="target3"></canvas>
<canvas id="target4"></canvas>
<h1>kampos</h1>
<h2>Tiny and fast effects compositor</h2>
<video id="video" src="https://video.wixstatic.com/video/11062b_6ceb80744f45401caf9eb666caeb9887/480p/mp4/file.mp4" loop muted preload="auto" crossorigin="anonymous" playsinline autoplay></video>
<video id="video2" src="./demo/starry-night.mp4" loop muted preload="auto" crossorigin="anonymous" playsinline autoplay></video>
</main>
<script type="module">
import {Kampos, effects, noise} from './index.js';

const target = document.querySelector('#target');
const body = document.body;
const width = body.clientWidth;
const height = body.clientHeight;

target.width = width;
target.height = height;

const mousePosition = [0.5, 0.5];

const turbulence = effects.turbulence({noise: noise.simplex, output: '\n'});
const render = {
fragment: {
uniform: {
u_resolution: 'vec2',
u_pointer: 'vec2'
},
constant: `
</body>
<script type="module">
import {Kampos, effects, noise} from './index.js';

const target = document.querySelector('#target');
const targetCtx = target.getContext('bitmaprenderer');
const target2 = document.querySelector('#target2');
const target2Ctx = target2.getContext('bitmaprenderer');
const target3 = document.querySelector('#target3');
const target3Ctx = target3.getContext('bitmaprenderer');
const target4 = document.querySelector('#target4');
const target4Ctx = target4.getContext('bitmaprenderer');

const body = document.body;
const width = body.clientWidth / 2;
const height = body.clientHeight;

target.width = width;
target.height = height;
target2.width = width;
target2.height = height;

const offscreen = new OffscreenCanvas(width, height);

const mousePosition = [0.5, 0.5];
const mousePosition2 = [0.5, 0.5];

const turbulence = effects.turbulence({noise: noise.simplex, output: '\n'});
const getRender = (c, d, mouse) => ({
fragment: {
uniform: {
u_resolution: 'vec2',
u_pointer: 'vec2'
},
constant: `
vec3 A = vec3(0.5);
vec3 B = vec3(0.5);
vec3 C = vec3(1.0, 0.7, 0.4);
vec3 D = vec3(0.0, 0.15, 0.2);
vec3 C = vec3(${c});
vec3 D = vec3(${d});
vec3 palette(float t, vec3 a, vec3 b, vec3 c, vec3 d) {
return a + b * cos(6.28318 * (c * t + d));
}`,
main: `
main: `
vec2 st = gl_FragCoord.xy / u_resolution.xy;
float dist = distance(u_pointer, st);
alpha = smoothstep(turbulenceValue * 0.2, 0.2 + turbulenceValue * 0.2, dist);
color = palette(turbulenceValue, A, B, C, D);`
},
uniforms: [
{
name: 'u_resolution',
type: 'f',
data: [width, height]
},
uniforms: [
{
name: 'u_resolution',
type: 'f',
data: [width, height]
},
{
name: 'u_pointer',
type: 'f',
data: mousePosition
}
],
get mouse() {
return this.uniforms[1].data;
},
set mouse(data) {
this.uniforms[1].data[0] = data[0];
this.uniforms[1].data[1] = data[1];
{
name: 'u_pointer',
type: 'f',
data: mouse
}
};
],
get mouse() {
return this.uniforms[1].data;
},
set mouse(data) {
this.uniforms[1].data[0] = data[0];
this.uniforms[1].data[1] = data[1];
}
});

const render = getRender([1.0, 0.7, 0.4], [0.0, 0.15, 0.2], mousePosition);
const render2 = getRender([0.0, 0.9, 0.6], [0.6, 0.15, 0.5], mousePosition2);

const FREQUENCY = 2 / (width > height ? width : height);

const FREQUENCY = 2 / (width > height ? width : height);
turbulence.frequency = {x: FREQUENCY, y: FREQUENCY};
turbulence.octaves = 6;

turbulence.frequency = {x: FREQUENCY, y: FREQUENCY};
turbulence.octaves = 6;
const instance = new Kampos({target: offscreen, effects:[turbulence, render], noSource: true});
const instance2 = new Kampos({target: offscreen, effects:[turbulence, render2], noSource: true});
const source = {width, height};

const instance = new Kampos({target, effects:[turbulence, render], noSource: true});
instance.play((time) => {
render.mouse = mousePosition;
turbulence.time = time * 2;
instance.play((time) => {
instance.setSource(source, true);
render.mouse = mousePosition;
turbulence.time = time * 2;
}, () => {
const bitmap = offscreen.transferToImageBitmap();
targetCtx.transferFromImageBitmap(bitmap);
});

instance2.play((time) => {
instance.setSource(source, true);
render2.mouse = mousePosition2;
turbulence.time = time * 3;
}, () => {
const bitmap = offscreen.transferToImageBitmap();
target2Ctx.transferFromImageBitmap(bitmap);
});

document.body.addEventListener('mousemove', (e) => {
mousePosition[0] = e.clientX / width;
mousePosition2[0] = (e.clientX - width) / width;
mousePosition[1] = (height - e.clientY) / height;
mousePosition2[1] = (height - e.clientY) / height;
});

const video = document.querySelector('#video');
video.addEventListener('timeupdate', () => {
const duotone = effects.duotone();
const instance3 = new Kampos({target: offscreen, effects:[duotone]});

const width = video.videoWidth;
const height = video.videoHeight;
const source = {media: video, width, height};
target3.width = width;
target3.height = height;
instance3.setSource(source);

instance3.play((time) => {
instance3.setSource(source, true);
}, () => {
const bitmap = offscreen.transferToImageBitmap();
target3Ctx.transferFromImageBitmap(bitmap);
});
}, {once: true});

document.body.addEventListener('mousemove', (e) => {
mousePosition[0] = e.clientX / width;
mousePosition[1] = (height - e.clientY) / height;
const video2 = document.querySelector('#video2');
video2.addEventListener('timeupdate', () => {
const duotone = effects.duotone({
light: [1, 1, 1, 1],
dark: [0, 0, 0, 1]
});
</script>
</body>
const instance4 = new Kampos({target: offscreen, effects:[duotone]});

const width = video2.videoWidth;
const height = video2.videoHeight;
const source = {media: video2, width, height};
target4.width = width;
target4.height = height;
instance4.setSource(source);

instance4.play((time) => {
instance4.setSource(source, true);
}, () => {
const bitmap = offscreen.transferToImageBitmap();
target4Ctx.transferFromImageBitmap(bitmap);
});
}, {once: true});
</script>
</html>
Loading

0 comments on commit 21a4287

Please sign in to comment.