Example
<a href="https://xyzcode.blogspot.com/2019/04/icy-landscape.html">
<div id="stage">
</div>
</a>
<style>
#stage {
width: 700px;
height: 100%;
}
canvas {
position: relative;
place-content: center;
}
</style>
<script>
let { sin, cos, random, PI, abs, max} = Math
let c = document.getElementById('stage').appendChild(document.createElement('canvas')).getContext('2d')
let mask = document.createElement('canvas').getContext('2d')
let canvas = c.canvas
let image = new Image()
let frame = 0
let renderSquares = () => {
squares.forEach(square => {
let {x, y, p, s} = square
c.save()
c.translate(x + sin(frame / 100 + p) * canvas.width / 2, y + cos(frame / 100 + p) * canvas.height / 2)
c.rotate(frame / 180 * PI + p)
c.fillStyle = "#111"
c.fillRect(-s / 2, - s / 2, s, s)
c.restore()
})
}
let clear = () => {
c.fillStyle = "#000"
c.fillRect(0, 0, canvas.width, canvas.height)
}
let render = () => {
let percentFrame = frame % 100 / 100
frame++
clear()
c.drawImage(image, 0, 0, image.width, image.height)
mask.save()
mask.translate(canvas.width / 2, canvas.height / 2)
mask.scale(1.2 + sin(frame / 100) * 0.1, 1.2 + sin(frame / 100) * 0.1)
mask.drawImage(canvas, -canvas.width / 2, -canvas.height / 2)
mask.restore()
mask.globalCompositeOperation = "multiply"
mask.fillStyle = mask.createRadialGradient(canvas.width / 2, canvas.height / 2, 32 + sin(frame / 30) * 16, canvas.width / 2, canvas.height / 2, canvas.width / 1.5)
mask.fillStyle.addColorStop(0, "#000")
mask.fillStyle.addColorStop(0.8 + cos(frame / 30) * 0.1, "#000")
mask.fillStyle.addColorStop(0.6 + cos(frame / 40) * 0.05, "#fff")
mask.fillStyle.addColorStop(0.4 + cos(frame / 50) * 0.1, "#000")
mask.fillStyle.addColorStop(0.2 + cos(frame / 60) * 0.05, "#fff")
mask.fillStyle.addColorStop(0, "#000")
mask.fillRect(0, 0, canvas.width, canvas.height)
mask.globalCompositeOperation = "source-over"
c.globalCompositeOperation = "difference"
c.drawImage(mask.canvas, 0, 0)
c.globalCompositeOperation = "color-dodge"
c.drawImage(mask.canvas, 0, 0)
c.globalCompositeOperation = "source-over"
mask.drawImage(canvas, 0, 0)
mask.globalCompositeOperation = "screen"
mask.filter = "blur(3px)"
mask.drawImage(canvas, 0, 0)
mask.filter = "blur(0px)"
mask.globalCompositeOperation = "source-over"
c.drawImage(mask.canvas, 0, 0)
requestAnimationFrame(render)
}
canvas.width = mask.canvas.width = 500
canvas.height = mask.canvas.height = 500
image.src = "https://res.cloudinary.com/dlb3jof8w/image/upload/v1554933000/photo-1552332271-fcd3c889767e.jpg"
render()
</script>
<div id="stage">
</div>
</a>
<style>
#stage {
width: 700px;
height: 100%;
}
canvas {
position: relative;
place-content: center;
}
</style>
<script>
let { sin, cos, random, PI, abs, max} = Math
let c = document.getElementById('stage').appendChild(document.createElement('canvas')).getContext('2d')
let mask = document.createElement('canvas').getContext('2d')
let canvas = c.canvas
let image = new Image()
let frame = 0
let renderSquares = () => {
squares.forEach(square => {
let {x, y, p, s} = square
c.save()
c.translate(x + sin(frame / 100 + p) * canvas.width / 2, y + cos(frame / 100 + p) * canvas.height / 2)
c.rotate(frame / 180 * PI + p)
c.fillStyle = "#111"
c.fillRect(-s / 2, - s / 2, s, s)
c.restore()
})
}
let clear = () => {
c.fillStyle = "#000"
c.fillRect(0, 0, canvas.width, canvas.height)
}
let render = () => {
let percentFrame = frame % 100 / 100
frame++
clear()
c.drawImage(image, 0, 0, image.width, image.height)
mask.save()
mask.translate(canvas.width / 2, canvas.height / 2)
mask.scale(1.2 + sin(frame / 100) * 0.1, 1.2 + sin(frame / 100) * 0.1)
mask.drawImage(canvas, -canvas.width / 2, -canvas.height / 2)
mask.restore()
mask.globalCompositeOperation = "multiply"
mask.fillStyle = mask.createRadialGradient(canvas.width / 2, canvas.height / 2, 32 + sin(frame / 30) * 16, canvas.width / 2, canvas.height / 2, canvas.width / 1.5)
mask.fillStyle.addColorStop(0, "#000")
mask.fillStyle.addColorStop(0.8 + cos(frame / 30) * 0.1, "#000")
mask.fillStyle.addColorStop(0.6 + cos(frame / 40) * 0.05, "#fff")
mask.fillStyle.addColorStop(0.4 + cos(frame / 50) * 0.1, "#000")
mask.fillStyle.addColorStop(0.2 + cos(frame / 60) * 0.05, "#fff")
mask.fillStyle.addColorStop(0, "#000")
mask.fillRect(0, 0, canvas.width, canvas.height)
mask.globalCompositeOperation = "source-over"
c.globalCompositeOperation = "difference"
c.drawImage(mask.canvas, 0, 0)
c.globalCompositeOperation = "color-dodge"
c.drawImage(mask.canvas, 0, 0)
c.globalCompositeOperation = "source-over"
mask.drawImage(canvas, 0, 0)
mask.globalCompositeOperation = "screen"
mask.filter = "blur(3px)"
mask.drawImage(canvas, 0, 0)
mask.filter = "blur(0px)"
mask.globalCompositeOperation = "source-over"
c.drawImage(mask.canvas, 0, 0)
requestAnimationFrame(render)
}
canvas.width = mask.canvas.width = 500
canvas.height = mask.canvas.height = 500
image.src = "https://res.cloudinary.com/dlb3jof8w/image/upload/v1554933000/photo-1552332271-fcd3c889767e.jpg"
render()
</script>