jekyll-theme-satellite 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/_config.yml +82 -0
  4. data/_includes/loading.html +6 -0
  5. data/_includes/navigation.html +84 -0
  6. data/_includes/pagination.html +71 -0
  7. data/_includes/post.html +65 -0
  8. data/_includes/search.html +21 -0
  9. data/_includes/sidebar.html +83 -0
  10. data/_layouts/default.html +113 -0
  11. data/_sass/darkmode.scss +211 -0
  12. data/_sass/layout.scss +57 -0
  13. data/_sass/navigation.scss +178 -0
  14. data/_sass/pagination.scss +253 -0
  15. data/_sass/post.scss +640 -0
  16. data/_sass/search.scss +248 -0
  17. data/_sass/sidebar.scss +309 -0
  18. data/_sass/toc.scss +52 -0
  19. data/_sass/vars.scss +15 -0
  20. data/assets/css/highlight-dark.min.css +1 -0
  21. data/assets/css/highlight-default.min.css +1 -0
  22. data/assets/css/style.scss +89 -0
  23. data/assets/fonts/Lato-Regular.ttf +0 -0
  24. data/assets/fonts/NunitoSans-Regular.ttf +0 -0
  25. data/assets/fonts/Righteous-Regular.ttf +0 -0
  26. data/assets/img/La-Mancha.jpg +0 -0
  27. data/assets/img/example.jpg +0 -0
  28. data/assets/img/favicon.webp +0 -0
  29. data/assets/img/icon/book-solid.svg +1 -0
  30. data/assets/img/icon/calendar-days-regular.svg +1 -0
  31. data/assets/img/icon/clipboard-regular.svg +1 -0
  32. data/assets/img/icon/folder-open-regular.svg +1 -0
  33. data/assets/img/icon/tags-solid.svg +1 -0
  34. data/assets/img/loading.webp +0 -0
  35. data/assets/img/profile.jpg +0 -0
  36. data/assets/img/sorry.png +0 -0
  37. data/assets/img/thumbnail/book.jpg +0 -0
  38. data/assets/img/thumbnail/bricks.webp +0 -0
  39. data/assets/img/thumbnail/empty.jpg +0 -0
  40. data/assets/img/thumbnail/nightgardenflower.jpg +0 -0
  41. data/assets/img/thumbnail/sample.png +0 -0
  42. data/assets/img/tile.png +0 -0
  43. data/assets/js/404.js +22 -0
  44. data/assets/js/highlight.min.js +1213 -0
  45. data/assets/js/main.js +709 -0
  46. data/assets/js/stars.js +700 -0
  47. data/assets/js/sweet-scroll.min.js +2 -0
  48. data/assets/js/tocbot.min.js +1 -0
  49. metadata +104 -0
