From 3099fd7d9fa414ddb581eab29d5d2c34f527c020 Mon Sep 17 00:00:00 2001 From: m1ngsama Date: Wed, 10 Dec 2025 10:58:34 +0800 Subject: [PATCH] feat: optimize slogan animation with smooth color interpolation Implemented true color interpolation for buttery smooth gradient animation: - Added hexToRgb, rgbToHex, and interpolateColor functions for mathematical color blending - Increased frame rate from 24 to 60 FPS for ultra-smooth motion - Changed easing from cubic to sine wave for more natural transitions - Dynamically generate gradients per frame instead of using pre-defined set - Eliminates staggered/jumping effect in the slogan text animation The animation now uses real-time color interpolation between adjacent colors in the sequence, creating seamless transitions without visible steps. --- src/core/logo.ts | 104 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 90 insertions(+), 14 deletions(-) diff --git a/src/core/logo.ts b/src/core/logo.ts index 42149d9..34eeee1 100644 --- a/src/core/logo.ts +++ b/src/core/logo.ts @@ -25,27 +25,103 @@ function createBlueGradient(text: string): string { } /** - * 显示渐变动画效果(优化版 - 更丝滑的动画) + * 将十六进制颜色转换为RGB + */ +function hexToRgb(hex: string): [number, number, number] { + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result + ? [parseInt(result[1]!, 16), parseInt(result[2]!, 16), parseInt(result[3]!, 16)] + : [0, 0, 0]; +} + +/** + * 将RGB转换为十六进制颜色 + */ +function rgbToHex(r: number, g: number, b: number): string { + return '#' + [r, g, b].map(x => { + const hex = Math.round(x).toString(16); + return hex.length === 1 ? '0' + hex : hex; + }).join(''); +} + +/** + * 在两个颜色之间进行线性插值 + */ +function interpolateColor(color1: string, color2: string, factor: number): string { + const [r1, g1, b1] = hexToRgb(color1); + const [r2, g2, b2] = hexToRgb(color2); + + const r = r1 + (r2 - r1) * factor; + const g = g1 + (g2 - g1) * factor; + const b = b1 + (b2 - b1) * factor; + + return rgbToHex(r, g, b); +} + +/** + * 缓动函数 - 平滑的进出效果 + */ +function easeInOutSine(t: number): number { + return -(Math.cos(Math.PI * t) - 1) / 2; +} + +/** + * 显示渐变动画效果(优化版 - 真正丝滑的动画) */ async function animateGradient(text: string, duration: number = 1200): Promise { - const frames = 24; // 增加帧数使动画更流畅 + const frames = 60; // 60帧实现真正的流畅动画 const frameDelay = duration / frames; - // 预创建所有渐变对象 - const gradients = [ - gradient('#1e3a8a', '#2563eb', '#3b82f6'), - gradient('#2563eb', '#3b82f6', '#0ea5e9'), - gradient('#3b82f6', '#0ea5e9', '#06b6d4'), - gradient('#0ea5e9', '#06b6d4', '#14b8a6'), - gradient('#06b6d4', '#14b8a6', '#0ea5e9'), - gradient('#14b8a6', '#0ea5e9', '#3b82f6'), - gradient('#0ea5e9', '#3b82f6', '#2563eb'), - gradient('#3b82f6', '#2563eb', '#1e3a8a'), + // 定义颜色序列 - 形成完整的蓝色系循环 + const colorSequence = [ + '#1e3a8a', // 深蓝 + '#2563eb', // 蓝 + '#3b82f6', // 亮蓝 + '#0ea5e9', // 天蓝 + '#06b6d4', // 青色 + '#14b8a6', // 青绿 + '#06b6d4', // 青色 + '#0ea5e9', // 天蓝 + '#3b82f6', // 亮蓝 + '#2563eb', // 蓝 + '#1e3a8a', // 深蓝 ]; for (let i = 0; i < frames; i++) { - const gradientIndex = Math.floor((i / frames) * gradients.length); - const frameGradient = gradients[gradientIndex]!; + // 使用平滑的正弦缓动 + const progress = easeInOutSine(i / frames); + + // 计算在颜色序列中的位置 + const position = progress * (colorSequence.length - 1); + const index1 = Math.floor(position); + const index2 = Math.min(index1 + 1, colorSequence.length - 1); + const localProgress = position - index1; + + // 在相邻颜色间插值,生成三个平滑过渡的颜色 + const color1 = interpolateColor( + colorSequence[index1]!, + colorSequence[index2]!, + localProgress + ); + + const nextIndex1 = Math.min(index2, colorSequence.length - 1); + const nextIndex2 = Math.min(nextIndex1 + 1, colorSequence.length - 1); + const color2 = interpolateColor( + colorSequence[nextIndex1]!, + colorSequence[nextIndex2]!, + localProgress + ); + + const nextIndex3 = Math.min(nextIndex2, colorSequence.length - 1); + const nextIndex4 = Math.min(nextIndex3 + 1, colorSequence.length - 1); + const color3 = interpolateColor( + colorSequence[nextIndex3]!, + colorSequence[nextIndex4]!, + localProgress + ); + + // 为当前帧创建渐变 + const frameGradient = gradient(color1, color2, color3); // 清除当前行并显示新帧 process.stdout.write('\r' + frameGradient(text));