Created
May 8, 2020 01:20
-
-
Save j-k-projects/1ecdddae7f48cf58b8c52608980bf633 to your computer and use it in GitHub Desktop.
Shapeshifter Blob
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="canvas_wrapper"> | |
<canvas id="c"></canvas> | |
</div> | |
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"> | |
<defs> | |
<filter id="goo"> | |
<feGaussianBlur in="SourceGraphic" result="blur" stdDeviation="8" /> | |
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="joint" /> | |
</filter> | |
</defs> | |
</svg> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
console.clear() | |
class Utils { | |
static randomRange(min, max) { | |
return Math.random() * (max - min) + min | |
} | |
static mapRange (value, inputMin, inputMax, outputMin, outputMax, clamp) { | |
if (Math.abs(inputMin - inputMax) < Number.EPSILON) { | |
return outputMin; | |
} else { | |
var outVal = ((value - inputMin) / (inputMax - inputMin) * (outputMax - outputMin) + outputMin); | |
if (clamp) { | |
if (outputMax < outputMin) { | |
if (outVal < outputMax) outVal = outputMax; | |
else if (outVal > outputMin) outVal = outputMin; | |
} else { | |
if (outVal > outputMax) outVal = outputMax; | |
else if (outVal < outputMin) outVal = outputMin; | |
} | |
} | |
return outVal; | |
} | |
} | |
} | |
Utils.simplex = new SimplexNoise('seed') | |
class App { | |
constructor() { | |
this.canvas = document.getElementById('c') | |
this.ctx = this.canvas.getContext('2d') | |
this.shadowCanvas = document.createElement('canvas') | |
this.shadowCtx = this.shadowCanvas.getContext('2d') | |
this.timestamp = 0 | |
this.fpsHistory = [] | |
this.angle = 0 | |
this.setUpVars() | |
this.setUpListeners() | |
// this.setUpGui() | |
this.update() | |
} | |
setUpGui() { | |
const pane = new Tweakpane() | |
const folder = pane.addFolder({ | |
expanded: false, | |
title: 'Settings', | |
}) | |
folder.addInput(this.config, 'bgColor') | |
} | |
setUpVars() { | |
this.canvas.width = this.shadowCanvas.width = this.wWidth = window.innerWidth | |
this.canvas.height = this.shadowCanvas.height = this.wHeight = window.innerHeight | |
this.wCenterX = this.wWidth / 2 | |
this.wCenterY = this.wHeight / 2 | |
this.wHypot = Math.hypot(this.wWidth, this.wHeight) | |
this.wMin = Math.min(this.wWidth, this.wHeight) | |
} | |
setUpListeners() { | |
window.addEventListener('resize', this.setUpVars.bind(this)) | |
} | |
drawTheThing(ctx, angle, scale = 1, color = '#000') { | |
const angleStep = Math.PI * 0.01 | |
const maxRadius = this.wMin * 0.3 * scale | |
let radius = maxRadius | |
ctx.save() | |
ctx.translate(this.wCenterX, this.wCenterY) | |
ctx.rotate(this.angle + angle) | |
ctx.beginPath() | |
const startR = Utils.simplex.noise2D(Math.sin(0), this.timestamp) * radius | |
const startX = Math.sin(0) * startR | |
const startY = Math.cos(0) * startR | |
ctx.moveTo(startX, startY) | |
for (let angle = 0; angle <= Math.PI * 2; angle += angleStep) { | |
const n = Utils.simplex.noise2D(Math.sin(angle), this.timestamp) | |
const newRadius = n * radius | |
const xPos = Math.sin(angle) * newRadius | |
const yPos = Math.cos(angle) * newRadius | |
ctx.lineTo( | |
xPos, | |
yPos | |
) | |
} | |
ctx.fillStyle = color | |
ctx.fill() | |
for (let angle = 0; angle <= Math.PI * 2; angle += angleStep) { | |
const n = Utils.simplex.noise2D(Math.sin(angle), this.timestamp) | |
const newRadius = Math.pow(n * radius, 1.1) | |
const xPos = Math.sin(angle) * newRadius | |
const yPos = Math.cos(angle) * newRadius | |
ctx.beginPath() | |
ctx.arc( | |
xPos, | |
yPos, | |
this.wMin * 0.01, | |
0, Math.PI * 2 | |
) | |
ctx.fill() | |
} | |
ctx.restore() | |
} | |
draw(ctx) { | |
ctx.save() | |
ctx.clearRect(0, 0, this.wWidth, this.wHeight) | |
ctx.restore() | |
this.drawTheThing(ctx, 0) | |
this.drawTheThing(ctx, Math.PI * 0.13, 0.9) | |
this.drawTheThing(ctx, Math.PI * 0.24, 0.8) | |
this.drawTheThing(ctx, Math.PI * 0.37, 0.8) | |
this.drawTheThing(ctx, Math.PI * 0.6, 0.8) | |
this.drawTheThing(ctx, Math.PI * 0.77, 1) | |
} | |
update(t) { | |
const prevTimestamp = this.timestamp * 5000 | |
if (t) { | |
this.timestamp = t / 5000 | |
this.angle += 0.001 | |
this.draw(this.shadowCtx) | |
} | |
this.ctx.clearRect(0, 0, this.wWidth, this.wHeight) | |
this.ctx.drawImage(this.shadowCanvas, 0, 0) | |
// show fps | |
const fps = Math.round(1 / (t - prevTimestamp) * 1000) | |
this.fpsHistory.unshift(fps) | |
this.fpsHistory.length = 5 | |
this.ctx.font = '16px sans-serif' | |
this.ctx.fillText(this.fpsHistory.reduce((a,b) => a+b) / 5, 50, 50) | |
window.requestAnimationFrame(this.update.bind(this)) | |
} | |
} | |
new App() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/victor/1.1.0/victor.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/2.1.0/chroma.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.4.0/simplex-noise.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/tweakpane.min.js"></script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
overflow: hidden; | |
background-image: radial-gradient( | |
circle at center, | |
#E08E79, | |
#F1D4AF, | |
#ECE5CE, | |
#C5E0DC | |
); | |
& > .canvas_wrapper { | |
width: 100vw; height: 100vh; | |
-webkit-filter: url("#goo"); | |
filter: url("#goo"); | |
& > canvas { | |
width: 100%; height: 100%; | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment