viewof gif = {
const gif = new GIF()
const canvas = DOM.canvas(w, h)
const context = canvas.getContext('2d')
const gradients = array(ny).map(i => {
const gradient = context.createLinearGradient(0, h / 2, w, h / 2)
array(nx[i]).forEach((d, j, arr) => {
gradient.addColorStop(j / (arr.length - 1), colorScale(random()))
})
return gradient
})
context.shadowColor = 'black'
context.shadowBlur = 15
for (let t = 0, nFrames = 60; t < nFrames; t++) {
const xt = Math.cos(t / nFrames * TAU) * moveAmp
const yt = Math.sin(t / nFrames * TAU) * moveAmp
context.fillStyle = 'black'
context.fillRect(0, 0, w, h)
array(ny).forEach(i => {
const Y = (h + 200) / (ny - 1) * i - 100
let x = 0
let y = Y + simplex.noise3D(x / noiseScale + xt, Y / noiseScale + yt, seed) * amp
const step = w / nx[i]
context.fillStyle = gradients[i]
context.beginPath()
context.moveTo(-10, h + 200)
context.lineTo(0, y)
array(nx[i]).forEach(() => {
let px = x
x = x + step
let py = y
y = Y + simplex.noise3D(x / noiseScale + xt, Y / noiseScale + yt, seed) * amp
context.bezierCurveTo(px + step / 4, py, x - step / 4, y, x, y)
})
context.lineTo(w + 10, h + 200)
context.closePath()
context.fill()
})
gif.addFrame(canvas, { copy: true, delay: 120, quality: 1 })
yield canvas;
}
gif.on('finished', blob => {
canvas.value = blob
canvas.dispatchEvent(new CustomEvent('input'))
})
gif.render()
}