Заменил приблизительную hex-палитру на настоящие oklch()-цвета из
макета, подключил JetBrains Mono через Google Fonts (обновил CSP:
style-src/font-src для fonts.googleapis.com/fonts.gstatic.com).
Секция "обо мне" резюме — без term-window, плоские абзацы; опыт работы
в формате период/роль/компания·город + буллеты с тире; контакты в виде
label+value, как в макете. Карточки проектов — без бара с точками,
header-строка "drwxr-xr-x {name}" + ссылка справа, как в Projects.dc.html.
matrix-rain.js переписан по алгоритму из макета (shadowBlur на "голове"
капли, katakana-набор символов, накопительное падение). Градиент
глубины поверх дождя взял по факту темнее, чем в инлайн-стилях макета
(0.72–0.96 давал почти невидимый дождь) — подобрал по референс-скриншоту
макета (0.35–0.6), а не по сырым числам.
49 lines
1.4 KiB
JavaScript
49 lines
1.4 KiB
JavaScript
const canvas = document.getElementById('matrix-rain');
|
|
|
|
if (canvas && !window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
|
const ctx = canvas.getContext('2d');
|
|
const chars = 'アカサタナハマヤラワ01アイウエオカキク';
|
|
const fontSize = 16;
|
|
|
|
let columns = 0;
|
|
let drops = [];
|
|
let frameCount = 0;
|
|
|
|
function resize() {
|
|
canvas.width = window.innerWidth;
|
|
canvas.height = window.innerHeight;
|
|
columns = Math.floor(canvas.width / fontSize);
|
|
drops = new Array(columns).fill(0).map(() => Math.random() * -50);
|
|
}
|
|
|
|
function draw() {
|
|
ctx.fillStyle = 'rgba(3, 5, 3, 0.12)';
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
ctx.font = `${fontSize}px monospace`;
|
|
|
|
for (let i = 0; i < drops.length; i++) {
|
|
const text = chars[Math.floor(Math.random() * chars.length)];
|
|
const isHead = Math.random() > 0.92;
|
|
ctx.shadowColor = 'rgba(100, 255, 160, 1)';
|
|
ctx.shadowBlur = isHead ? 12 : 2;
|
|
ctx.fillStyle = isHead ? 'rgba(210, 255, 225, 1)' : 'rgba(80, 255, 140, 1)';
|
|
ctx.fillText(text, i * fontSize, drops[i] * fontSize);
|
|
if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
|
|
drops[i] = 0;
|
|
}
|
|
drops[i] += 0.4;
|
|
}
|
|
ctx.shadowBlur = 0;
|
|
}
|
|
|
|
function tick() {
|
|
frameCount++;
|
|
if (frameCount % 2 === 0) draw();
|
|
requestAnimationFrame(tick);
|
|
}
|
|
|
|
resize();
|
|
window.addEventListener('resize', resize);
|
|
requestAnimationFrame(tick);
|
|
}
|