Advertisement
Guest User

Untitled

a guest
Jun 24th, 2019
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.48 KB | None | 0 0
  1. "use strict";
  2.  
  3. const backgroundColor = "rgba(0,0,10,0.5)";
  4. const baseHue = rand(360);
  5. const rangeHue = 180;
  6. const tentacleCount = 30;
  7. const segmentCountMin = 10;
  8. const segmentCountMax = 20;
  9. const segmentLengthMin = 20;
  10. const segmentLengthMax = 40;
  11. const colonyRadius = 200;
  12.  
  13. let canvas;
  14. let ctx;
  15. let center;
  16. let mouse;
  17. let tick;
  18. let simplex;
  19. let tentacles;
  20.  
  21. class Tentacle {
  22. constructor(x, y, segmentNum, baseLength, baseDirection) {
  23. this.base = [x, y];
  24. this.position = [x, y];
  25. this.target = [x, y];
  26. this.segmentNum = segmentNum;
  27. this.baseLength = baseLength;
  28. this.baseDirection = baseDirection;
  29. this.segmentProps = ["x1", "y1", "x2", "y2", "l", "d", "h"];
  30. this.segments = new PropsArray(segmentNum, this.segmentProps);
  31. this.follow = false;
  32.  
  33. let i = this.segments.length - this.segmentProps.length;
  34. let x1, y1, x2, y2, l, d, h;
  35.  
  36. l = this.baseLength;
  37. d = this.baseDirection;
  38.  
  39. for (; i >= 0; i -= this.segmentProps.length) {
  40. x1 = x2 || this.position[0];
  41. y1 = y2 || this.position[1];
  42. x2 = x1 - l * cos(d);
  43. y2 = y1 - l * sin(d);
  44. d += 0.309;
  45. l *= 0.98;
  46. h = baseHue + fadeIn(i, this.segments.length) * rangeHue;
  47. this.segments.set([x1, y1, x2, y2, l, d, h], i);
  48. }
  49. }
  50. setCtx(ctx) {
  51. this.ctx = ctx;
  52. }
  53. setTarget(target) {
  54. this.target = target;
  55. }
  56. updateBase() {
  57. let t = simplex.noise3D(this.base[0] * 0.005, this.base[1] * 0.005, tick * 0.005) * TAU;
  58.  
  59. this.base.lerp([
  60. this.base[0] + 20 * cos(t),
  61. this.base[1] + 20 * sin(t)
  62. ], 0.025);
  63. }
  64. async update() {
  65. let target = this.position;
  66. let i = this.segments.length - this.segmentProps.length;
  67. let promises = [];
  68.  
  69. this.position.lerp(this.target, 0.015);
  70. !this.follow && this.updateBase();
  71.  
  72. for (; i >= 0; i -= this.segmentProps.length) {
  73. promises.push(
  74. new Promise(resolve => {
  75. let [x1, y1, x2, y2, l, d, h] = this.segments.get(i);
  76. let t, n, tn;
  77.  
  78. x1 = target[0];
  79. y1 = target[1];
  80. t = angle(x1, y1, x2, y2);
  81. n = simplex.noise3D(
  82. (x1) * 0.005,
  83. (y1) * 0.005,
  84. (i + tick) * 0.005
  85. );
  86. tn = t + (n * PI * 0.0125);
  87. x2 = x1 + l * cos(tn);
  88. y2 = y1 + l * sin(tn);
  89. d = t;
  90.  
  91. target = [x2, y2];
  92.  
  93. this.segments.set([x1, y1, x2, y2, l, d], i);
  94. this.drawSegment(x1, y1, x2, y2, h, n, i);
  95.  
  96. resolve();
  97. })
  98. );
  99. }
  100.  
  101. await Promise.all(promises);
  102. }
  103. drawSegment(x1, y1, x2, y2, h, n, i) {
  104. const fn = fadeInOut(1 + n, 2);
  105. const fa = fadeInOut(i, this.segments.length);
  106. const a = 0.25 * (fn + fa);
  107.  
  108. this.ctx.beginPath();
  109. this.ctx.strokeStyle = `hsla(${h}, 50%, 50%, ${a})`;
  110. this.ctx.moveTo(x2, y2);
  111. this.ctx.lineTo(x1, y1);
  112. this.ctx.stroke();
  113. this.ctx.beginPath();
  114.  
  115. this.ctx.closePath();
  116. this.ctx.strokeStyle = `hsla(${h}, 50%, 50%, ${a + 0.5})`;
  117. this.ctx.arc(x1, y1, fn * 3, 0, TAU);
  118. this.ctx.stroke();
  119. this.ctx.closePath();
  120. }
  121. }
  122.  
  123. function setup() {
  124. tick = 0;
  125. simplex = new SimplexNoise();
  126. mouse = [0, 0];
  127. createCanvas();
  128. resize();
  129. tentacles = [];
  130.  
  131. let i, d, t, tentacle;
  132.  
  133. for (i = 0; i < tentacleCount; i++) {
  134. d = randRange(colonyRadius);
  135. t = i / tentacleCount * TAU;
  136. tentacle = new Tentacle(
  137. center[0] + d * cos(t),
  138. center[1] + d * sin(t),
  139. round(randIn(segmentCountMin, segmentCountMax)),
  140. round(randIn(segmentLengthMin, segmentLengthMax)),
  141. t
  142. );
  143. tentacle.setCtx(ctx.a);
  144. tentacles.push(tentacle);
  145. }
  146.  
  147. loop();
  148. }
  149.  
  150. function createCanvas() {
  151. canvas = {
  152. a: document.createElement("canvas"),
  153. b: document.createElement("canvas")
  154. };
  155. canvas.b.style = `
  156. position: absolute;
  157. top: 0;
  158. left: 0;
  159. width: 100%;
  160. height: 100%;
  161. `;
  162. document.body.appendChild(canvas.b);
  163. ctx = {
  164. a: canvas.a.getContext("2d"),
  165. b: canvas.b.getContext("2d")
  166. };
  167. center = [0.5 * canvas.a.width, 0.5 * canvas.a.height];
  168. }
  169.  
  170. function resize() {
  171. const { innerWidth, innerHeight } = window;
  172.  
  173. canvas.a.width = innerWidth;
  174. canvas.a.height = innerHeight;
  175.  
  176. ctx.a.drawImage(canvas.b, 0, 0);
  177.  
  178. canvas.b.width = innerWidth;
  179. canvas.b.height = innerHeight;
  180.  
  181. ctx.b.drawImage(canvas.a, 0, 0);
  182.  
  183. center[0] = 0.5 * canvas.a.width;
  184. center[1] = 0.5 * canvas.a.height;
  185. }
  186.  
  187. function renderBackground() {
  188. ctx.a.clearRect(0, 0, canvas.b.width, canvas.b.height);
  189. ctx.b.fillStyle = backgroundColor;
  190. ctx.b.fillRect(0, 0, canvas.a.width, canvas.a.height);
  191. }
  192.  
  193. function renderGlow() {
  194. ctx.b.save();
  195. ctx.b.filter = "blur(8px) brightness(200%)";
  196. ctx.b.globalCompositeOperation = "lighter";
  197. ctx.b.drawImage(canvas.a, 0, 0);
  198. ctx.b.restore();
  199.  
  200. ctx.b.save();
  201. ctx.b.filter = "blur(4px) brightness(200%)";
  202. ctx.b.globalCompositeOperation = "lighter";
  203. ctx.b.drawImage(canvas.a, 0, 0);
  204. ctx.b.restore();
  205. }
  206.  
  207. function renderToScreen() {
  208. ctx.b.save();
  209. ctx.b.globalCompositeOperation = "lighter";
  210. ctx.b.drawImage(canvas.a, 0, 0);
  211. ctx.b.restore();
  212. }
  213.  
  214. async function loop() {
  215. tick++;
  216.  
  217. renderBackground();
  218.  
  219. await Promise.all(tentacles.map(tentacle => tentacle.update()));
  220.  
  221. renderGlow();
  222. renderToScreen();
  223.  
  224. window.requestAnimationFrame(loop);
  225. }
  226.  
  227. window.addEventListener("load", setup);
  228. window.addEventListener("resize", resize);
  229. window.addEventListener("mousemove", (e) => {
  230. tentacles.forEach((tentacle, i) => {
  231. const t = i / tentacles.length * TAU;
  232. tentacle.setTarget([e.clientX + colonyRadius * cos(t + tick * 0.05), e.clientY + colonyRadius * sin(t + tick * 0.05)]);
  233. tentacle.follow = true;
  234. })
  235. });
  236. window.addEventListener("mouseout", () => {
  237. tentacles.forEach(tentacle => {
  238. tentacle.base = [
  239. center[0] + colonyRadius * cos(rand(TAU)),
  240. center[1] + colonyRadius * sin(rand(TAU))
  241. ];
  242. tentacle.setTarget(tentacle.base);
  243. tentacle.follow = false;
  244. });
  245. })
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement