style: 添加预设样式

This commit is contained in:
Baobhan Sith
2025-05-27 21:36:06 +08:00
parent 9c109f4240
commit 4966d2e575
16 changed files with 1779 additions and 148 deletions
-123
View File
@@ -1,123 +0,0 @@
<style>
#matrix-rain-container {
width: 100%; height: 100%; background: #000;
overflow: hidden; position: relative;
}
#matrix-canvas { display: block; position: absolute; top: 0; left: 0; }
</style>
<div id="matrix-rain-container">
<canvas id="matrix-canvas"></canvas>
</div>
<script>
(function() {
const canvas = document.getElementById('matrix-canvas');
const layerElement = canvas.closest('.terminal-custom-html-layer'); // Or document.body if not in that specific env
if (!canvas || !layerElement) {
console.error("Canvas or layerElement not found.");
return;
}
const ctx = canvas.getContext('2d');
let animationFrameId;
const characters = 'アァカサタナハマヤャラワABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const fontSize = 14;
let columns, drops = [];
// --- Slowdown Configuration ---
const slowdownFactor = 10; // 数字越大,动画越慢 (例如 2 = 半速, 3 = 1/3速度)
const originalAlpha = 0.1; // 原始的背景淡出alpha值
// 计算调整后的alpha值,以保持拖尾视觉效果
// 如果 slowdownFactor 为 1, adjustedAlpha 等于 originalAlpha
// (1 - newAlpha)^slowdownFactor = (1 - originalAlpha)^1
// 1 - newAlpha = (1 - originalAlpha)^(1/slowdownFactor)
// newAlpha = 1 - (1 - originalAlpha)^(1/slowdownFactor)
const adjustedAlpha = slowdownFactor <= 1 ? originalAlpha : 1 - Math.pow(1 - originalAlpha, 1 / slowdownFactor);
let frameCounter = 0; // 用于控制逻辑更新频率的计数器
// --- End Slowdown Configuration ---
function setupDimensionsAndColumns() {
canvas.width = layerElement.offsetWidth;
canvas.height = layerElement.offsetHeight;
columns = Math.floor(canvas.width / fontSize);
drops = [];
for (let x = 0; x < columns; x++) {
drops[x] = 1 + Math.floor(Math.random() * (canvas.height / fontSize));
}
frameCounter = 0; // 重置帧计数器
}
function drawMatrix() {
if (!ctx || canvas.width === 0 || canvas.height === 0) {
animationFrameId = requestAnimationFrame(drawMatrix);
return;
}
// 背景淡出效果:每一帧都执行,使用调整后的alpha值
ctx.fillStyle = `rgba(0, 0, 0, ${adjustedAlpha})`;
ctx.fillRect(0, 0, canvas.width, canvas.height);
frameCounter++;
// 只有当帧计数器达到 slowdownFactor 时,才更新雨滴逻辑和绘制字符
if (frameCounter >= slowdownFactor) {
frameCounter = 0; // 重置计数器
ctx.fillStyle = '#0F0'; // 雨滴颜色
ctx.font = fontSize + 'px monospace';
for (let i = 0; i < drops.length; i++) {
const text = characters.charAt(Math.floor(Math.random() * characters.length));
ctx.fillText(text, i * fontSize, drops[i] * fontSize);
// 如果雨滴超出画布底部,并且随机条件满足,则重置雨滴到顶部
if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
drops[i] = 0;
}
drops[i]++; // 雨滴下落
}
}
animationFrameId = requestAnimationFrame(drawMatrix);
}
const debounce = (func, delay) => {
let t;
return (...a) => {
clearTimeout(t);
t = setTimeout(() => func.apply(this, a), delay);
};
};
const debouncedReinitialize = debounce(() => {
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
setupDimensionsAndColumns();
if (columns > 0) {
drawMatrix();
}
}, 250);
// 确保 layerElement 存在才进行监听
if (layerElement) {
const resizeObserver = new ResizeObserver(entries => {
entries.forEach(entry => {
if (entry.target === layerElement) {
debouncedReinitialize();
}
});
});
resizeObserver.observe(layerElement);
} else {
// Fallback if layerElement is not specific, e.g. observe window or body
// window.addEventListener('resize', debouncedReinitialize); // Example fallback
console.warn("layerElement not found for ResizeObserver, resize handling might be limited.");
}
setupDimensionsAndColumns();
if (columns > 0) {
drawMatrix();
}
})();
</script>
-123
View File
@@ -1,123 +0,0 @@
<style>
#matrix-rain-container {
width: 100%; height: 100%; background: #000;
overflow: hidden; position: relative;
}
#matrix-canvas { display: block; position: absolute; top: 0; left: 0; }
</style>
<div id="matrix-rain-container">
<canvas id="matrix-canvas"></canvas>
</div>
<script>
(function() {
const canvas = document.getElementById('matrix-canvas');
const layerElement = canvas.closest('.terminal-custom-html-layer'); // Or document.body if not in that specific env
if (!canvas || !layerElement) {
console.error("Canvas or layerElement not found.");
return;
}
const ctx = canvas.getContext('2d');
let animationFrameId;
const characters = 'アァカサタナハマヤャラワABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const fontSize = 14;
let columns, drops = [];
// --- Slowdown Configuration ---
const slowdownFactor = 10; // 数字越大,动画越慢 (例如 2 = 半速, 3 = 1/3速度)
const originalAlpha = 0.1; // 原始的背景淡出alpha值
// 计算调整后的alpha值,以保持拖尾视觉效果
// 如果 slowdownFactor 为 1, adjustedAlpha 等于 originalAlpha
// (1 - newAlpha)^slowdownFactor = (1 - originalAlpha)^1
// 1 - newAlpha = (1 - originalAlpha)^(1/slowdownFactor)
// newAlpha = 1 - (1 - originalAlpha)^(1/slowdownFactor)
const adjustedAlpha = slowdownFactor <= 1 ? originalAlpha : 1 - Math.pow(1 - originalAlpha, 1 / slowdownFactor);
let frameCounter = 0; // 用于控制逻辑更新频率的计数器
// --- End Slowdown Configuration ---
function setupDimensionsAndColumns() {
canvas.width = layerElement.offsetWidth;
canvas.height = layerElement.offsetHeight;
columns = Math.floor(canvas.width / fontSize);
drops = [];
for (let x = 0; x < columns; x++) {
drops[x] = 1 + Math.floor(Math.random() * (canvas.height / fontSize));
}
frameCounter = 0; // 重置帧计数器
}
function drawMatrix() {
if (!ctx || canvas.width === 0 || canvas.height === 0) {
animationFrameId = requestAnimationFrame(drawMatrix);
return;
}
// 背景淡出效果:每一帧都执行,使用调整后的alpha值
ctx.fillStyle = `rgba(0, 0, 0, ${adjustedAlpha})`;
ctx.fillRect(0, 0, canvas.width, canvas.height);
frameCounter++;
// 只有当帧计数器达到 slowdownFactor 时,才更新雨滴逻辑和绘制字符
if (frameCounter >= slowdownFactor) {
frameCounter = 0; // 重置计数器
ctx.fillStyle = '#0F0'; // 雨滴颜色
ctx.font = fontSize + 'px monospace';
for (let i = 0; i < drops.length; i++) {
const text = characters.charAt(Math.floor(Math.random() * characters.length));
ctx.fillText(text, i * fontSize, drops[i] * fontSize);
// 如果雨滴超出画布底部,并且随机条件满足,则重置雨滴到顶部
if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
drops[i] = 0;
}
drops[i]++; // 雨滴下落
}
}
animationFrameId = requestAnimationFrame(drawMatrix);
}
const debounce = (func, delay) => {
let t;
return (...a) => {
clearTimeout(t);
t = setTimeout(() => func.apply(this, a), delay);
};
};
const debouncedReinitialize = debounce(() => {
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
setupDimensionsAndColumns();
if (columns > 0) {
drawMatrix();
}
}, 250);
// 确保 layerElement 存在才进行监听
if (layerElement) {
const resizeObserver = new ResizeObserver(entries => {
entries.forEach(entry => {
if (entry.target === layerElement) {
debouncedReinitialize();
}
});
});
resizeObserver.observe(layerElement);
} else {
// Fallback if layerElement is not specific, e.g. observe window or body
// window.addEventListener('resize', debouncedReinitialize); // Example fallback
console.warn("layerElement not found for ResizeObserver, resize handling might be limited.");
}
setupDimensionsAndColumns();
if (columns > 0) {
drawMatrix();
}
})();
</script>
+164
View File
@@ -0,0 +1,164 @@
<style>
#color-ribbons-container {
width: 100%; height: 100%;
background-color: #222733; /* 柔和的深蓝灰色 */
overflow: hidden; position: relative;
}
#ribbons-canvas { display: block; position: absolute; top: 0; left: 0; }
</style>
<div id="color-ribbons-container">
<canvas id="ribbons-canvas"></canvas>
</div>
<script>
(function() {
const canvas = document.getElementById('ribbons-canvas');
const layerElement = canvas.closest('.terminal-custom-html-layer') || canvas.parentElement;
if (!canvas || !layerElement) return;
const ctx = canvas.getContext('2d');
let width, height, animationFrameId;
const ribbons = [];
const numRibbons = 5; // 彩带数量
let time = 0;
// HSL颜色辅助函数
function hslToRgb(h, s, l) {
let r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
class Ribbon {
constructor() {
this.numPoints = 50 + Math.floor(Math.random() * 30); // 组成彩带路径的点数
this.points = [];
this.baseY = height * (0.2 + Math.random() * 0.6);
this.amplitude = height * (0.05 + Math.random() * 0.15);
this.frequency = 0.002 + Math.random() * 0.003;
this.phase = Math.random() * Math.PI * 2;
this.thickness = 20 + Math.random() * 30; // 彩带厚度
this.speed = 0.5 + Math.random() * 0.5; // 彩带横向移动速度
this.hueStart = Math.random(); // 0-1
this.hueChangeSpeed = 0.0005 + Math.random() * 0.001;
this.opacity = 0.1 + Math.random() * 0.2;
this.xOffset = -width * Math.random(); // 初始横向偏移,让彩带从不同位置进入
}
update(deltaTime) {
this.xOffset += this.speed * (deltaTime / (1000/60)); // Normalize speed to 60fps
if (this.xOffset > width + this.thickness * 5) { // 彩带完全移出右侧
this.xOffset = -this.thickness * 5 - Math.random() * width * 0.5; // 从左侧重新进入
this.baseY = height * (0.2 + Math.random() * 0.6); // 改变Y基线
this.hueStart = Math.random(); // 改变颜色
}
this.hueStart = (this.hueStart + this.hueChangeSpeed) % 1;
this.points = [];
for (let i = 0; i < this.numPoints; i++) {
const progress = i / (this.numPoints - 1); // 0 to 1
const x = this.xOffset + progress * (width + this.thickness * 10); // 彩带绘制范围比屏幕宽
const y = this.baseY + Math.sin(x * this.frequency + this.phase + time * 0.01) * this.amplitude +
Math.cos(x * this.frequency * 0.5 + this.phase * 0.7 + time * 0.005) * this.amplitude * 0.5;
this.points.push({ x, y });
}
}
draw() {
if (this.points.length < 2) return;
ctx.beginPath();
for (let i = 0; i < this.points.length -1; i++) {
const p1 = this.points[i];
const p2 = this.points[i+1];
// 计算垂直于路径的偏移点,形成彩带的上下边缘
const angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
const dxTop = Math.sin(angle) * this.thickness / 2;
const dyTop = -Math.cos(angle) * this.thickness / 2;
const dxBottom = -Math.sin(angle) * this.thickness / 2;
const dyBottom = Math.cos(angle) * this.thickness / 2;
if (i === 0) {
ctx.moveTo(p1.x + dxTop, p1.y + dyTop);
} else {
ctx.lineTo(p1.x + dxTop, p1.y + dyTop);
}
}
// 绘制下边缘 (反向)
for (let i = this.points.length - 1; i > 0; i--) {
const p1 = this.points[i];
// p2 is points[i-1] but we use p1's angle approx or recalculate
const p_prev = this.points[i-1];
const angle = Math.atan2(p1.y - p_prev.y, p1.x - p_prev.x); // Angle from prev to current
const dxBottom = -Math.sin(angle) * this.thickness / 2;
const dyBottom = Math.cos(angle) * this.thickness / 2;
ctx.lineTo(p1.x + dxBottom, p1.y + dyBottom);
}
ctx.closePath();
const [r,g,b] = hslToRgb(this.hueStart, 0.7, 0.6); // (饱和度0.7, 亮度0.6)
ctx.fillStyle = `rgba(${r},${g},${b}, ${this.opacity})`;
ctx.fill();
}
}
function init() {
width = layerElement.offsetWidth;
height = layerElement.offsetHeight;
canvas.width = width;
canvas.height = height;
ribbons.length = 0;
for (let i = 0; i < numRibbons; i++) {
ribbons.push(new Ribbon());
}
// 使用 'lighter' 或 'screen' 混合模式让彩带叠加时颜色混合更好
ctx.globalCompositeOperation = 'screen';
}
let lastTime = 0;
function animate(currentTime) {
const deltaTime = currentTime - lastTime;
lastTime = currentTime;
time++;
ctx.clearRect(0, 0, width, height); // 清晰的背景,或者用低alpha填充制造拖尾
ribbons.forEach(ribbon => {
ribbon.update(deltaTime || (1000/60)); // Provide a fallback for deltaTime on first frame
ribbon.draw();
});
animationFrameId = requestAnimationFrame(animate);
}
let resizeTimeout;
function onResize() {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
if (animationFrameId) cancelAnimationFrame(animationFrameId);
init();
// animate(0); // Restart animation loop
}, 250);
}
init();
animate(0); // Start animation loop
window.addEventListener('resize', onResize);
canvas.cleanup = function() { if (animationFrameId) cancelAnimationFrame(animationFrameId); };
})();
</script>
+88
View File
@@ -0,0 +1,88 @@
<style>
#svg-lava-lamp-background {
width: 100%;
height: 100%;
background-color: #111827; /* 深灰蓝 */
overflow: hidden;
}
#svg-lava-lamp-background svg {
width: 100%;
height: 100%;
}
.lava-g {
filter: url(#gooeyFilter); /* 应用"粘稠"滤镜 */
}
.lava-blob {
fill: #ffcc00; /* 岩浆颜色 */
/* 动画由JS控制更灵活,但这里用CSS尝试 */
animation: moveBlob 15s infinite ease-in-out alternate;
}
.lava-blob:nth-child(1) { animation-duration: 18s; animation-delay: -2s; fill: #ff9900;}
.lava-blob:nth-child(2) { animation-duration: 12s; animation-delay: -5s; fill: #ff6600;}
.lava-blob:nth-child(3) { animation-duration: 20s; animation-delay: 0s; fill: #ff3300;}
.lava-blob:nth-child(4) { animation-duration: 16s; animation-delay: -8s; fill: #cc3300;}
.lava-blob:nth-child(5) { animation-duration: 14s; animation-delay: -12s;fill: #ffcc00;}
@keyframes moveBlob {
0% { transform: translate(0px, 0px) scale(1); }
25% { transform: translate(30px, -50px) scale(1.2); }
50% { transform: translate(-20px, 40px) scale(0.8); }
75% { transform: translate(10px, -30px) scale(1.1); }
100% { transform: translate(0px, 0px) scale(1); }
}
</style>
<div id="svg-lava-lamp-background">
<svg viewBox="0 0 300 400" preserveAspectRatio="xMidYMid slice" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="gooeyFilter">
<!-- 高斯模糊使边缘模糊 -->
<feGaussianBlur in="SourceGraphic" stdDeviation="12" result="blur" />
<!-- 颜色矩阵增加alpha对比度,使模糊的边缘更"粘稠"地融合 -->
<feColorMatrix in="blur" mode="matrix"
values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 25 -10"
result="gooey" />
<!-- 可选:将原始图形叠在上面,如果想要更清晰的中心 -->
<!-- <feComposite in="SourceGraphic" in2="gooey" operator="atop"/> -->
</filter>
</defs>
<!-- 将所有气泡放在一个应用了滤镜的组中 -->
<g class="lava-g">
<!-- 定义一些圆形作为气泡 -->
<circle class="lava-blob" cx="100" cy="300" r="40" />
<circle class="lava-blob" cx="200" cy="350" r="55" />
<circle class="lava-blob" cx="150" cy="100" r="30" />
<circle class="lava-blob" cx="50" cy="150" r="45" />
<circle class="lava-blob" cx="250" cy="200" r="60" />
<circle class="lava-blob" cx="120" cy="220" r="35" />
</g>
</svg>
</div>
<script>
(function() {
// 用JS可以更精细地控制每个blob的动画,例如使用随机目标点
const blobs = document.querySelectorAll('#svg-lava-lamp-background .lava-blob');
const svg = document.querySelector('#svg-lava-lamp-background svg');
if (!blobs.length || !svg) return;
const viewBoxWidth = svg.viewBox.baseVal.width;
const viewBoxHeight = svg.viewBox.baseVal.height;
blobs.forEach((blob, index) => {
// 可以用JS设置更复杂的动画,这里CSS动画已经够用
// 为了让CSS动画不完全同步,已经用了nth-child和animation-delay
// 如果想完全随机化CSS动画的参数,可以用JS来动态设置style属性
// 例如: blob.style.animationDuration = (10 + Math.random() * 10) + 's';
// blob.style.animationDelay = (-Math.random() * 5) + 's';
// 动态改变transform-origin让缩放更有趣
blob.style.transformOrigin = `${Math.random()*50+25}% ${Math.random()*50+25}%`;
});
})();
</script>
@@ -0,0 +1,92 @@
<style>
#css-3d-cubes-background {
width: 100%;
height: 100%;
background-color: #080010; /* 深紫色背景 */
overflow: hidden;
position: relative;
perspective: 1000px; /* 为3D效果设置透视 */
}
.scene {
width: 100%;
height: 100%;
position: absolute;
transform-style: preserve-3d;
}
.cube-wrapper {
position: absolute;
width: 100px; /* 调整立方体大小 */
height: 100px;
transform-style: preserve-3d;
/* 动画由JS控制或预设不同参数 */
}
.cube {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
transform: rotateX(0deg) rotateY(0deg); /* 初始旋转,会被动画覆盖 */
animation: spin 15s infinite linear;
}
.cube .face {
position: absolute;
width: 100px;
height: 100px;
border: 1px solid rgba(0, 255, 255, 0.7); /* 青色霓虹边框 */
background-color: rgba(0, 50, 80, 0.2); /* 半透明深蓝面 */
box-shadow: 0 0 10px rgba(0, 255, 255, 0.5), inset 0 0 8px rgba(0, 255, 255, 0.3);
}
/* 定位立方体的六个面 */
.cube .front { transform: rotateY( 0deg) translateZ(50px); }
.cube .back { transform: rotateY(180deg) translateZ(50px); }
.cube .right { transform: rotateY( 90deg) translateZ(50px); }
.cube .left { transform: rotateY(-90deg) translateZ(50px); }
.cube .top { transform: rotateX( 90deg) translateZ(50px); }
.cube .bottom { transform: rotateX(-90deg) translateZ(50px); }
@keyframes spin {
from { transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg); }
to { transform: rotateX(360deg) rotateY(360deg) rotateZ(360deg); }
}
/* 示例立方体位置和动画差异化 */
.cube-wrapper-1 { top: 20%; left: 30%; transform: scale(0.8) translateZ(-100px); }
.cube-wrapper-1 .cube { animation-duration: 18s; animation-delay: -2s; }
.cube-wrapper-2 { top: 50%; left: 60%; transform: scale(1.2) translateZ(50px); }
.cube-wrapper-2 .cube { animation-duration: 12s; }
.cube-wrapper-3 { top: 70%; left: 15%; transform: scale(0.6) translateZ(-200px); }
.cube-wrapper-3 .cube { animation-duration: 22s; animation-delay: -5s; }
</style>
<div id="css-3d-cubes-background">
<div class="scene">
<div class="cube-wrapper cube-wrapper-1">
<div class="cube">
<div class="face front"></div> <div class="face back"></div>
<div class="face right"></div> <div class="face left"></div>
<div class="face top"></div> <div class="face bottom"></div>
</div>
</div>
<div class="cube-wrapper cube-wrapper-2">
<div class="cube">
<div class="face front"></div> <div class="face back"></div>
<div class="face right"></div> <div class="face left"></div>
<div class="face top"></div> <div class="face bottom"></div>
</div>
</div>
<div class="cube-wrapper cube-wrapper-3">
<div class="cube">
<div class="face front"></div> <div class="face back"></div>
<div class="face right"></div> <div class="face left"></div>
<div class="face top"></div> <div class="face bottom"></div>
</div>
</div>
<!-- 可以用JS动态添加更多cube-wrapper并随机化参数 -->
</div>
</div>