@@ -0,0 +1,700 @@
1
+ /**
2
+ * Stars
3
+ * Inspired by Steve Courtney's poster art for Celsius GS's Drifter - http://celsiusgs.com/drifter/posters.php
4
+ * by Cory Hughart - http://coryhughart.com
5
+ */
6
+
7
+ // Settings
8
+ var particleCount = 40,
9
+ flareCount = 16,
10
+ motion = 0.05,
11
+ tilt = 0.05,
12
+ color = '#44b5fd',
13
+ colorPalette = ["#c13c3c", "#c13cc1", "#3c3cc1", "#3cc1c1", "#3cc13c", "#c1c13c"],
14
+ particleSizeBase = 2,
15
+ particleSizeMultiplier = 0.5,
16
+ flareSizeBase = 100,
17
+ flareSizeMultiplier = 100,
18
+ lineWidth = 1,
19
+ linkChance = 75, // chance per frame of link, higher = smaller chance
20
+ linkLengthMin = 5, // min linked vertices
21
+ linkLengthMax = 7, // max linked vertices
22
+ linkOpacity = 0.375; // number between 0 & 1
23
+ linkFade = 90, // link fade-out frames
24
+ linkSpeed = 1, // distance a link travels in 1 frame
25
+ glareAngle = -60,
26
+ glareOpacityMultiplier = 0.05,
27
+ renderParticles = true,
28
+ renderParticleGlare = true,
29
+ renderFlares = true,
30
+ renderLinks = true,
31
+ renderMesh = false,
32
+ flicker = true,
33
+ flickerSmoothing = 15, // higher = smoother flicker
34
+ blurSize = 0,
35
+ orbitTilt = true,
36
+ randomMotion = true,
37
+ noiseLength = 1000,
38
+ noiseStrength = 1;
39
+
40
+ var canvas = document.getElementById('stars'),
41
+ context = canvas.getContext('2d'),
42
+ mouse = { x: 0, y: 0 },
43
+ m = {},
44
+ r = 0,
45
+ c = 1000, // multiplier for delaunay points, since floats too small can mess up the algorithm
46
+ n = 0,
47
+ nAngle = (Math.PI * 2) / noiseLength,
48
+ nRad = 100,
49
+ nScale = 0.5,
50
+ nPos = {x: 0, y: 0},
51
+ points = [],
52
+ vertices = [],
53
+ triangles = [],
54
+ links = [],
55
+ particles = [],
56
+ flares = [];
57
+
58
+ // Delaunay Triangulation
59
+ var EPSILON = 1.0 / 1048576.0;
60
+
61
+ function randomColor(colors){
62
+ return colors[Math.floor(Math.random() * colors.length)];
63
+ }
64
+
65
+ function supertriangle(vertices) {
66
+ var xmin = Number.POSITIVE_INFINITY,
67
+ ymin = Number.POSITIVE_INFINITY,
68
+ xmax = Number.NEGATIVE_INFINITY,
69
+ ymax = Number.NEGATIVE_INFINITY,
70
+ i, dx, dy, dmax, xmid, ymid;
71
+
72
+ for(i = vertices.length; i--; ) {
73
+ if(vertices[i][0] < xmin) xmin = vertices[i][0];
74
+ if(vertices[i][0] > xmax) xmax = vertices[i][0];
75
+ if(vertices[i][1] < ymin) ymin = vertices[i][1];
76
+ if(vertices[i][1] > ymax) ymax = vertices[i][1];
77
+ }
78
+
79
+ dx = xmax - xmin;
80
+ dy = ymax - ymin;
81
+ dmax = Math.max(dx, dy);
82
+ xmid = xmin + dx * 0.5;
83
+ ymid = ymin + dy * 0.5;
84
+
85
+ return [
86
+ [xmid - 20 * dmax, ymid - dmax],
87
+ [xmid , ymid + 20 * dmax],
88
+ [xmid + 20 * dmax, ymid - dmax]
89
+ ];
90
+ }
91
+
92
+ function circumcircle(vertices, i, j, k) {
93
+ var x1 = vertices[i][0],
94
+ y1 = vertices[i][1],
95
+ x2 = vertices[j][0],
96
+ y2 = vertices[j][1],
97
+ x3 = vertices[k][0],
98
+ y3 = vertices[k][1],
99
+ fabsy1y2 = Math.abs(y1 - y2),
100
+ fabsy2y3 = Math.abs(y2 - y3),
101
+ xc, yc, m1, m2, mx1, mx2, my1, my2, dx, dy;
102
+
103
+ /* Check for coincident points */
104
+ if(fabsy1y2 < EPSILON && fabsy2y3 < EPSILON)
105
+ throw new Error("Eek! Coincident points!");
106
+
107
+ if(fabsy1y2 < EPSILON) {
108
+ m2 = -((x3 - x2) / (y3 - y2));
109
+ mx2 = (x2 + x3) / 2.0;
110
+ my2 = (y2 + y3) / 2.0;
111
+ xc = (x2 + x1) / 2.0;
112
+ yc = m2 * (xc - mx2) + my2;
113
+ }
114
+ else if(fabsy2y3 < EPSILON) {
115
+ m1 = -((x2 - x1) / (y2 - y1));
116
+ mx1 = (x1 + x2) / 2.0;
117
+ my1 = (y1 + y2) / 2.0;
118
+ xc = (x3 + x2) / 2.0;
119
+ yc = m1 * (xc - mx1) + my1;
120
+ }
121
+ else {
122
+ m1 = -((x2 - x1) / (y2 - y1));
123
+ m2 = -((x3 - x2) / (y3 - y2));
124
+ mx1 = (x1 + x2) / 2.0;
125
+ mx2 = (x2 + x3) / 2.0;
126
+ my1 = (y1 + y2) / 2.0;
127
+ my2 = (y2 + y3) / 2.0;
128
+ xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
129
+ yc = (fabsy1y2 > fabsy2y3) ?
130
+ m1 * (xc - mx1) + my1 :
131
+ m2 * (xc - mx2) + my2;
132
+ }
133
+
134
+ dx = x2 - xc;
135
+ dy = y2 - yc;
136
+ return {i: i, j: j, k: k, x: xc, y: yc, r: dx * dx + dy * dy};
137
+ }
138
+
139
+ function dedup(edges) {
140
+ var i, j, a, b, m, n;
141
+
142
+ for(j = edges.length; j; ) {
143
+ b = edges[--j];
144
+ a = edges[--j];
145
+
146
+ for(i = j; i; ) {
147
+ n = edges[--i];
148
+ m = edges[--i];
149
+
150
+ if((a === m && b === n) || (a === n && b === m)) {
151
+ edges.splice(j, 2);
152
+ edges.splice(i, 2);
153
+ break;
154
+ }
155
+ }
156
+ }
157
+ }
158
+
159
+ function Delaunay(vertices, key) {
160
+ var n = vertices.length,
161
+ i, j, indices, st, open, closed, edges, dx, dy, a, b, c;
162
+
163
+ /* Bail if there aren't enough vertices to form any triangles. */
164
+ if(n < 3)
165
+ return [];
166
+
167
+ /* Slice out the actual vertices from the passed objects. (Duplicate the
168
+ * array even if we don't, though, since we need to make a supertriangle
169
+ * later on!) */
170
+ vertices = vertices.slice(0);
171
+
172
+ if(key)
173
+ for(i = n; i--; )
174
+ vertices[i] = vertices[i][key];
175
+
176
+ /* Make an array of indices into the vertex array, sorted by the
177
+ * vertices' x-position. */
178
+ indices = new Array(n);
179
+
180
+ for(i = n; i--; )
181
+ indices[i] = i;
182
+
183
+ indices.sort(function(i, j) {
184
+ return vertices[j][0] - vertices[i][0];
185
+ });
186
+
187
+ /* Next, find the vertices of the supertriangle (which contains all other
188
+ * triangles), and append them onto the end of a (copy of) the vertex
189
+ * array. */
190
+ st = supertriangle(vertices);
191
+ vertices.push(st[0], st[1], st[2]);
192
+
193
+ /* Initialize the open list (containing the supertriangle and nothing
194
+ * else) and the closed list (which is empty since we havn't processed
195
+ * any triangles yet). */
196
+ open = [circumcircle(vertices, n + 0, n + 1, n + 2)];
197
+ closed = [];
198
+ edges = [];
199
+
200
+ /* Incrementally add each vertex to the mesh. */
201
+ for(i = indices.length; i--; edges.length = 0) {
202
+ c = indices[i];
203
+
204
+ /* For each open triangle, check to see if the current point is
205
+ * inside it's circumcircle. If it is, remove the triangle and add
206
+ * it's edges to an edge list. */
207
+ for(j = open.length; j--; ) {
208
+ /* If this point is to the right of this triangle's circumcircle,
209
+ * then this triangle should never get checked again. Remove it
210
+ * from the open list, add it to the closed list, and skip. */
211
+ dx = vertices[c][0] - open[j].x;
212
+
213
+ if(dx > 0.0 && dx * dx > open[j].r) {
214
+ closed.push(open[j]);
215
+ open.splice(j, 1);
216
+ continue;
217
+ }
218
+
219
+ /* If we're outside the circumcircle, skip this triangle. */
220
+ dy = vertices[c][1] - open[j].y;
221
+
222
+ if(dx * dx + dy * dy - open[j].r > EPSILON)
223
+ continue;
224
+
225
+ /* Remove the triangle and add it's edges to the edge list. */
226
+ edges.push(
227
+ open[j].i, open[j].j,
228
+ open[j].j, open[j].k,
229
+ open[j].k, open[j].i
230
+ );
231
+
232
+ open.splice(j, 1);
233
+ }
234
+
235
+ /* Remove any doubled edges. */
236
+ dedup(edges);
237
+
238
+ /* Add a new triangle for each edge. */
239
+ for(j = edges.length; j; ) {
240
+ b = edges[--j];
241
+ a = edges[--j];
242
+ open.push(circumcircle(vertices, a, b, c));
243
+ }
244
+ }
245
+
246
+ /* Copy any remaining open triangles to the closed list, and then
247
+ * remove any triangles that share a vertex with the supertriangle,
248
+ * building a list of triplets that represent triangles. */
249
+ for(i = open.length; i--; )
250
+ closed.push(open[i]);
251
+
252
+ open.length = 0;
253
+
254
+ for(i = closed.length; i--; )
255
+ if(closed[i].i < n && closed[i].j < n && closed[i].k < n)
256
+ open.push(closed[i].i, closed[i].j, closed[i].k);
257
+
258
+ /* Yay, we're done! */
259
+ return open;
260
+ }
261
+
262
+ function init() {
263
+ var i, j, k;
264
+
265
+ // requestAnimFrame polyfill
266
+ window.requestAnimFrame = (function(){
267
+ return window.requestAnimationFrame ||
268
+ window.webkitRequestAnimationFrame ||
269
+ window.mozRequestAnimationFrame ||
270
+ function( callback ){
271
+ window.setTimeout(callback, 1000 / 60);
272
+ };
273
+ })();
274
+
275
+ // Size canvas
276
+ resize();
277
+
278
+ mouse.x = canvas.clientWidth / 2;
279
+ mouse.y = canvas.clientHeight / 2;
280
+
281
+ // Create particle positions
282
+ for (i = 0; i < particleCount; i++) {
283
+ var p = new Particle();
284
+ particles.push(p);
285
+ points.push([p.x*c, p.y*c]);
286
+ }
287
+
288
+ vertices = Delaunay(points);
289
+ // Create an array of "triangles" (groups of 3 indices)
290
+ var tri = [];
291
+
292
+ for (i = 0; i < vertices.length; i++) {
293
+ if (tri.length == 3) {
294
+ triangles.push(tri);
295
+ tri = [];
296
+ }
297
+
298
+ tri.push(vertices[i]);
299
+ }
300
+
301
+ // Tell all the particles who their neighbors are
302
+ for (i = 0; i < particles.length; i++) {
303
+ // Loop through all tirangles
304
+ for (j = 0; j < triangles.length; j++) {
305
+ // Check if this particle's index is in this triangle
306
+ k = triangles[j].indexOf(i);
307
+ // If it is, add its neighbors to the particles contacts list
308
+ if (k !== -1) {
309
+ triangles[j].forEach(function(value, index, array) {
310
+ if (value !== i && particles[i].neighbors.indexOf(value) == -1) {
311
+ particles[i].neighbors.push(value);
312
+ }
313
+ });
314
+ }
315
+ }
316
+ }
317
+
318
+ if (renderFlares) {
319
+ // Create flare positions
320
+ for (i = 0; i < flareCount; i++) {
321
+ flares.push(new Flare());
322
+ }
323
+ }
324
+
325
+ // Motion mode
326
+ if ('ontouchstart' in document.documentElement && window.DeviceOrientationEvent) {
327
+ console.log('Using device orientation');
328
+ window.addEventListener('deviceorientation', function(e) {
329
+ mouse.x = (canvas.clientWidth / 2) - ((e.gamma / 90) * (canvas.clientWidth / 2) * 2);
330
+ mouse.y = (canvas.clientHeight / 2) - ((e.beta / 90) * (canvas.clientHeight / 2) * 2);
331
+ }, true);
332
+ }
333
+ else {
334
+ // Mouse move listener
335
+ console.log('Using mouse movement');
336
+ document.body.addEventListener('mousemove', function(e) {
337
+ mouse.x = e.clientX;
338
+ mouse.y = e.clientY;
339
+ });
340
+ }
341
+
342
+ // Animation loop
343
+ (function animloop(){
344
+ requestAnimFrame(animloop);
345
+ resize();
346
+ render();
347
+ })();
348
+ }
349
+
350
+ function render() {
351
+ if (randomMotion) {
352
+ n++;
353
+
354
+ if (n >= noiseLength) {
355
+ n = 0;
356
+ }
357
+
358
+ nPos = noisePoint(n);
359
+ }
360
+
361
+ // Clear
362
+ context.clearRect(0, 0, canvas.width, canvas.height);
363
+
364
+ if (blurSize > 0) {
365
+ context.shadowBlur = blurSize;
366
+ context.shadowColor = randomColor(colorPalette);
367
+ }
368
+
369
+ if (renderParticles) {
370
+ // Render particles
371
+ for (var i = 0; i < particleCount; i++) {
372
+ particles[i].render();
373
+ }
374
+ }
375
+
376
+ if (renderMesh) {
377
+ // Render all lines
378
+ context.beginPath();
379
+
380
+ for (var v = 0; v < vertices.length-1; v++) {
381
+ // Splits the array into triplets
382
+ if ((v + 1) % 3 === 0) { continue; }
383
+
384
+ var p1 = particles[vertices[v]],
385
+ p2 = particles[vertices[v+1]];
386
+
387
+ var pos1 = position(p1.x, p1.y, p1.z),
388
+ pos2 = position(p2.x, p2.y, p2.z);
389
+
390
+ context.moveTo(pos1.x, pos1.y);
391
+ context.lineTo(pos2.x, pos2.y);
392
+ }
393
+
394
+ context.strokeStyle = randomColor(colorPalette);
395
+ context.lineWidth = lineWidth;
396
+ context.stroke();
397
+ context.closePath();
398
+ }
399
+
400
+ if (renderLinks) {
401
+ // Possibly start a new link
402
+ if (random(0, linkChance) == linkChance) {
403
+ var length = random(linkLengthMin, linkLengthMax);
404
+ var start = random(0, particles.length-1);
405
+ startLink(start, length);
406
+ }
407
+
408
+ // Render existing links
409
+ // Iterate in reverse so that removing items doesn't affect the loop
410
+ for (var l = links.length-1; l >= 0; l--) {
411
+ if (links[l] && !links[l].finished) {
412
+ links[l].render();
413
+ }
414
+ else {
415
+ delete links[l];
416
+ }
417
+ }
418
+ }
419
+
420
+ if (renderFlares) {
421
+ // Render flares
422
+ for (var j = 0; j < flareCount; j++) {
423
+ flares[j].render();
424
+ }
425
+ }
426
+ }
427
+
428
+ function resize() {
429
+ canvas.width = window.innerWidth * (window.devicePixelRatio || 1);
430
+ canvas.height = canvas.width * (canvas.clientHeight / canvas.clientWidth);
431
+ }
432
+
433
+ function startLink(vertex, length) {
434
+ links.push(new Link(vertex, length));
435
+ }
436
+
437
+ // Particle class
438
+ var Particle = function() {
439
+ this.x = random(-0.1, 1.1, true);
440
+ this.y = random(-0.1, 1.1, true);
441
+ this.z = random(0,4);
442
+ this.color = randomColor(colorPalette);
443
+ this.opacity = random(0.1,1,true);
444
+ this.flicker = 0;
445
+ this.neighbors = []; // placeholder for neighbors
446
+ };
447
+
448
+ Particle.prototype.render = function() {
449
+ var pos = position(this.x, this.y, this.z),
450
+ r = ((this.z * particleSizeMultiplier) + particleSizeBase) * (sizeRatio() / 1000),
451
+ o = this.opacity;
452
+
453
+ if (flicker) {
454
+ var newVal = random(-0.5, 0.5, true);
455
+ this.flicker += (newVal - this.flicker) / flickerSmoothing;
456
+
457
+ if (this.flicker > 0.5) this.flicker = 0.5;
458
+ if (this.flicker < -0.5) this.flicker = -0.5;
459
+
460
+ o += this.flicker;
461
+
462
+ if (o > 1) o = 1;
463
+ if (o < 0) o = 0;
464
+ }
465
+
466
+ context.fillStyle = this.color;
467
+ context.globalAlpha = o;
468
+ context.beginPath();
469
+ context.arc(pos.x, pos.y, r, 0, 2 * Math.PI, false);
470
+ context.fill();
471
+ context.closePath();
472
+
473
+ if (renderParticleGlare) {
474
+ context.globalAlpha = o * glareOpacityMultiplier;
475
+ context.ellipse(pos.x, pos.y, r * 100, r, (glareAngle - ((nPos.x - 0.5) * noiseStrength * motion)) * (Math.PI / 180), 0, 2 * Math.PI, false);
476
+ context.fill();
477
+ context.closePath();
478
+ }
479
+
480
+ context.globalAlpha = 1;
481
+ };
482
+
483
+ // Flare class
484
+ var Flare = function() {
485
+ this.x = random(-0.25, 1.25, true);
486
+ this.y = random(-0.25, 1.25, true);
487
+ this.z = random(0,2);
488
+ this.color = randomColor(colorPalette);
489
+ this.opacity = random(0.001, 0.01, true);
490
+ };
491
+
492
+ Flare.prototype.render = function() {
493
+ var pos = position(this.x, this.y, this.z),
494
+ r = ((this.z * flareSizeMultiplier) + flareSizeBase) * (sizeRatio() / 1000);
495
+
496
+ // Feathered circles
497
+ context.beginPath();
498
+ context.globalAlpha = this.opacity;
499
+ context.arc(pos.x, pos.y, r, 0, 2 * Math.PI, false);
500
+ context.fillStyle = this.color;
501
+ context.fill();
502
+ context.closePath();
503
+ context.globalAlpha = 1;
504
+ };
505
+
506
+ // Link class
507
+ var Link = function(startVertex, numPoints) {
508
+ this.length = numPoints;
509
+ this.verts = [startVertex];
510
+ this.stage = 0;
511
+ this.linked = [startVertex];
512
+ this.distances = [];
513
+ this.traveled = 0;
514
+ this.fade = 0;
515
+ this.finished = false;
516
+ };
517
+
518
+ Link.prototype.render = function() {
519
+ // Stages:
520
+ // 0. Vertex collection
521
+ // 1. Render line reaching from vertex to vertex
522
+ // 2. Fade out
523
+ // 3. Finished (delete me)
524
+
525
+ var i, p, pos, points;
526
+
527
+ switch (this.stage) {
528
+ // VERTEX COLLECTION STAGE
529
+ case 0:
530
+ // Grab the last member of the link
531
+ var last = particles[this.verts[this.verts.length-1]];
532
+ if (last && last.neighbors && last.neighbors.length > 0) {
533
+ // Grab a random neighbor
534
+ var neighbor = last.neighbors[random(0, last.neighbors.length-1)];
535
+ // If we haven't seen that particle before, add it to the link
536
+ if (this.verts.indexOf(neighbor) == -1) {
537
+ this.verts.push(neighbor);
538
+ }
539
+ // If we have seen that particle before, we'll just wait for the next frame
540
+ }
541
+ else {
542
+ this.stage = 3;
543
+ this.finished = true;
544
+ }
545
+
546
+ if (this.verts.length >= this.length) {
547
+ // Calculate all distances at once
548
+ for (i = 0; i < this.verts.length-1; i++) {
549
+ var p1 = particles[this.verts[i]],
550
+ p2 = particles[this.verts[i+1]],
551
+ dx = p1.x - p2.x,
552
+ dy = p1.y - p2.y,
553
+ dist = Math.sqrt(dx*dx + dy*dy);
554
+
555
+ this.distances.push(dist);
556
+ }
557
+ this.stage = 1;
558
+ }
559
+ break;
560
+
561
+ // RENDER LINE ANIMATION STAGE
562
+ case 1:
563
+ if (this.distances.length > 0) {
564
+
565
+ points = [];
566
+
567
+ // Gather all points already linked
568
+ for (i = 0; i < this.linked.length; i++) {
569
+ p = particles[this.linked[i]];
570
+ pos = position(p.x, p.y, p.z);
571
+ points.push([pos.x, pos.y]);
572
+ }
573
+
574
+ var linkSpeedRel = linkSpeed * 0.00001 * canvas.width;
575
+ this.traveled += linkSpeedRel;
576
+ var d = this.distances[this.linked.length-1];
577
+ // Calculate last point based on linkSpeed and distance travelled to next point
578
+ if (this.traveled >= d) {
579
+ this.traveled = 0;
580
+ // We've reached the next point, add coordinates to array
581
+ this.linked.push(this.verts[this.linked.length]);
582
+ p = particles[this.linked[this.linked.length-1]];
583
+ pos = position(p.x, p.y, p.z);
584
+ points.push([pos.x, pos.y]);
585
+
586
+ if (this.linked.length >= this.verts.length) {
587
+ this.stage = 2;
588
+ }
589
+ }
590
+ else {
591
+ // We're still travelling to the next point, get coordinates at travel distance
592
+ // http://math.stackexchange.com/a/85582
593
+ var a = particles[this.linked[this.linked.length-1]],
594
+ b = particles[this.verts[this.linked.length]],
595
+ t = d - this.traveled,
596
+ x = ((this.traveled * b.x) + (t * a.x)) / d,
597
+ y = ((this.traveled * b.y) + (t * a.y)) / d,
598
+ z = ((this.traveled * b.z) + (t * a.z)) / d;
599
+
600
+ pos = position(x, y, z);
601
+ points.push([pos.x, pos.y]);
602
+ }
603
+
604
+ this.drawLine(points);
605
+ }
606
+ else {
607
+ this.stage = 3;
608
+ this.finished = true;
609
+ }
610
+ break;
611
+
612
+ // FADE OUT STAGE
613
+ case 2:
614
+ if (this.verts.length > 1) {
615
+ if (this.fade < linkFade) {
616
+ this.fade++;
617
+
618
+ // Render full link between all vertices and fade over time
619
+ points = [];
620
+ var alpha = (1 - (this.fade / linkFade)) * linkOpacity;
621
+
622
+ for (i = 0; i < this.verts.length; i++) {
623
+ p = particles[this.verts[i]];
624
+ pos = position(p.x, p.y, p.z);
625
+ points.push([pos.x, pos.y]);
626
+ }
627
+
628
+ this.drawLine(points, alpha);
629
+ }
630
+ else {
631
+ this.stage = 3;
632
+ this.finished = true;
633
+ }
634
+ }
635
+ else {
636
+ this.stage = 3;
637
+ this.finished = true;
638
+ }
639
+
640
+ break;
641
+ // FINISHED STAGE
642
+ case 3:
643
+ default:
644
+ this.finished = true;
645
+ break;
646
+ }
647
+ };
648
+
649
+ Link.prototype.drawLine = function(points, alpha) {
650
+ if (typeof alpha !== 'number') alpha = linkOpacity;
651
+
652
+ if (points.length > 1 && alpha > 0) {
653
+ context.globalAlpha = alpha;
654
+ context.beginPath();
655
+
656
+ for (var i = 0; i < points.length-1; i++) {
657
+ context.moveTo(points[i][0], points[i][1]);
658
+ context.lineTo(points[i+1][0], points[i+1][1]);
659
+ }
660
+
661
+ context.strokeStyle = '#888';
662
+ context.lineWidth = lineWidth;
663
+ context.stroke();
664
+ context.closePath();
665
+ context.globalAlpha = 1;
666
+ }
667
+ };
668
+
669
+ // Utils
670
+ function noisePoint(i) {
671
+ var a = nAngle * i,
672
+ cosA = Math.cos(a),
673
+ sinA = Math.sin(a),
674
+ rad = nRad;
675
+
676
+ return {
677
+ x: rad * cosA,
678
+ y: rad * sinA
679
+ };
680
+ }
681
+
682
+ function position(x, y, z) {
683
+ return {
684
+ x: (x * canvas.width) + ((((canvas.width / 2) - mouse.x + ((nPos.x - 0.5) * noiseStrength)) * z) * motion),
685
+ y: (y * canvas.height) + ((((canvas.height / 2) - mouse.y + ((nPos.y - 0.5) * noiseStrength)) * z) * motion)
686
+ };
687
+ }
688
+
689
+ function sizeRatio() {
690
+ return canvas.width >= canvas.height ? canvas.width : canvas.height;
691
+ }
692
+
693
+ function random(min, max, float) {
694
+ return float ?
695
+ Math.random() * (max - min) + min :
696
+ Math.floor(Math.random() * (max - min + 1)) + min;
697
+ }
698
+
699
+ // init
700
+ if (canvas) init();