<svg class="flameSVG" viewBox="0 0 800 600" xmlns="http://www.w3.org/2000/svg">
<defs>
<rect class="flame" x="400" y="310" width="5" height="5" rx="0.5" ry="0.5" fill="#FFDD02"/>
<circle class="spark" cx="400" cy="300" r="0.05" fill="#FFDD02"/>
<filter id="shadow" x="-100%" y="-100%" width="250%" height="250%">
<feOffset in="SourceAlpha" dx="4" dy="4" result="offsetOut"></feOffset>
<feGaussianBlur stdDeviation="3" in="offsetOut" result="drop" />
<feOffset dx="0" dy="0" result="offsetblur"></feOffset>
<feFlood id="glowAlpha" flood-color="#000" flood-opacity="0.2"></feFlood>
<feComposite in2="offsetblur" operator="in"></feComposite>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g class="whole">
<g class="flameContainer" />
<g class="sparksContainer" />
<g class="logs" opacity="1">
<path d="M446.68,299.63l-91.46,29.22a3,3,0,0,1-3.68-2.12L349.2,318a3,3,0,0,1,2.12-3.68l91.46-29.22a3,3,0,0,1,3.68,2.12L448.8,296A3,3,0,0,1,446.68,299.63Z" fill="#612e25"/>
<path filter="url(#shadow)" d="M349.2,296l2.34-8.69a3,3,0,0,1,3.68-2.12l91.46,29.22A3,3,0,0,1,448.8,318l-2.34,8.69a3,3,0,0,1-3.68,2.12l-91.46-29.22A3,3,0,0,1,349.2,296Z" fill="#70392f"/>
</g>
</g>
<rect class="hit" width="200" height="260" x="300" y="230" fill="transparent"></rect>
</svg>
body {
background-color: #0F1217;
overflow: hidden;
text-align: center;
}
body, html {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
svg {
width: 100%;
height: 100%;
visibility: hidden;
}
.hit {
cursor: pointer;
}
var xmlns = "http://www.w3.org/2000/svg",
xlinkns = "http://www.w3.org/1999/xlink",
select = function(s) {
return document.querySelector(s);
},
selectAll = function(s) {
return document.querySelectorAll(s);
},
flameContainer = select('.flameContainer'),
sparksContainer = select('.sparksContainer'),
flameSVG = select('.flameSVG'),
flamePosXArr = [10, -10],
flameOffset = 0.34,
sparkOffset = 0.72,
numFlames = 50
CustomEase.create("return", "M0,0 C0,0 0.162,1 0.4,1 0.918,1 1,0 1,0");
CustomEase.create("sparkFlicker", "M0,0 C0.126,0.382 0.216,0.572 0.414,0.482 0.821,0.296 0.984,0.94 1,1");
CustomEase.create("flameJump", "M0,0 C0.126,0.382 0.256,0.248 0.406,0.23 0.85,0.176 0.984,0.94 1,1");
TweenMax.set('svg', {
visibility: 'visible'
})
TweenMax.set('.whole', {
scale:1.52,
transformOrigin:'50% -500%'
})
var mainTl = new TimelineMax({});
var flameTl = new TimelineMax({repeat:0});
function createFlames(){
for(var i = 0; i < numFlames; i++){
var f = select('.flame').cloneNode(true);
flameContainer.appendChild(f);
TweenMax.set(f, {
x:(i%2) ? flamePosXArr[0] : flamePosXArr[1],
transformOrigin:'50% 50%',
rotation:-45
})
var fTl = new TimelineMax({repeat:-1, repeatDelay:((numFlames-1) * flameOffset)-2});
fTl.to(f, 2, {
x:(i%2)? '-=22' : '+=22',
scale:10,
ease:'return'
})
.to(f, 2, {
y:-145,
ease:'flameJump'
},'-=2')
.to(f, 2, {
fill:'#F73B01',
ease:Sine.easeOut
},'-=2')
.to(f, 2, {
alpha:0,
ease:Expo.easeIn
},'-=2')
flameTl.add(fTl, i*flameOffset);
var s = select('.spark').cloneNode(true);
sparksContainer.appendChild(s);
TweenMax.set(s, {
x:(i%3) ? flamePosXArr[1] : flamePosXArr[0],
transformOrigin:'50% 50%'
})
}
}
createFlames();
var sparkTl = new TimelineMax({repeat:-1});
sparkTl.staggerTo('.spark', 2, {
cycle:{
x:['-=25', '+=15', 0, '+=23', '-=5', '+=71', '-=54'],
scale:function(){
return Math.random() * 23
}
},
ease:'return'
},sparkOffset)
.staggerTo('.spark', 3, {
cycle:{
ease:[SlowMo.ease.config(0.2,0.2),'sparkFlicker',SlowMo.ease.config(0.42,0.52) ],
y:function(){
return -(Math.random() * 200)-200
}
}
},sparkOffset,'-='+sparkTl.duration())
.staggerTo('.spark', 3, {
cycle:{
fill:['#F36B01', '#FDBB01', '#ededed']
},
ease:Sine.easeIn
},sparkOffset,'-='+sparkTl.duration())
.staggerTo('.spark', 3, {
alpha:0,
ease:Expo.easeIn
},sparkOffset,'-='+sparkTl.duration())
sparkTl.timeScale(1)
mainTl.add(flameTl, 0);
mainTl.add(sparkTl, 0);
mainTl.timeScale(1.2).seek(97);
function pokeFire(){
resetSparks();
var pokeTl = new TimelineMax({onComplete:function(){
resetSparks();
sparkTl.play(99)
}}).timeScale(2)
pokeTl.staggerTo('.logs path', 0.7, {
cycle:{
rotation:[3, -3],
transformOrigin:['2% 100%', '98% 100%']
},
ease:'return'
},0.02)
.to(flameContainer, 0.7, {
scaleY:0.8,
transformOrigin:'50% 100%',
ease:'return'
},'-=' + pokeTl.duration())
.staggerTo('.spark', 3, {
cycle:{
x:['-=25', '+=15', 0, '+=23', '-=5', '+=71', '-=54'],
scale:function(){
return (Math.random() * 30)
}
},
ease:'return'
},0.07,'-=1.2')
.staggerTo('.spark', 3, {
cycle:{
ease:[SlowMo.ease.config(0.2,0.2),'sparkFlicker',SlowMo.ease.config(0.42,0.52) ],
y:function(){
return -(Math.random() * 200)-200
}
}
},0.07,'-='+pokeTl.duration())
.staggerTo('.spark', 3, {
cycle:{
fill:['#F36B01', '#FDBB01']
},
ease:Sine.easeIn
},0.07,'-='+pokeTl.duration())
.staggerTo('.spark', 3, {
alpha:0,
ease:Expo.easeIn
},0.07,'-='+pokeTl.duration())
}
function resetSparks(){
TweenMax.staggerTo('.spark', 0, {
cycle:{
x:function(i){
return (i%3) ? flamePosXArr[1] : flamePosXArr[0]
}
},
y:0,
alpha:1,
scale:1
},0)
}
flameSVG.onclick = pokeFire;
This Pen doesn't use any external CSS resources.