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()