Реалистичный дождь в стиле Матрицы на CSS3 + HTML5 Canvas
Прикольная визуализация дождя из старой доброй Матрицы
Для начала посмотрите ДЕМО
Установка:
1#: В самый низ вашего CSS вставьте:
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 |
html, body { height: 100%; margin: 0; overflow: hidden; } body { display: flex; align-items: center; justify-content: center; background: #000; } main { display: flex; } p { line-height: 1; } span { display: block; width: 2vmax; height: 2vmax; font-size: 2vmax; color: #9bff9b11; text-align: center; font-family: "Helvetica Neue", Helvetica, sans-serif; } |
2#: После открывающего тега <body> поместите:
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 |
<main></main> <script type="text/javascript"> function r(from, to) { return ~~(Math.random() * (to - from + 1) + from); } function pick() { return arguments[r(0, arguments.length - 1)]; } function getChar() { return String.fromCharCode(pick( r(0x3041, 0x30ff), r(0x2000, 0x206f), r(0x0020, 0x003f) )); } function loop(fn, delay) { let stamp = Date.now(); function _loop() { if (Date.now() - stamp >= delay) { fn(); stamp = Date.now(); } requestAnimationFrame(_loop); } requestAnimationFrame(_loop); } class Char { constructor() { this.element = document.createElement('span'); this.mutate(); } mutate() { this.element.textContent = getChar(); } } class Trail { constructor(list = [], options) { this.list = list; this.options = Object.assign( { size: 10, offset: 0 }, options ); this.body = []; this.move(); } traverse(fn) { this.body.forEach((n, i) => { let last = (i == this.body.length - 1); if (n) fn(n, i, last); }); } move() { this.body = []; let { offset, size } = this.options; for (let i = 0; i < size; ++i) { let item = this.list[offset + i - size + 1]; this.body.push(item); } this.options.offset = (offset + 1) % (this.list.length + size - 1); } } class Rain { constructor({ target, row }) { this.element = document.createElement('p'); this.build(row); if (target) { target.appendChild(this.element); } this.drop(); } build(row = 20) { let root = document.createDocumentFragment(); let chars = []; for (let i = 0; i < row; ++i) { let c = new Char(); root.appendChild(c.element); chars.push(c); if (Math.random() < .5) { loop(() => c.mutate(), r(1e3, 5e3)); } } this.trail = new Trail(chars, { size: r(10, 30), offset: r(0, 100) }); this.element.appendChild(root); } drop() { let trail = this.trail; let len = trail.body.length; let delay = r(10, 100); loop(() => { trail.move(); trail.traverse((c, i, last) => { c.element.style = ` color: hsl(136, 100%, ${85 / len * (i + 1)}%) `; if (last) { c.mutate(); c.element.style = ` color: hsl(136, 100%, 85%); text-shadow: 0 0 .5em #fff, 0 0 .5em currentColor; `; } }); }, delay); } } const main = document.querySelector('main'); for (let i = 0; i < 50; ++i) { new Rain({ target: main, row: 50 }); } </script> |