Files
novalon-website/.superpowers/brainstorm/39838-1777791603/hero-ink-demos.html
T

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>