<script>
const canvas = document.getElementById('liquid-matrix-canvas');
const ctx = canvas.getContext('2d');
let width, height;
let streams = [];
let particles = [];
const fontSize = 20;
const characters = 'アァカサタナハマヤャラワガザダバパイィキシチニヒミリヰギジヂビピウゥクスツヌフムユュルグズブプエェケセテネヘメレヱゲゼデベペオォコソトノホモヨョロヲゴゾドボポヴッン0123456789';
function resizeCanvas() {
width = canvas.width = window.innerWidth;
height = canvas.height = window.innerHeight;
initializeStreams();
}
function initializeStreams() {
streams = [];
const columns = Math.ceil(width / fontSize);
for (let i = 0; i < columns; i++) {
streams.push(new Stream(i * fontSize));
}
}
class Particle {
constructor(x, y, color) {
this.x = x;
this.y = y;
this.color = color;
this.size = Math.random() * 3 + 1;
this.vx = (Math.random() - 0.5) * 4;
this.vy = (Math.random() - 0.5) * 4 - 2; // Initial upward push
this.life = 100;
this.gravity = 0.1;
}
update() {
this.vy += this.gravity;
this.x += this.vx;
this.y += this.vy;
this.life--;
}
draw() {
ctx.globalAlpha = this.life / 100;
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill();
}
}
class Stream {
constructor(x) {
this.x = x;
this.y = Math.random() * -height;
this.speed = Math.random() * 2 + 0.5; // Slower, syrupy speed
this.length = Math.floor(Math.random() * 20 + 10);
this.symbols = [];
this.isChrome = Math.random() > 0.5;
this.createSymbols();
}
createSymbols() {
for (let i = 0; i < this.length; i++) {
const char = characters.charAt(Math.floor(Math.random() * characters.length));
this.symbols.push({ char, yOffset: i * fontSize });
}
}
update() {
this.y += this.speed;
if (this.y - this.length * fontSize > height) {
this.y = Math.random() * -height;
this.speed = Math.random() * 2 + 0.5;
}
}
draw() {
for (let i = 0; i < this.symbols.length; i++) {
const symbol = this.symbols[i];
const yPos = this.y - symbol.yOffset;
if (yPos > height + fontSize || yPos < 0) continue;
const opacity = 1 - (i / this.symbols.length);
const isHead = (i === 0);
if (this.isChrome) {
this.drawChromeSymbol(symbol.char, yPos, opacity, isHead);
} else {
this.drawGreenSymbol(symbol.char, yPos, opacity, isHead);
}
}
this.checkSplash();
}
drawChromeSymbol(char, y, opacity, isHead) {
const gradient = ctx.createLinearGradient(this.x, y - fontSize, this.x, y);
gradient.addColorStop(0, '#f0f0f0');
gradient.addColorStop(0.3, '#ffffff');
gradient.addColorStop(0.5, '#c0c0c0');
gradient.addColorStop(0.7, '#f0f0f0');
gradient.addColorStop(1, '#a0a0a0');
ctx.fillStyle = gradient;
ctx.globalAlpha = opacity * 0.9;
if (isHead) {
ctx.shadowColor = '#ffffff';
ctx.shadowBlur = 10;
ctx.globalAlpha = 1;
}
ctx.fillText(char, this.x, y);
ctx.shadowBlur = 0; // Reset shadow
}
drawGreenSymbol(char, y, opacity, isHead) {
const gradient = ctx.createLinearGradient(this.x, y - fontSize, this.x, y);
gradient.addColorStop(0, '#afffba');
gradient.addColorStop(0.3, '#00ff41');
gradient.addColorStop(0.5, '#ffffff');
gradient.addColorStop(0.7, '#00ff41');
gradient.addColorStop(1, '#0c6b20');
ctx.fillStyle = gradient;
ctx.globalAlpha = opacity;
if (isHead) {
ctx.shadowColor = '#00ff41';
ctx.shadowBlur = 15;
ctx.globalAlpha = 1;
}
ctx.fillText(char, this.x, y);
ctx.shadowBlur = 0; // Reset shadow
}
checkSplash() {
const headY = this.y;
if (headY > height && !this.splashed) {
const splashCount = Math.floor(Math.random() * 10 + 5);
const splashColor = this.isChrome ? '#c0c0c0' : '#00ff41';
for (let i = 0; i < splashCount; i++) {
particles.push(new Particle(this.x + (Math.random() - 0.5) * fontSize, height, splashColor));
}
this.splashed = true; // Prevent multiple splashes per fall
}
if (headY < height) {
this.splashed = false;
}
}
}
function animate() {
// Draw a semi-transparent black rectangle for the fading trail effect
ctx.fillStyle = 'rgba(1, 2, 1, 0.1)';
ctx.fillRect(0, 0, width, height);
ctx.font = `${fontSize}px monospace`;
streams.forEach(stream => {
stream.update();
stream.draw();
});
// Update and draw particles
for (let i = particles.length - 1; i >= 0; i--) {
particles[i].update();
particles[i].draw();
if (particles[i].life <= 0) {
particles.splice(i, 1);
}
}
ctx.globalAlpha = 1.0; // Reset global alpha
requestAnimationFrame(animate);
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
animate();
</script>
<script>
const canvas = document.getElementById('liquid-matrix-canvas');
const ctx = canvas.getContext('2d');
let width, height;
let streams = [];
let particles = [];
const fontSize = 20;
const characters = 'アァカサタナハマヤャラワガザダバパイィキシチニヒミリヰギジヂビピウゥクスツヌフムユュルグズブプエェケセテネヘメレヱゲゼデベペオォコソトノホモヨョロヲゴゾドボポヴッン0123456789';
function resizeCanvas() {
width = canvas.width = window.innerWidth;
height = canvas.height = window.innerHeight;
initializeStreams();
}
function initializeStreams() {
streams = [];
const columns = Math.ceil(width / fontSize);
for (let i = 0; i < columns; i++) {
streams.push(new Stream(i * fontSize));
}
}
class Particle {
constructor(x, y, color) {
this.x = x;
this.y = y;
this.color = color;
this.size = Math.random() * 3 + 1;
this.vx = (Math.random() - 0.5) * 4;
this.vy = (Math.random() - 0.5) * 4 - 2; // Initial upward push
this.life = 100;
this.gravity = 0.1;
}
update() {
this.vy += this.gravity;
this.x += this.vx;
this.y += this.vy;
this.life--;
}
draw() {
ctx.globalAlpha = this.life / 100;
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill();
}
}
class Stream {
constructor(x) {
this.x = x;
this.y = Math.random() * -height;
this.speed = Math.random() * 2 + 0.5; // Slower, syrupy speed
this.length = Math.floor(Math.random() * 20 + 10);
this.symbols = [];
this.isChrome = Math.random() > 0.5;
this.createSymbols();
}
createSymbols() {
for (let i = 0; i < this.length; i++) {
const char = characters.charAt(Math.floor(Math.random() * characters.length));
this.symbols.push({ char, yOffset: i * fontSize });
}
}
update() {
this.y += this.speed;
if (this.y - this.length * fontSize > height) {
this.y = Math.random() * -height;
this.speed = Math.random() * 2 + 0.5;
}
}
draw() {
for (let i = 0; i < this.symbols.length; i++) {
const symbol = this.symbols[i];
const yPos = this.y - symbol.yOffset;
if (yPos > height + fontSize || yPos < 0) continue;
const opacity = 1 - (i / this.symbols.length);
const isHead = (i === 0);
if (this.isChrome) {
this.drawChromeSymbol(symbol.char, yPos, opacity, isHead);
} else {
this.drawGreenSymbol(symbol.char, yPos, opacity, isHead);
}
}
this.checkSplash();
}
drawChromeSymbol(char, y, opacity, isHead) {
const gradient = ctx.createLinearGradient(this.x, y - fontSize, this.x, y);
gradient.addColorStop(0, '#f0f0f0');
gradient.addColorStop(0.3, '#ffffff');
gradient.addColorStop(0.5, '#c0c0c0');
gradient.addColorStop(0.7, '#f0f0f0');
gradient.addColorStop(1, '#a0a0a0');
ctx.fillStyle = gradient;
ctx.globalAlpha = opacity * 0.9;
if (isHead) {
ctx.shadowColor = '#ffffff';
ctx.shadowBlur = 10;
ctx.globalAlpha = 1;
}
ctx.fillText(char, this.x, y);
ctx.shadowBlur = 0; // Reset shadow
}
drawGreenSymbol(char, y, opacity, isHead) {
const gradient = ctx.createLinearGradient(this.x, y - fontSize, this.x, y);
gradient.addColorStop(0, '#afffba');
gradient.addColorStop(0.3, '#00ff41');
gradient.addColorStop(0.5, '#ffffff');
gradient.addColorStop(0.7, '#00ff41');
gradient.addColorStop(1, '#0c6b20');
ctx.fillStyle = gradient;
ctx.globalAlpha = opacity;
if (isHead) {
ctx.shadowColor = '#00ff41';
ctx.shadowBlur = 15;
ctx.globalAlpha = 1;
}
ctx.fillText(char, this.x, y);
ctx.shadowBlur = 0; // Reset shadow
}
checkSplash() {
const headY = this.y;
if (headY > height && !this.splashed) {
const splashCount = Math.floor(Math.random() * 10 + 5);
const splashColor = this.isChrome ? '#c0c0c0' : '#00ff41';
for (let i = 0; i < splashCount; i++) {
particles.push(new Particle(this.x + (Math.random() - 0.5) * fontSize, height, splashColor));
}
this.splashed = true; // Prevent multiple splashes per fall
}
if (headY < height) {
this.splashed = false;
}
}
}
function animate() {
// Draw a semi-transparent black rectangle for the fading trail effect
ctx.fillStyle = 'rgba(1, 2, 1, 0.1)';
ctx.fillRect(0, 0, width, height);
ctx.font = `${fontSize}px monospace`;
streams.forEach(stream => {
stream.update();
stream.draw();
});
// Update and draw particles
for (let i = particles.length - 1; i >= 0; i--) {
particles[i].update();
particles[i].draw();
if (particles[i].life <= 0) {
particles.splice(i, 1);
}
}
ctx.globalAlpha = 1.0; // Reset global alpha
requestAnimationFrame(animate);
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
animate();
</script>