Skip to content

Instantly share code, notes, and snippets.

Created July 12, 2017 08:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/a6f66ce7d791f0b520f6a59d89757d5c to your computer and use it in GitHub Desktop.
Save anonymous/a6f66ce7d791f0b520f6a59d89757d5c to your computer and use it in GitHub Desktop.
Paint on Heat Distortion
<main>
<canvas data-img=""></canvas>
<div class="mask">
<div class="mask-inner">
</div>
</div>
</main>
<a class="button">Clear</a>
<span class="button">
<input type="file" id="upload">
</span>
<svg xlmns="http://www.w3.org/2000/svg" version="1.1">
<filter id="heat" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
<feTurbulence id="heatturb" type="fractalNoise" numOctaves="1" seed="2"></feTurbulence>
<feDisplacementMap xChannelSelector="G" yChannelSelector="B" scale="22" in="SourceGraphic"></feDisplacementMap>
</filter>
</svg>

Paint on Heat Distortion

This pen is very experimental and probably will not work in any browser except recent versions of Chrome.

Paint on a heat distortion effect. Uses GSAP to animate SVG, canvas for the paint tool, and CSS Masks to marry them.

A Pen by Matt Popovich on CodePen.

License.

var canvas = $('canvas')[0];
var ctx = canvas.getContext('2d');
var sketch = $('main')[0];
var sketch_style = getComputedStyle(sketch);
canvas.width = parseInt(sketch_style.getPropertyValue('width'));
canvas.height = parseInt(sketch_style.getPropertyValue('height'));
var mouse = { x: 0, y: 0 };
canvas.addEventListener('mousemove', function(e) {
var c = $('canvas');
mouse.x = e.pageX - c.offset().left;
mouse.y = e.pageY - c.offset().top;
}, false);
ctx.lineWidth = 40;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = 'black';
canvas.addEventListener('mousedown', function(e) {
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);
canvas.addEventListener('mousemove', onPaint, false);
}, false);
canvas.addEventListener('mouseup', function() {
canvas.removeEventListener('mousemove', onPaint, false);
}, false);
var onPaint = function() {
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
var url = canvas.toDataURL();
$('div').css({ display: 'initial', 'mask-image': 'url('+url+')' });
};
var timeline = new TimelineMax({ repeat: -1, yoyo: true }),
feTurb = document.querySelector('#heatturb');
timeline.add(
new TweenMax.to(feTurb, 8, {
onUpdate: function() {
var bfX = this.progress() * 0.01 + 0.025,
bfY = this.progress() * 0.003 + 0.01,
bfStr = bfX.toString() + ' ' + bfY.toString();
feTurb.setAttribute('baseFrequency', bfStr);
}
}), 0
);
function clear () {
$('div').css({ display: 'none', 'mask-image': 'none' });
}
$('.button').click(function(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
clear();
});
document.getElementById('upload').onchange = function(e) {
var imageFile = this.files[0];
var newImg = window.URL.createObjectURL(imageFile);
// var newImg = $("input").value;
console.log(newImg);
clear();
$('main').css({
'background': 'url("'+newImg+'")',
'background-size': 'cover',
'background-position': 'center'
});
$('.mask-inner').css({
'background': 'url("'+newImg+'")',
'background-size': 'cover',
'background-position': 'center'
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
* {
box-sizing: border-box;
margin: 0; padding: 0;
}
body, html {
height: 100%;
overflow-x: hidden;
}
body {
padding: 30px 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(to bottom, rgba(15,0,0,1) 0%,rgba(35,5,5,1) 60%, rgba(195,15,5,1) 92%, rgba(255,65,5,1) 100%);
}
main {
cursor: grab;
width: 700px;
height: 450px;
flex-shrink: 0;
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/436243/87e79ed19a288cc9b004234db8853204.jpg);
background-size: cover;
background-position: 100% 50%;
position: relative;
border: 2px solid rgba(195,15,5,.3);
}
canvas {
opacity: 0;
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
}
.mask {
display: none;
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
pointer-events: none;
mask-mode: luminance;
mask-size: 100% 100%;
backdrop-filter: hard-light;
}
.mask-inner {
position: absolute;
top: 0; left: 0;
width: 100%;
height: 100%;
background: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/436243/87e79ed19a288cc9b004234db8853204.jpg') 0% 0% repeat;
background-size: cover;
background-position: 100% 50%;
filter: url(#heat);
}
.button {
position: relative;
-webkit-font-smoothing: antialiased;
background-color: rgba(15,0,0,1);
border: none;
color: #fff;
display: inline-block;
text-align: center;
font-size: 14px;
font-weight: 100;
text-decoration: none;
user-select: none;
letter-spacing: 2px;
color: white;
margin: 15px 10px 0;
padding: 8px 0;
width: 280px;
text-transform: uppercase;
transition: all 0.1s ease-out;
cursor: pointer;
&:hover {
background-color: rgba(125,15,5,1);
outline: 1px solid rgba(255,255,255,.3);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment