Alga
Sample generative art as a playground of Tweakpane, compact GUI for fine-tuning parameters and monitoring value changes.
by cocopon
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.4/pixi.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/tweakpane.min.js"></script>
CSS
@import url('https://fonts.googleapis.com/css?family=Roboto+Mono:400,500,700');
html,
body {
background: #111;
margin: 0;
overflow: hidden;
width: 600px;
}
body>canvas {
left: 50%;
margin-left: -300px;
margin-top: -300px;
position: absolute;
top: 50%;
}
/* Translucent pane */
:root {
--tp-base-background-color: #2f313740;
}
.tp-rotv {
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
JavaScript
// Input parameters
const INPUTS = {
color: '#fff',
count: 10000,
mainFreq: 24,
maxSize: 180,
minSize: 130,
speed: 2 * 1e-4,
subFreq: 300,
subLen: 0.2,
};
// Output parameters
const OUTPUTS = {
json: '',
};
// Canvas size
const SIZE = 600;
function map(v, s1, e1, s2, e2) {
return s2 + (v - s1) / (e1 - s1) * (e2 - s2);
}
function saveCanvas(canvasElem) {
const anchor = document.createElement('a');
anchor.download = 'capture.png';
anchor.href = canvasElem.toDataURL();
anchor.click();
}
// Custom shader
class EffectFilter extends PIXI.Filter {
constructor() {
super(
null,
`
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform vec4 filterArea;
uniform vec2 screenSize;
uniform float abberation;
vec2 applyOffset(float ofs) {
return ((vTextureCoord.xy * filterArea.xy - screenSize / 2.0) * (1.0 + ofs) + screenSize / 2.0) / filterArea.xy;
}
void main(void) {
float pr = texture2D(uSampler, applyOffset(0.0)).r;
float pg = texture2D(uSampler, applyOffset(-abberation)).g;
float pb = texture2D(uSampler, applyOffset(abberation * -2.0)).b;
gl_FragColor = vec4(pr, pg, pb, 1.0);
}
`, {
abberation: {
type: 'float',
value: 0,
},
screenSize: {
type: 'vec2',
value: [0, 0],
},
}
);
this.padding = 0;
}
get abberation() {
return this.uniforms.abberation;
}
set abberation(value) {
this.uniforms.abberation = value;
}
get screenSize() {
return this.uniforms.screenSize;
}
set screenSize(value) {
this.uniforms.screenSize = value;
}
}
// PIXI.js application
const app = new PIXI.Application({
height: SIZE,
preserveDrawingBuffer: true,
width: SIZE,
});
app.stage.filterArea = new PIXI.Rectangle(0, 0, SIZE, SIZE);
document.body.appendChild(app.renderer.view);
const filter = new EffectFilter();
filter.abberation = 0.015;
filter.screenSize = [SIZE,...