feat(christmas.html): 添加背景音乐和不蒜子统计功能
- 格式化HTML代码,提升可读性 - 添加背景音乐播放功能,支持自动播放和用户交互播放 - 集成不蒜子网站统计脚本 - 优化粒子系统和3D渲染效果 - 改进手部识别交互逻辑 - 更新默认图片文字内容 - 添加音频播放错误处理机制 - 优化CSS样式结构和动画效果
This commit is contained in:
201
christmas.html
201
christmas.html
@@ -8,7 +8,8 @@
|
|||||||
|
|
||||||
|
|
||||||
<!--SEO信息 -->
|
<!--SEO信息 -->
|
||||||
<meta name="description" content="关于Honesty,关于HeHouHui,关于HeHui,关于明厚, About Me Honesty, About Me HeHouHui, About Me HeHui">
|
<meta name="description"
|
||||||
|
content="关于Honesty,关于HeHouHui,关于HeHui,关于明厚, About Me Honesty, About Me HeHouHui, About Me HeHui">
|
||||||
<meta name="keywords" content="Honesty,HeHouHui,HeHui,明厚">
|
<meta name="keywords" content="Honesty,HeHouHui,HeHui,明厚">
|
||||||
<link rel="canonical" href="https://www.hehouhui.cn/about.html">
|
<link rel="canonical" href="https://www.hehouhui.cn/about.html">
|
||||||
<meta name="author" content="Honesty">
|
<meta name="author" content="Honesty">
|
||||||
@@ -18,7 +19,8 @@
|
|||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://www.hehouhui.cn/christmas.html">
|
<meta property="og:url" content="https://www.hehouhui.cn/christmas.html">
|
||||||
<meta property="og:title" content="🎄圣诞快乐🎉 - Honesty的个人主页">
|
<meta property="og:title" content="🎄圣诞快乐🎉 - Honesty的个人主页">
|
||||||
<meta property="og:description" content="我是一名充满热情的Java后端开发工程师,专注于AI技术的探索与应用。来自湖南,现在上海工作,享受在这座充满活力的城市中追求技术梦想。">
|
<meta property="og:description"
|
||||||
|
content="我是一名充满热情的Java后端开发工程师,专注于AI技术的探索与应用。来自湖南,现在上海工作,享受在这座充满活力的城市中追求技术梦想。">
|
||||||
<meta property="og:image" content="https://www.hehouhui.cn/images/avatar.jpeg">
|
<meta property="og:image" content="https://www.hehouhui.cn/images/avatar.jpeg">
|
||||||
<meta property="og:site_name" content="Honesty的个人主页">
|
<meta property="og:site_name" content="Honesty的个人主页">
|
||||||
<meta property="og:locale" content="zh_CN">
|
<meta property="og:locale" content="zh_CN">
|
||||||
@@ -27,7 +29,8 @@
|
|||||||
<meta property="twitter:card" content="summary_large_image">
|
<meta property="twitter:card" content="summary_large_image">
|
||||||
<meta property="twitter:url" content="https://www.hehouhui.cn/christmas.html">
|
<meta property="twitter:url" content="https://www.hehouhui.cn/christmas.html">
|
||||||
<meta property="twitter:title" content="🎄圣诞快乐🎉 - Honesty的个人主页">
|
<meta property="twitter:title" content="🎄圣诞快乐🎉 - Honesty的个人主页">
|
||||||
<meta property="twitter:description" content="我是一名充满热情的Java后端开发工程师,专注于AI技术的探索与应用。来自湖南,现在上海工作,享受在这座充满活力的城市中追求技术梦想。">
|
<meta property="twitter:description"
|
||||||
|
content="我是一名充满热情的Java后端开发工程师,专注于AI技术的探索与应用。来自湖南,现在上海工作,享受在这座充满活力的城市中追求技术梦想。">
|
||||||
<meta property="twitter:image" content="https://www.hehouhui.cn/images/avatar.jpeg">
|
<meta property="twitter:image" content="https://www.hehouhui.cn/images/avatar.jpeg">
|
||||||
<meta property="twitter:site" content="@Honesty861024">
|
<meta property="twitter:site" content="@Honesty861024">
|
||||||
<link rel="alternate" hreflang="zh-cn" href="https://www.hehouhui.cn/about.html">
|
<link rel="alternate" hreflang="zh-cn" href="https://www.hehouhui.cn/about.html">
|
||||||
@@ -40,14 +43,33 @@
|
|||||||
<meta property="wechat:description" content="我是一名充满热情的Java后端开发工程师,专注于AI技术的探索与应用。">
|
<meta property="wechat:description" content="我是一名充满热情的Java后端开发工程师,专注于AI技术的探索与应用。">
|
||||||
<title>Grand Luxury Tree Final v2</title>
|
<title>Grand Luxury Tree Final v2</title>
|
||||||
<style>
|
<style>
|
||||||
body { margin: 0; overflow: hidden; background-color: #000000; font-family: 'Times New Roman', serif; }
|
body {
|
||||||
#canvas-container { width: 100vw; height: 100vh; position: absolute; top: 0; left: 0; z-index: 1; }
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #000000;
|
||||||
|
font-family: 'Times New Roman', serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#canvas-container {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* UI Overlay - Minimalist */
|
/* UI Overlay - Minimalist */
|
||||||
#ui-layer {
|
#ui-layer {
|
||||||
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
|
position: absolute;
|
||||||
z-index: 10; pointer-events: none;
|
top: 0;
|
||||||
display: flex; flex-direction: column;
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 10;
|
||||||
|
pointer-events: none;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-top: 40px;
|
padding-top: 40px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -62,29 +84,58 @@
|
|||||||
|
|
||||||
/* Loading */
|
/* Loading */
|
||||||
#loader {
|
#loader {
|
||||||
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
|
position: absolute;
|
||||||
background: #000; z-index: 100;
|
top: 0;
|
||||||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: #000;
|
||||||
|
z-index: 100;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
transition: opacity 0.8s ease-out;
|
transition: opacity 0.8s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loader-text {
|
.loader-text {
|
||||||
color: #d4af37; font-size: 14px; letter-spacing: 4px; margin-top: 20px;
|
color: #d4af37;
|
||||||
text-transform: uppercase; font-weight: 100;
|
font-size: 14px;
|
||||||
|
letter-spacing: 4px;
|
||||||
|
margin-top: 20px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spinner {
|
.spinner {
|
||||||
width: 40px; height: 40px; border: 1px solid rgba(212, 175, 55, 0.2);
|
width: 40px;
|
||||||
border-top: 1px solid #d4af37; border-radius: 50%;
|
height: 40px;
|
||||||
|
border: 1px solid rgba(212, 175, 55, 0.2);
|
||||||
|
border-top: 1px solid #d4af37;
|
||||||
|
border-radius: 50%;
|
||||||
animation: spin 1s linear infinite;
|
animation: spin 1s linear infinite;
|
||||||
}
|
}
|
||||||
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Typography - Centerpiece */
|
/* Typography - Centerpiece */
|
||||||
h1 {
|
h1 {
|
||||||
color: #fceea7; font-size: 56px; margin: 0; font-weight: 400;
|
color: #fceea7;
|
||||||
|
font-size: 56px;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 400;
|
||||||
letter-spacing: 6px;
|
letter-spacing: 6px;
|
||||||
text-shadow: 0 0 50px rgba(252, 238, 167, 0.6);
|
text-shadow: 0 0 50px rgba(252, 238, 167, 0.6);
|
||||||
background: linear-gradient(to bottom, #fff, #eebb66);
|
background: linear-gradient(to bottom, #fff, #eebb66);
|
||||||
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
font-family: 'Cinzel', 'Times New Roman', serif;
|
font-family: 'Cinzel', 'Times New Roman', serif;
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
transition: opacity 0.5s ease; /* Ensure smooth transitions if needed */
|
transition: opacity 0.5s ease; /* Ensure smooth transitions if needed */
|
||||||
@@ -97,6 +148,7 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
transition: opacity 0.5s ease; /* Add transition for smooth hiding */
|
transition: opacity 0.5s ease; /* Add transition for smooth hiding */
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-btn {
|
.upload-btn {
|
||||||
background: rgba(20, 20, 20, 0.6);
|
background: rgba(20, 20, 20, 0.6);
|
||||||
border: 1px solid rgba(212, 175, 55, 0.4);
|
border: 1px solid rgba(212, 175, 55, 0.4);
|
||||||
@@ -110,11 +162,13 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
backdrop-filter: blur(5px);
|
backdrop-filter: blur(5px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-btn:hover {
|
.upload-btn:hover {
|
||||||
background: #d4af37;
|
background: #d4af37;
|
||||||
color: #000;
|
color: #000;
|
||||||
box-shadow: 0 0 20px rgba(212, 175, 55, 0.5);
|
box-shadow: 0 0 20px rgba(212, 175, 55, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hint-text {
|
.hint-text {
|
||||||
color: rgba(212, 175, 55, 0.5);
|
color: rgba(212, 175, 55, 0.5);
|
||||||
font-size: 9px;
|
font-size: 9px;
|
||||||
@@ -123,14 +177,20 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
#file-input { display: none; }
|
#file-input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* Webcam feedback */
|
/* Webcam feedback */
|
||||||
#webcam-wrapper {
|
#webcam-wrapper {
|
||||||
position: absolute; bottom: 40px; right: 40px;
|
position: absolute;
|
||||||
width: 120px; height: 90px;
|
bottom: 40px;
|
||||||
|
right: 40px;
|
||||||
|
width: 120px;
|
||||||
|
height: 90px;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
overflow: hidden; opacity: 0; /* Hidden by default but functional */
|
overflow: hidden;
|
||||||
|
opacity: 0; /* Hidden by default but functional */
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -231,6 +291,22 @@
|
|||||||
setupEvents();
|
setupEvents();
|
||||||
await initMediaPipe();
|
await initMediaPipe();
|
||||||
|
|
||||||
|
// Play background music
|
||||||
|
const audio = document.getElementById('bg-music');
|
||||||
|
if (audio) {
|
||||||
|
// 尝试自动播放音频
|
||||||
|
try {
|
||||||
|
const playPromise = audio.play();
|
||||||
|
if (playPromise !== undefined) {
|
||||||
|
playPromise.catch(error => {
|
||||||
|
console.log("Audio autoplay failed:", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error attempting to play audio:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const loader = document.getElementById('loader');
|
const loader = document.getElementById('loader');
|
||||||
loader.style.opacity = 0;
|
loader.style.opacity = 0;
|
||||||
setTimeout(() => loader.remove(), 800);
|
setTimeout(() => loader.remove(), 800);
|
||||||
@@ -300,14 +376,18 @@
|
|||||||
|
|
||||||
function createTextures() {
|
function createTextures() {
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
canvas.width = 128; canvas.height = 128;
|
canvas.width = 128;
|
||||||
|
canvas.height = 128;
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.fillStyle = '#ffffff';
|
ctx.fillStyle = '#ffffff';
|
||||||
ctx.fillRect(0, 0, 128, 128);
|
ctx.fillRect(0, 0, 128, 128);
|
||||||
ctx.fillStyle = '#880000';
|
ctx.fillStyle = '#880000';
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
for (let i = -128; i < 256; i += 32) {
|
for (let i = -128; i < 256; i += 32) {
|
||||||
ctx.moveTo(i, 0); ctx.lineTo(i+32, 128); ctx.lineTo(i+16, 128); ctx.lineTo(i-16, 0);
|
ctx.moveTo(i, 0);
|
||||||
|
ctx.lineTo(i + 32, 128);
|
||||||
|
ctx.lineTo(i + 16, 128);
|
||||||
|
ctx.lineTo(i - 16, 0);
|
||||||
}
|
}
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
caneTexture = new THREE.CanvasTexture(canvas);
|
caneTexture = new THREE.CanvasTexture(canvas);
|
||||||
@@ -502,14 +582,19 @@
|
|||||||
|
|
||||||
function createDefaultPhotos() {
|
function createDefaultPhotos() {
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
canvas.width = 512; canvas.height = 512;
|
canvas.width = 512;
|
||||||
|
canvas.height = 512;
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.fillStyle = '#050505'; ctx.fillRect(0,0,512,512);
|
ctx.fillStyle = '#050505';
|
||||||
ctx.strokeStyle = '#eebb66'; ctx.lineWidth = 15; ctx.strokeRect(20,20,472,472);
|
ctx.fillRect(0, 0, 512, 512);
|
||||||
ctx.font = '500 60px Times New Roman'; ctx.fillStyle = '#eebb66';
|
ctx.strokeStyle = '#eebb66';
|
||||||
|
ctx.lineWidth = 15;
|
||||||
|
ctx.strokeRect(20, 20, 472, 472);
|
||||||
|
ctx.font = '500 60px Times New Roman';
|
||||||
|
ctx.fillStyle = '#eebb66';
|
||||||
ctx.textAlign = 'center';
|
ctx.textAlign = 'center';
|
||||||
ctx.fillText("JOYEUX", 256, 230);
|
ctx.fillText("JOYEUX", 256, 230);
|
||||||
ctx.fillText("NOEL", 256, 300);
|
ctx.fillText("W.F", 256, 300);
|
||||||
|
|
||||||
const tex = new THREE.CanvasTexture(canvas);
|
const tex = new THREE.CanvasTexture(canvas);
|
||||||
tex.colorSpace = THREE.SRGBColorSpace;
|
tex.colorSpace = THREE.SRGBColorSpace;
|
||||||
@@ -518,7 +603,11 @@
|
|||||||
|
|
||||||
function addPhotoToScene(texture) {
|
function addPhotoToScene(texture) {
|
||||||
const frameGeo = new THREE.BoxGeometry(1.4, 1.4, 0.05);
|
const frameGeo = new THREE.BoxGeometry(1.4, 1.4, 0.05);
|
||||||
const frameMat = new THREE.MeshStandardMaterial({ color: CONFIG.colors.champagneGold, metalness: 1.0, roughness: 0.1 });
|
const frameMat = new THREE.MeshStandardMaterial({
|
||||||
|
color: CONFIG.colors.champagneGold,
|
||||||
|
metalness: 1.0,
|
||||||
|
roughness: 0.1
|
||||||
|
});
|
||||||
const frame = new THREE.Mesh(frameGeo, frameMat);
|
const frame = new THREE.Mesh(frameGeo, frameMat);
|
||||||
|
|
||||||
const photoGeo = new THREE.PlaneGeometry(1.2, 1.2);
|
const photoGeo = new THREE.PlaneGeometry(1.2, 1.2);
|
||||||
@@ -557,7 +646,8 @@
|
|||||||
video = document.getElementById('webcam');
|
video = document.getElementById('webcam');
|
||||||
webcamCanvas = document.getElementById('webcam-preview');
|
webcamCanvas = document.getElementById('webcam-preview');
|
||||||
webcamCtx = webcamCanvas.getContext('2d');
|
webcamCtx = webcamCanvas.getContext('2d');
|
||||||
webcamCanvas.width = 160; webcamCanvas.height = 120;
|
webcamCanvas.width = 160;
|
||||||
|
webcamCanvas.height = 120;
|
||||||
|
|
||||||
const vision = await FilesetResolver.forVisionTasks(
|
const vision = await FilesetResolver.forVisionTasks(
|
||||||
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm"
|
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm"
|
||||||
@@ -579,6 +669,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let lastVideoTime = -1;
|
let lastVideoTime = -1;
|
||||||
|
|
||||||
async function predictWebcam() {
|
async function predictWebcam() {
|
||||||
if (video.currentTime !== lastVideoTime) {
|
if (video.currentTime !== lastVideoTime) {
|
||||||
lastVideoTime = video.currentTime;
|
lastVideoTime = video.currentTime;
|
||||||
@@ -597,7 +688,9 @@
|
|||||||
STATE.hand.x = (lm[9].x - 0.5) * 2;
|
STATE.hand.x = (lm[9].x - 0.5) * 2;
|
||||||
STATE.hand.y = (lm[9].y - 0.5) * 2;
|
STATE.hand.y = (lm[9].y - 0.5) * 2;
|
||||||
|
|
||||||
const thumb = lm[4]; const index = lm[8]; const wrist = lm[0];
|
const thumb = lm[4];
|
||||||
|
const index = lm[8];
|
||||||
|
const wrist = lm[0];
|
||||||
const pinchDist = Math.hypot(thumb.x - index.x, thumb.y - index.y);
|
const pinchDist = Math.hypot(thumb.x - index.x, thumb.y - index.y);
|
||||||
const tips = [lm[8], lm[12], lm[16], lm[20]];
|
const tips = [lm[8], lm[12], lm[16], lm[20]];
|
||||||
let avgDist = 0;
|
let avgDist = 0;
|
||||||
@@ -668,5 +761,49 @@
|
|||||||
|
|
||||||
init();
|
init();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- Background Music -->
|
||||||
|
<audio id="bg-music" loop preload="auto">
|
||||||
|
<source src="data/christmas.mp3" type="audio/mpeg">
|
||||||
|
</audio>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Auto play background music
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const audio = document.getElementById('bg-music');
|
||||||
|
try {
|
||||||
|
// 尝试自动播放
|
||||||
|
const playPromise = audio.play();
|
||||||
|
if (playPromise !== undefined) {
|
||||||
|
playPromise.then(_ => {
|
||||||
|
// 自动播放成功
|
||||||
|
console.log("Background music is playing");
|
||||||
|
}).catch(error => {
|
||||||
|
// 自动播放失败(浏览器限制),需要用户交互
|
||||||
|
console.log("Auto-play prevented by browser policy:", error);
|
||||||
|
// 添加用户交互事件来播放音频
|
||||||
|
document.body.addEventListener('click', function () {
|
||||||
|
if (audio.paused) {
|
||||||
|
audio.play();
|
||||||
|
}
|
||||||
|
}, {once: true});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error attempting to play audio:", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<!-- 不蒜子统计 -->
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
// 动态加载不蒜子统计脚本
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = "//cdn.busuanzi.cc/busuanzi/3.6.9/busuanzi.abbr.min.js";
|
||||||
|
script.async = true;
|
||||||
|
document.head.appendChild(script);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user