-
Notifications
You must be signed in to change notification settings - Fork 0
/
cacophony-of-pixels.js
142 lines (117 loc) · 5.54 KB
/
cacophony-of-pixels.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// the screensaver glue: making sure we quit when needed
var ipc = require('ipc');
var sendQuit = function(){
ipc.send('sendQuit');
}
document.addEventListener('keydown', sendQuit);
document.addEventListener('mousedown', sendQuit);
// Also quit on mouse movement, but delay mousemove tracking, otherwise we'll close immediately
setTimeout( function() {
var treshold = 5;
document.addEventListener('mousemove', function(e) {
if (treshold * treshold < e.movementX * e.movementX
+ e.movementY * e.movementY) {
sendQuit();
}
});
}, 3000);
// The actual screensaver
document.addEventListener("DOMContentLoaded", function () {
document.removeEventListener("DOMContentLoaded", arguments.callee, false);
// canvas setup
var can = document.getElementById("screen");
can.width = window.screen.width;
can.height = window.screen.height;
var ctx = can.getContext("2d");
ctx.fillStyle = "black";
ctx.fillRect(0, 0, can.width, can.height);
// stores for animatable values + a function to generate them
var startValues = {};
var endValues = {};
var generateValues = function(valueStore) {
valueStore.spotlightRadius = (screen.height / 8) + Math.random() * (screen.height / 4);
valueStore.spotlightX = Math.random() * screen.width;
valueStore.spotlightY = Math.random() * screen.height;
valueStore.randomness = Math.random() * 0.7;
valueStore.redConstant = Math.random();
valueStore.redConstantRate = Math.random();
valueStore.greenConstant = Math.random();
valueStore.greenConstantRate = Math.random();
valueStore.blueConstant = Math.random();
valueStore.blueConstantRate = Math.random();
}
generateValues(endValues); //we'll get the first startValues from here... it's hacky, but hey: less flags!
// animation-related global variables (yummy globals!)
var currentAnimationState = 0;
var currentAnimationLengthMs = -1;
var pastAnimationsMs = 0;
// constans and silly utility methods
var pixelSize = 10;
var lerp = function (a, b, f) {
return a * (1 - f) + b * f;
}
var easeIn = function(f) {
return Math.pow(f, 2);
}
var easeInOut = function(f) {
return (f <= 0.5) ? easeIn(f * 2) / 2 : ((1 - easeIn((1 - f) * 2)) / 2 + 0.5);
}
var getAnimatedValue = function (propertyName) {
var f = easeInOut(currentAnimationState);
// gotta love JavaScript objects
return lerp(startValues[propertyName], endValues[propertyName], f);
}
var getLightAmount = function(distFactor, constant, constantRate) {
return distFactor * (1 - constantRate) + constant * constantRate;
}
var getBaseNoise = function () {
return (Math.random() * 255 * getAnimatedValue("randomness")) + 255 * (1 - getAnimatedValue("randomness"));
}
var simpleCopy = function (from, to) {
//Thanks, http://stackoverflow.com/questions/9362716/how-to-duplicate-object-properties-in-another-object
for(var k in from) to[k] = from[k];
}
var redAmountFun = function (d) { return getLightAmount(d, getAnimatedValue("redConstant"), getAnimatedValue("redConstantRate")); };
var greenAmountFun = function (d) { return getLightAmount(d, getAnimatedValue("greenConstant"), getAnimatedValue("greenConstantRate")); };
var blueAmountFun = function (d) { return getLightAmount(d, getAnimatedValue("blueConstant"), getAnimatedValue("blueConstantRate")); };
// "planning" the next animation
var setupAnimation = function() {
simpleCopy(endValues, startValues);
generateValues(endValues);
currentAnimationLengthMs = 1000 + Math.random() * 3000;
}
// the "renderer"... get ready to hear your fans crying
var start = null;
var render = function (timestampMs) {
if (!start) start = timestampMs;
var elapsedMs = timestampMs - start;
var animationElapsedMs = elapsedMs - pastAnimationsMs;
if (animationElapsedMs >= currentAnimationLengthMs) {
pastAnimationsMs += currentAnimationLengthMs;
setupAnimation();
animationElapsedMs = 0;
}
currentAnimationState = animationElapsedMs / currentAnimationLengthMs;
for (var i = 0; i < can.width; i += pixelSize)
for (var j = 0; j < can.height; j += pixelSize) {
var dist = Math.sqrt((getAnimatedValue("spotlightX") - i) * (getAnimatedValue("spotlightX") - i)
+ (getAnimatedValue("spotlightY") - j) * (getAnimatedValue("spotlightY") - j))
var distFactor = Math.max(getAnimatedValue("spotlightRadius") - dist, 0) / dist;
var redAmount = redAmountFun(distFactor);
var greenAmount = greenAmountFun(distFactor);
var blueAmount = blueAmountFun(distFactor);
var color = "rgb(" + Math.floor(getBaseNoise() * redAmount)
+ ", "
+ Math.floor(getBaseNoise() * greenAmount)
+ ", "
+ Math.floor(getBaseNoise() * blueAmount) + ")";
ctx.fillStyle = color;
ctx.fillRect(i, j, pixelSize, pixelSize);
}
}
var animate = function(timestamp) {
requestAnimationFrame(animate);
render(timestamp);
}
requestAnimationFrame(animate);
});