Toggle navigation
Sign Up
Log In
Explore
Works
Folders
Tools
Collections
Artists
Groups
Groups
Topics
Tasks
Tasks
Jobs
Teams
Jobs
Recommendation
More Effects...
JS
var RENDERER = { TREE_COUNT : 7, LIGHT_COUNT : 200, INTERVAL_Z : 400, FOCUS : 100, TREE_LUMINANCE : {min : 3, max : 15}, TREE_CHANGE_COUNT : 10, TREE_CHANGE_DELTA : 0.5, DELTA_THETA : Math.PI / 100, init : function(){ this.setParameters(); this.reconstructMethod(); this.createElements(); this.render(); }, setParameters : function(){ this.$container = $('#jsi-forest-container'); this.width = this.$container.width(); this.height = this.$container.height(); this.context = $('
').attr({width : this.width, height : this.height}).appendTo(this.$container).get(0).getContext('2d'); this.backgroundDark = this.context.createLinearGradient(0, 0, 0, this.height); this.backgroundDark.addColorStop(0, 'hsl(220, 80%, 40%)'); this.backgroundDark.addColorStop(0.3, 'hsl(220, 80%, 10%)'); this.backgroundDark.addColorStop(0.4, 'hsl(220, 80%, 3%)'); this.backgroundDark.addColorStop(0.6, 'hsl(120, 30%, 3%)'); this.backgroundDark.addColorStop(1, 'hsl(120, 30%, 10%)'); this.backgroundLight = this.context.createLinearGradient(0, 0, 0, this.height); this.backgroundLight.addColorStop(0, 'hsl(220, 80%, 60%)'); this.backgroundLight.addColorStop(0.4, 'hsl(220, 80%, 60%)'); this.backgroundLight.addColorStop(0.6, 'hsl(120, 50%, 60%)'); this.backgroundLight.addColorStop(1, 'hsl(120, 50%, 60%)'); this.theta = 0; this.trees = []; this.lights = []; this.treeIndex = 0; this.orderAsc = true; this.distance = Math.sqrt(Math.pow(this.width / 2, 2) + Math.pow(this.height / 2, 2)); this.maxLuminaceCount = (this.TREE_LUMINANCE.max - this.TREE_LUMINANCE.min) * this.TREE_CHANGE_COUNT / this.TREE_CHANGE_DELTA; }, reconstructMethod : function(){ this.render = this.render.bind(this); }, createElements : function(){ var treeLight = TREE_CREATOR.create(this.TREE_LUMINANCE.max), treeDarks = [], centerX = this.width / 2, centerY = this.height / 2, x = this.width * 1.6, y = this.height * 1.6, maxZ = this.INTERVAL_Z * this.TREE_COUNT; for(var i = this.TREE_LUMINANCE.min, max = this.TREE_LUMINANCE.max; i <= max; i += this.TREE_CHANGE_DELTA){ treeDarks.push(TREE_CREATOR.create(i)); } for(var i = 0, length = this.TREE_COUNT; i < length; i++){ var z = this.INTERVAL_Z * (length - i); this.trees.push(new TREE(treeLight, treeDarks, centerX, centerY, x, y, z, maxZ, this.FOCUS)); this.trees.push(new TREE(treeLight, treeDarks, centerX, centerY, -x, y, z, maxZ, this.FOCUS)); if(i > this.TREE_COUNT / 2){ this.trees.push(new TREE(treeLight, treeDarks, centerX, centerY, x * 2, y, z + this.INTERVAL_Z / 2, maxZ / 2, this.FOCUS)); this.trees.push(new TREE(treeLight, treeDarks, centerX, centerY, -x * 2, y, z + this.INTERVAL_Z / 2, maxZ / 2, this.FOCUS)); } } for(var i = 0, length = this.LIGHT_COUNT; i < length; i++){ this.lights.push(new LIGHT(this.width, this.height, centerX, centerY, maxZ, this.FOCUS)); } this.shadow = SHADOW.init(this.width, this.height); }, render : function(){ requestAnimationFrame(this.render); this.context.fillStyle = this.backgroundDark; this.context.fillRect(0, 0, this.width, this.height); for(var i = 0, length = this.trees.length, index = this.treeIndex / this.TREE_CHANGE_COUNT | 0; i < length; i++){ this.trees[i].render(this.context, false, index); } this.shadow.render(this.context); this.context.save(); this.context.beginPath(); for(var i = 0, length = this.lights.length; i < length; i++){ this.lights[i].render(this.context); } this.context.clip(); this.context.fillStyle = this.backgroundLight; this.context.fillRect(0, 0, this.width, this.height); for(var i = 0, length = this.trees.length; i < length; i++){ this.trees[i].render(this.context, true); } this.shadow.render(this.context); this.context.globalCompositeOperation = 'lighter'; var backgroundCover = this.context.createRadialGradient(this.width / 2, this.height / 2, 0, this.width / 2, this.height / 2, this.distance), hue = 180 + 90 * Math.sin(this.theta); backgroundCover.addColorStop(0, 'hsl(' + hue + ', 80%, 10%)'); backgroundCover.addColorStop(1, 'hsl(' + hue + ', 80%, 40%)'); this.context.fillStyle = backgroundCover; this.context.fillRect(0, 0, this.width, this.height); this.context.restore(); this.changeTreeIndex(); this.theta += this.DELTA_THETA; this.hue %= Math.PI * 2; }, changeTreeIndex : function(){ if(this.orderAsc){ if(++this.treeIndex == this.maxLuminaceCount){ this.treeIndex--; this.orderAsc = false; } }else{ if(--this.treeIndex == 0){ this.treeIndex++; this.orderAsc = true; } } } }; var TREE_CREATOR = { WIDTH : 120, HEIGHT : 200, TRUNK_RATE : 0.8, BRANCH_RADIAN : Math.PI / 6, BRANCH_RATE : 0.55, BRANCH_LEVEL : 8, COLOR : 'hsl(120, 80%, %luminance%)', create : function(luminance){ this.setParameters(luminance); this.drawTree(this.WIDTH / 2, this.HEIGHT, Math.PI / 2, this.HEIGHT / 4, 3, 0); return {canvas : this.canvas, x : -this.WIDTH / 2, y : -this.HEIGHT}; }, setParameters : function(luminance){ this.canvas = $('
').attr({width : this.WIDTH, height : this.HEIGHT}).get(0); this.context = this.canvas.getContext('2d'); this.context.strokeStyle = this.COLOR.replace('%luminance', luminance); }, drawTree : function(x, y, radian, length, width, level){ if (level > this.BRANCH_LEVEL) { return; } var sin = length * Math.sin(radian), cos = length * Math.cos(radian); this.drawTree(x + cos * this.TRUNK_RATE, y - sin * this.TRUNK_RATE, radian, length * this.TRUNK_RATE, width * this.TRUNK_RATE, level + 1); for(var i = -1; i <= 1; i += 2){ this.drawTree(x + cos * this.BRANCH_RATE, y - sin * this.BRANCH_RATE, radian + this.BRANCH_RADIAN * i, length * this.BRANCH_RATE, width * this.BRANCH_RATE, level + 1); } this.context.lineWidth = width; this.context.beginPath(); this.context.moveTo(x, y); this.context.lineTo(x + length*Math.cos(radian), y - length*Math.sin(radian)); this.context.stroke(); } }; var TREE = function(treeLight, treeDarks, centerX, centerY, x, y, z, maxZ, focus){ this.treeLight = treeLight; this.treeDarks = treeDarks; this.centerX = centerX; this.centerY = centerY; this.x = x; this.y = y; this.z = z; this.maxZ = maxZ; this.focus = focus; }; TREE.prototype = { MAGNIFICATION : 10, render : function(context, isLight, index){ var tree = isLight ? this.treeLight : this.treeDarks[index], rate = this.focus / (this.focus + this.z), x = this.centerX + this.x * rate, y = this.centerY + this.y * rate; rate *= this.MAGNIFICATION; context.save(); context.translate(x, y); context.scale(rate, rate); context.drawImage(tree.canvas, tree.x, tree.y); context.restore(); if(--this.z < 0){ this.z = this.maxZ; } } }; var LIGHT = function(width, height, centerX, centerY, maxZ, focus){ this.width = width; this.height = height; this.centerX = centerX; this.centerY = centerY; this.maxZ = maxZ; this.focus = focus; this.init(); }; LIGHT.prototype = { VELOCITY_RANGE : {min : -3, max : 3}, MAX_RADIUS : 12, init : function(){ this.x = this.getRandomValue({min : -this.width * 2, max : this.width * 2}); this.y = this.getRandomValue({min : -this.height, max : this.height}); this.z = this.getRandomValue({min : 0, max : this.maxZ}); this.vx = this.getRandomValue(this.VELOCITY_RANGE); this.vy = this.getRandomValue(this.VELOCITY_RANGE); this.rate = 1; }, getRandomValue : function(range){ return range.min + (range.max - range.min) * Math.random(); }, render : function(context){ var rate = this.focus / (this.focus + this.z), x = this.centerX + this.x * rate, y = this.centerY - this.y * rate; context.moveTo(x, y); context.arc(x, y, this.MAX_RADIUS * rate * this.rate, 0, Math.PI * 2, false); if(--this.z < -this.focus || x < 0 || x > this.width || y < 0 || y > this.height){ this.init(); this.rate = 0; } this.x += this.vx * rate; this.y += this.vy * rate; if(this.rate >= 1){ return; } this.rate += 0.01; } }; var SHADOW = { SHAKE_INTERVAL : Math.PI / 120, COLOR : 'rgba(0, 0, 0, 0.3)', init : function(width, height){ this.width = width; this.height = height; this.theta = 0; return this; }, render : function(context){ context.save(); context.fillStyle = this.COLOR; context.translate(this.width / 2, this.height); context.scale(0.6, 1.2); context.rotate(Math.PI / 60 * Math.sin(this.theta)); context.beginPath(); context.arc(0, -108, 8, 0, Math.PI * 2, false); context.fill(); context.beginPath(); context.moveTo(5, -100); context.bezierCurveTo(40, -100, 40, -70, 30, -40); context.lineTo(25, -40); context.lineTo(25, 5); context.lineTo(5, 5); context.lineTo(5, -40); context.lineTo(-5, -40); context.lineTo(-5, 5); context.lineTo(-25, 5); context.lineTo(-25, -40); context.lineTo(-30, -40); context.bezierCurveTo(-40, -70, -40, -100, -5, -100); context.fill(); context.restore(); this.theta += this.SHAKE_INTERVAL; this.theta %= Math.PI * 2; } }; $(function(){ RENDERER.init(); });
CSS
html, body{ width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; background-color: #101010; } .container{ position: absolute; width: 500px; height: 500px; top: 50%; left: 50%; margin-top: -250px; margin-left: -250px; }
HTML
Join Effecthub.com
Working with Global Gaming Artists and Developers!
Login
Sign Up
Or Login with Your Email Address:
Email
Password
Remember
Or Sign Up with Your Email Address:
Your Email
This field must contain a valid email
Set Password
Password should be at least 1 character
Stay informed via email