448 lines
20 KiB
HTML
448 lines
20 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>东方韵味 Hero — 水墨扩散 Demo</title>
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0a0a0a; color: #fff; overflow-x: hidden; }
|
|
|
|
.nav { position: fixed; top: 0; left: 0; right: 0; z-index: 100; display: flex; gap: 8px; padding: 16px 24px; background: rgba(0,0,0,0.8); backdrop-filter: blur(12px); border-bottom: 1px solid rgba(255,255,255,0.1); }
|
|
.nav button { padding: 8px 20px; border: 1px solid rgba(255,255,255,0.2); border-radius: 8px; background: transparent; color: #fff; cursor: pointer; font-size: 14px; transition: all 0.3s; }
|
|
.nav button:hover { background: rgba(255,255,255,0.1); }
|
|
.nav button.active { background: #C41E3A; border-color: #C41E3A; }
|
|
|
|
.demo-section { display: none; position: relative; min-height: 100vh; overflow: hidden; }
|
|
.demo-section.active { display: flex; }
|
|
|
|
.hero-content { position: relative; z-index: 10; max-width: 720px; padding: 0 48px; }
|
|
.hero-tag { display: inline-flex; align-items: center; gap: 8px; padding: 8px 20px; border-radius: 999px; font-size: 14px; font-weight: 500; margin-bottom: 24px; }
|
|
.hero-title { font-size: 72px; font-weight: 400; line-height: 1.1; margin-bottom: 20px; letter-spacing: 0.05em; }
|
|
.hero-subtitle { font-size: 24px; font-weight: 600; margin-bottom: 12px; }
|
|
.hero-desc { font-size: 18px; line-height: 1.7; margin-bottom: 36px; opacity: 0.6; }
|
|
.hero-buttons { display: flex; gap: 16px; }
|
|
.btn-primary { padding: 14px 32px; background: #C41E3A; color: #fff; border: none; border-radius: 8px; font-size: 16px; cursor: pointer; display: flex; align-items: center; gap: 8px; }
|
|
.btn-outline { padding: 14px 32px; background: transparent; color: #1C1C1C; border: 1px solid rgba(0,0,0,0.15); border-radius: 8px; font-size: 16px; cursor: pointer; }
|
|
|
|
.replay-btn { position: fixed; bottom: 24px; right: 24px; z-index: 100; padding: 10px 20px; background: rgba(0,0,0,0.6); color: #fff; border: none; border-radius: 8px; cursor: pointer; font-size: 13px; backdrop-filter: blur(8px); }
|
|
.replay-btn:hover { background: rgba(0,0,0,0.8); }
|
|
.style-label { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); padding: 8px 24px; background: rgba(0,0,0,0.7); backdrop-filter: blur(8px); border-radius: 999px; font-size: 13px; color: rgba(255,255,255,0.6); z-index: 100; }
|
|
|
|
/* ========== Variant 1: 宣纸底色 + 真实水墨扩散 ========== */
|
|
#v1 { background: #F7F4EE; color: #1C1C1C; align-items: center; justify-content: flex-start; padding-top: 20vh; }
|
|
#v1 .hero-tag { background: rgba(196,30,58,0.08); color: #C41E3A; border: 1px solid rgba(196,30,58,0.15); }
|
|
#v1 .hero-title { font-family: 'Noto Serif SC', 'STSong', 'SimSun', serif; color: #1a1a1a; }
|
|
#v1 .hero-subtitle { color: #C41E3A; }
|
|
#v1 .btn-primary { background: #C41E3A; color: #fff; }
|
|
#v1 .btn-outline { color: #1C1C1C; border-color: rgba(28,28,28,0.2); }
|
|
|
|
#v1 .ink-canvas { position: absolute; inset: 0; pointer-events: none; }
|
|
#v1 .seal { position: absolute; top: 18%; right: 14%; width: 72px; height: 72px; border: 2.5px solid #C41E3A; border-radius: 6px; display: flex; align-items: center; justify-content: center; font-family: 'Noto Serif SC', serif; font-size: 26px; color: #C41E3A; opacity: 0; }
|
|
#v1 .paper-texture { position: absolute; inset: 0; opacity: 0.03; background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='0.8' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100' height='100' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E"); }
|
|
|
|
@keyframes v1-fade-up { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
|
|
@keyframes v1-seal-stamp {
|
|
0% { transform: scale(2.5) rotate(-15deg); opacity: 0; }
|
|
50% { transform: scale(0.85) rotate(3deg); opacity: 1; }
|
|
70% { transform: scale(1.1) rotate(-2deg); }
|
|
100% { transform: scale(1) rotate(-5deg); opacity: 0.9; }
|
|
}
|
|
|
|
#v1 .hero-tag { animation: v1-fade-up 0.6s ease-out 1.5s both; }
|
|
#v1 .hero-title { animation: v1-fade-up 0.8s ease-out 1.8s both; }
|
|
#v1 .hero-subtitle { animation: v1-fade-up 0.6s ease-out 2.1s both; }
|
|
#v1 .hero-desc { animation: v1-fade-up 0.6s ease-out 2.3s both; }
|
|
#v1 .hero-buttons { animation: v1-fade-up 0.6s ease-out 2.5s both; }
|
|
#v1 .seal { animation: v1-seal-stamp 0.8s ease-out 2.8s both; }
|
|
|
|
/* ========== Variant 2: 深色 + 金墨扩散 ========== */
|
|
#v2 { background: #0D0D0D; color: #F5F0E8; align-items: center; justify-content: flex-start; padding-top: 20vh; }
|
|
#v2 .hero-tag { background: rgba(196,30,58,0.2); color: #ff8a95; border: 1px solid rgba(196,30,58,0.3); }
|
|
#v2 .hero-title { font-family: 'Noto Serif SC', 'STSong', 'SimSun', serif; color: #F5F0E8; }
|
|
#v2 .hero-subtitle { color: #C41E3A; }
|
|
#v2 .hero-desc { color: rgba(245,240,232,0.5); }
|
|
#v2 .btn-primary { background: #C41E3A; color: #fff; }
|
|
#v2 .btn-outline { color: #F5F0E8; border-color: rgba(245,240,232,0.2); }
|
|
|
|
#v2 .ink-canvas { position: absolute; inset: 0; pointer-events: none; }
|
|
#v2 .seal { position: absolute; top: 18%; right: 14%; width: 72px; height: 72px; border: 2.5px solid rgba(196,30,58,0.8); border-radius: 6px; display: flex; align-items: center; justify-content: center; font-family: 'Noto Serif SC', serif; font-size: 26px; color: rgba(196,30,58,0.8); opacity: 0; }
|
|
#v2 .ambient-glow { position: absolute; top: 30%; left: 50%; transform: translate(-50%, -50%); width: 600px; height: 600px; background: radial-gradient(circle, rgba(196,30,58,0.06) 0%, transparent 60%); filter: blur(40px); }
|
|
|
|
@keyframes v2-fade-up { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
|
|
@keyframes v2-seal-stamp {
|
|
0% { transform: scale(2.5) rotate(-15deg); opacity: 0; }
|
|
50% { transform: scale(0.85) rotate(3deg); opacity: 1; }
|
|
70% { transform: scale(1.1) rotate(-2deg); }
|
|
100% { transform: scale(1) rotate(-5deg); opacity: 0.85; }
|
|
}
|
|
|
|
#v2 .hero-tag { animation: v2-fade-up 0.6s ease-out 1.5s both; }
|
|
#v2 .hero-title { animation: v2-fade-up 0.8s ease-out 1.8s both; }
|
|
#v2 .hero-subtitle { animation: v2-fade-up 0.6s ease-out 2.1s both; }
|
|
#v2 .hero-desc { animation: v2-fade-up 0.6s ease-out 2.3s both; }
|
|
#v2 .hero-buttons { animation: v2-fade-up 0.6s ease-out 2.5s both; }
|
|
#v2 .seal { animation: v2-seal-stamp 0.8s ease-out 2.8s both; }
|
|
|
|
/* ========== Variant 3: 半透明水墨 + 现代极简 ========== */
|
|
#v3 { background: linear-gradient(170deg, #FAFAF5 0%, #FFF8F0 50%, #FFFFFF 100%); color: #1C1C1C; align-items: center; justify-content: flex-start; padding-top: 20vh; }
|
|
#v3 .hero-tag { background: #FEF2F4; color: #C41E3A; border: 1px solid rgba(196,30,58,0.1); }
|
|
#v3 .hero-title { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-size: 64px; letter-spacing: -0.02em; }
|
|
#v3 .hero-subtitle { color: #C41E3A; }
|
|
#v3 .btn-primary { background: #C41E3A; color: #fff; }
|
|
#v3 .btn-outline { color: #1C1C1C; border-color: rgba(28,28,28,0.2); }
|
|
|
|
#v3 .ink-canvas { position: absolute; inset: 0; pointer-events: none; }
|
|
#v3 .seal { position: absolute; bottom: 28%; right: 16%; width: 48px; height: 48px; border: 2px solid rgba(196,30,58,0.5); border-radius: 4px; display: flex; align-items: center; justify-content: center; font-family: 'Noto Serif SC', serif; font-size: 18px; color: rgba(196,30,58,0.5); opacity: 0; }
|
|
#v3 .deco-dots { position: absolute; top: 22%; right: 20%; display: grid; grid-template-columns: repeat(3, 6px); gap: 12px; }
|
|
#v3 .deco-dot { width: 6px; height: 6px; border-radius: 50%; background: rgba(196,30,58,0.15); }
|
|
|
|
@keyframes v3-fade-up { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
|
|
@keyframes v3-seal-appear {
|
|
0% { transform: scale(1.8) rotate(-10deg); opacity: 0; }
|
|
70% { transform: scale(0.95) rotate(1deg); opacity: 0.8; }
|
|
100% { transform: scale(1) rotate(-3deg); opacity: 0.7; }
|
|
}
|
|
@keyframes v3-dot-pulse { 0%, 100% { opacity: 0.3; } 50% { opacity: 0.8; } }
|
|
|
|
#v3 .hero-tag { animation: v3-fade-up 0.5s ease-out 1.5s both; }
|
|
#v3 .hero-title { animation: v3-fade-up 0.6s ease-out 1.7s both; }
|
|
#v3 .hero-subtitle { animation: v3-fade-up 0.5s ease-out 1.9s both; }
|
|
#v3 .hero-desc { animation: v3-fade-up 0.5s ease-out 2.1s both; }
|
|
#v3 .hero-buttons { animation: v3-fade-up 0.5s ease-out 2.3s both; }
|
|
#v3 .seal { animation: v3-seal-appear 0.6s ease-out 2.5s both; }
|
|
#v3 .deco-dot { animation: v3-dot-pulse 3s ease-in-out infinite; }
|
|
#v3 .deco-dot:nth-child(2) { animation-delay: 0.4s; }
|
|
#v3 .deco-dot:nth-child(3) { animation-delay: 0.8s; }
|
|
#v3 .deco-dot:nth-child(4) { animation-delay: 0.2s; }
|
|
#v3 .deco-dot:nth-child(5) { animation-delay: 0.6s; }
|
|
#v3 .deco-dot:nth-child(6) { animation-delay: 1s; }
|
|
</style>
|
|
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700&display=swap" rel="stylesheet">
|
|
</head>
|
|
<body>
|
|
|
|
<div class="nav">
|
|
<button class="active" onclick="switchStyle('v1')">V1 宣纸水墨</button>
|
|
<button onclick="switchStyle('v2')">V2 深色金墨</button>
|
|
<button onclick="switchStyle('v3')">V3 水墨极简</button>
|
|
</div>
|
|
|
|
<!-- V1: 宣纸底色 + 真实水墨扩散 -->
|
|
<section id="v1" class="demo-section active">
|
|
<div class="paper-texture"></div>
|
|
<canvas class="ink-canvas" id="ink-canvas-v1"></canvas>
|
|
<div class="seal">睿</div>
|
|
<div class="hero-content">
|
|
<div class="hero-tag">✦ 智连未来,成长伙伴</div>
|
|
<h1 class="hero-title">睿新致遠</h1>
|
|
<p class="hero-subtitle">企业数字化转型服务商</p>
|
|
<p class="hero-desc">以智慧连接数字趋势,以伙伴身份陪您成长——您的数字化转型同行者</p>
|
|
<div class="hero-buttons">
|
|
<button class="btn-primary">立即咨询 →</button>
|
|
<button class="btn-outline">探索产品</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- V2: 深色 + 金墨扩散 -->
|
|
<section id="v2" class="demo-section">
|
|
<div class="ambient-glow"></div>
|
|
<canvas class="ink-canvas" id="ink-canvas-v2"></canvas>
|
|
<div class="seal">睿</div>
|
|
<div class="hero-content">
|
|
<div class="hero-tag">✦ 智连未来,成长伙伴</div>
|
|
<h1 class="hero-title">睿新致遠</h1>
|
|
<p class="hero-subtitle">企业数字化转型服务商</p>
|
|
<p class="hero-desc">以智慧连接数字趋势,以伙伴身份陪您成长——您的数字化转型同行者</p>
|
|
<div class="hero-buttons">
|
|
<button class="btn-primary">立即咨询 →</button>
|
|
<button class="btn-outline">探索产品</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- V3: 水墨极简 -->
|
|
<section id="v3" class="demo-section">
|
|
<canvas class="ink-canvas" id="ink-canvas-v3"></canvas>
|
|
<div class="deco-dots">
|
|
<div class="deco-dot"></div><div class="deco-dot"></div><div class="deco-dot"></div>
|
|
<div class="deco-dot"></div><div class="deco-dot"></div><div class="deco-dot"></div>
|
|
</div>
|
|
<div class="seal">睿</div>
|
|
<div class="hero-content">
|
|
<div class="hero-tag">✦ 智连未来,成长伙伴</div>
|
|
<h1 class="hero-title">睿新致遠</h1>
|
|
<p class="hero-subtitle">企业数字化转型服务商</p>
|
|
<p class="hero-desc">以智慧连接数字趋势,以伙伴身份陪您成长——您的数字化转型同行者</p>
|
|
<div class="hero-buttons">
|
|
<button class="btn-primary">立即咨询 →</button>
|
|
<button class="btn-outline">探索产品</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="style-label" id="style-label">V1 宣纸水墨 — 传统宣纸底色 + 水墨扩散 + 印章</div>
|
|
<button class="replay-btn" onclick="replayAnimation()">↻ 重播动画</button>
|
|
|
|
<script>
|
|
const labels = {
|
|
v1: 'V1 宣纸水墨 — 传统宣纸底色 + 水墨扩散 + 印章',
|
|
v2: 'V2 深色金墨 — 深色背景 + 金色/朱砂水墨 + 印章',
|
|
v3: 'V3 水墨极简 — 浅色现代 + 半透明水墨 + 微装饰',
|
|
};
|
|
|
|
let currentStyle = 'v1';
|
|
let animFrames = {};
|
|
|
|
function switchStyle(style) {
|
|
currentStyle = style;
|
|
document.querySelectorAll('.demo-section').forEach(s => s.classList.remove('active'));
|
|
document.querySelectorAll('.nav button').forEach(b => b.classList.remove('active'));
|
|
document.getElementById(style).classList.add('active');
|
|
document.querySelectorAll('.nav button')[['v1','v2','v3'].indexOf(style)].classList.add('active');
|
|
document.getElementById('style-label').textContent = labels[style];
|
|
replayAnimation();
|
|
}
|
|
|
|
function replayAnimation() {
|
|
Object.values(animFrames).forEach(id => cancelAnimationFrame(id));
|
|
animFrames = {};
|
|
|
|
const active = document.querySelector('.demo-section.active');
|
|
const clone = active.cloneNode(true);
|
|
active.parentNode.replaceChild(clone, active);
|
|
|
|
const canvasId = 'ink-canvas-' + currentStyle;
|
|
const canvas = document.getElementById(canvasId);
|
|
if (canvas) {
|
|
if (currentStyle === 'v1') startInkAnimationV1(canvas);
|
|
else if (currentStyle === 'v2') startInkAnimationV2(canvas);
|
|
else if (currentStyle === 'v3') startInkAnimationV3(canvas);
|
|
}
|
|
}
|
|
|
|
// ==========================================
|
|
// Ink Spread Animation Engine
|
|
// ==========================================
|
|
|
|
class InkDroplet {
|
|
constructor(x, y, maxRadius, color, speed, canvas) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.maxRadius = maxRadius;
|
|
this.color = color;
|
|
this.speed = speed;
|
|
this.canvas = canvas;
|
|
this.radius = 0;
|
|
this.opacity = 0;
|
|
this.phase = 'spreading'; // spreading -> settling -> done
|
|
this.wobble = Math.random() * Math.PI * 2;
|
|
this.wobbleSpeed = 0.02 + Math.random() * 0.02;
|
|
this.wobbleAmp = 0.15 + Math.random() * 0.1;
|
|
this.edgeParticles = [];
|
|
this.settleTimer = 0;
|
|
this.branches = [];
|
|
|
|
const branchCount = 3 + Math.floor(Math.random() * 4);
|
|
for (let i = 0; i < branchCount; i++) {
|
|
const angle = (Math.PI * 2 / branchCount) * i + (Math.random() - 0.5) * 0.5;
|
|
this.branches.push({
|
|
angle,
|
|
length: 0,
|
|
maxLength: maxRadius * (0.3 + Math.random() * 0.5),
|
|
width: 2 + Math.random() * 4,
|
|
speed: speed * (0.6 + Math.random() * 0.4),
|
|
wobble: Math.random() * Math.PI * 2,
|
|
});
|
|
}
|
|
}
|
|
|
|
update() {
|
|
if (this.phase === 'spreading') {
|
|
this.radius += this.speed;
|
|
this.wobble += this.wobbleSpeed;
|
|
this.opacity = Math.min(0.6, this.radius / this.maxRadius * 0.6);
|
|
|
|
for (const b of this.branches) {
|
|
if (b.length < b.maxLength) {
|
|
b.length += b.speed;
|
|
b.wobble += 0.03;
|
|
}
|
|
}
|
|
|
|
if (this.radius >= this.maxRadius) {
|
|
this.phase = 'settling';
|
|
}
|
|
} else if (this.phase === 'settling') {
|
|
this.settleTimer++;
|
|
this.opacity = Math.max(0.08, this.opacity - 0.003);
|
|
this.wobble += this.wobbleSpeed * 0.5;
|
|
if (this.settleTimer > 120) {
|
|
this.phase = 'done';
|
|
}
|
|
}
|
|
}
|
|
|
|
draw(ctx) {
|
|
if (this.opacity <= 0) return;
|
|
|
|
// Main ink body with organic edge
|
|
ctx.save();
|
|
ctx.globalAlpha = this.opacity;
|
|
|
|
// Draw organic ink shape
|
|
ctx.beginPath();
|
|
const segments = 60;
|
|
for (let i = 0; i <= segments; i++) {
|
|
const angle = (Math.PI * 2 / segments) * i;
|
|
const wobbleOffset = Math.sin(angle * 3 + this.wobble) * this.wobbleAmp
|
|
+ Math.sin(angle * 5 + this.wobble * 1.3) * this.wobbleAmp * 0.5;
|
|
const r = this.radius * (1 + wobbleOffset);
|
|
const px = this.x + Math.cos(angle) * r;
|
|
const py = this.y + Math.sin(angle) * r;
|
|
if (i === 0) ctx.moveTo(px, py);
|
|
else ctx.lineTo(px, py);
|
|
}
|
|
ctx.closePath();
|
|
|
|
// Radial gradient for ink density
|
|
const grad = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.radius * 1.2);
|
|
grad.addColorStop(0, this.color);
|
|
grad.addColorStop(0.6, this.color);
|
|
grad.addColorStop(1, 'transparent');
|
|
ctx.fillStyle = grad;
|
|
ctx.fill();
|
|
|
|
// Draw branches (毛细扩散)
|
|
for (const b of this.branches) {
|
|
if (b.length <= 0) continue;
|
|
ctx.beginPath();
|
|
ctx.lineWidth = b.width;
|
|
ctx.lineCap = 'round';
|
|
const startR = this.radius * 0.6;
|
|
const sx = this.x + Math.cos(b.angle) * startR;
|
|
const sy = this.y + Math.sin(b.angle) * startR;
|
|
const wobbleX = Math.sin(b.wobble) * 8;
|
|
const wobbleY = Math.cos(b.wobble * 0.7) * 8;
|
|
const ex = this.x + Math.cos(b.angle) * (startR + b.length) + wobbleX;
|
|
const ey = this.y + Math.sin(b.angle) * (startR + b.length) + wobbleY;
|
|
const cpx = (sx + ex) / 2 + wobbleX * 0.5;
|
|
const cpy = (sy + ey) / 2 + wobbleY * 0.5;
|
|
ctx.moveTo(sx, sy);
|
|
ctx.quadraticCurveTo(cpx, cpy, ex, ey);
|
|
ctx.strokeStyle = this.color;
|
|
ctx.globalAlpha = this.opacity * 0.5;
|
|
ctx.stroke();
|
|
}
|
|
|
|
ctx.restore();
|
|
}
|
|
}
|
|
|
|
function startInkAnimationV1(canvas) {
|
|
const ctx = canvas.getContext('2d');
|
|
canvas.width = window.innerWidth;
|
|
canvas.height = window.innerHeight;
|
|
|
|
const droplets = [];
|
|
const inkColor = 'rgba(28, 28, 28, 0.7)';
|
|
|
|
// Main large droplet
|
|
droplets.push(new InkDroplet(canvas.width * 0.7, canvas.height * 0.35, 250, inkColor, 2.5, canvas));
|
|
// Secondary droplets
|
|
setTimeout(() => {
|
|
droplets.push(new InkDroplet(canvas.width * 0.25, canvas.height * 0.7, 150, inkColor, 1.8, canvas));
|
|
}, 400);
|
|
setTimeout(() => {
|
|
droplets.push(new InkDroplet(canvas.width * 0.8, canvas.height * 0.75, 100, inkColor, 1.5, canvas));
|
|
}, 700);
|
|
// Red accent droplet
|
|
setTimeout(() => {
|
|
droplets.push(new InkDroplet(canvas.width * 0.72, canvas.height * 0.32, 60, 'rgba(196, 30, 58, 0.5)', 1.2, canvas));
|
|
}, 600);
|
|
|
|
function animate() {
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
for (const d of droplets) {
|
|
d.update();
|
|
d.draw(ctx);
|
|
}
|
|
animFrames['v1'] = requestAnimationFrame(animate);
|
|
}
|
|
animate();
|
|
}
|
|
|
|
function startInkAnimationV2(canvas) {
|
|
const ctx = canvas.getContext('2d');
|
|
canvas.width = window.innerWidth;
|
|
canvas.height = window.innerHeight;
|
|
|
|
const droplets = [];
|
|
const goldColor = 'rgba(212, 165, 116, 0.5)';
|
|
const redColor = 'rgba(196, 30, 58, 0.4)';
|
|
|
|
// Gold ink spread
|
|
droplets.push(new InkDroplet(canvas.width * 0.65, canvas.height * 0.3, 300, goldColor, 2, canvas));
|
|
setTimeout(() => {
|
|
droplets.push(new InkDroplet(canvas.width * 0.3, canvas.height * 0.65, 180, goldColor, 1.5, canvas));
|
|
}, 500);
|
|
// Red accent
|
|
setTimeout(() => {
|
|
droplets.push(new InkDroplet(canvas.width * 0.67, canvas.height * 0.28, 80, redColor, 1, canvas));
|
|
}, 800);
|
|
// Subtle dark ink
|
|
setTimeout(() => {
|
|
droplets.push(new InkDroplet(canvas.width * 0.8, canvas.height * 0.7, 120, 'rgba(245, 240, 232, 0.15)', 1.2, canvas));
|
|
}, 600);
|
|
|
|
function animate() {
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
for (const d of droplets) {
|
|
d.update();
|
|
d.draw(ctx);
|
|
}
|
|
animFrames['v2'] = requestAnimationFrame(animate);
|
|
}
|
|
animate();
|
|
}
|
|
|
|
function startInkAnimationV3(canvas) {
|
|
const ctx = canvas.getContext('2d');
|
|
canvas.width = window.innerWidth;
|
|
canvas.height = window.innerHeight;
|
|
|
|
const droplets = [];
|
|
const lightInk = 'rgba(28, 28, 28, 0.12)';
|
|
const redHint = 'rgba(196, 30, 58, 0.15)';
|
|
|
|
// Very subtle, translucent ink
|
|
droplets.push(new InkDroplet(canvas.width * 0.7, canvas.height * 0.3, 200, lightInk, 1.8, canvas));
|
|
setTimeout(() => {
|
|
droplets.push(new InkDroplet(canvas.width * 0.2, canvas.height * 0.7, 120, lightInk, 1.2, canvas));
|
|
}, 600);
|
|
setTimeout(() => {
|
|
droplets.push(new InkDroplet(canvas.width * 0.72, canvas.height * 0.28, 50, redHint, 0.8, canvas));
|
|
}, 900);
|
|
|
|
function animate() {
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
for (const d of droplets) {
|
|
d.update();
|
|
d.draw(ctx);
|
|
}
|
|
animFrames['v3'] = requestAnimationFrame(animate);
|
|
}
|
|
animate();
|
|
}
|
|
|
|
// Init
|
|
startInkAnimationV1(document.getElementById('ink-canvas-v1'));
|
|
|
|
window.addEventListener('resize', () => {
|
|
replayAnimation();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|