中核华泰建设有限公司的网站,内容型网站,十堰秦楚网,南京专业app开发定制文章目录一、效果展示二、源代码三、最初代版本的prompt四、手势控制原理一、效果展示
5种粒子效果3种手势控制背景音乐调色盘全屏控制 二、源代码
!DOCTYPE html
html langzh-CN
headmeta charsetUTF-8meta n…文章目录一、效果展示二、源代码三、最初代版本的prompt四、手势控制原理一、效果展示5种粒子效果3种手势控制背景音乐调色盘全屏控制二、源代码!DOCTYPEhtmlhtmllangzh-CNheadmetacharsetUTF-8metanameviewportcontentwidthdevice-width, initial-scale1.0title3D 粒子手势交互系统 v2.6 - 完整HUD版/titlescriptsrchttps://cdn.tailwindcss.com/scriptscriptasyncsrchttps://unpkg.com/es-module-shims1.6.3/dist/es-module-shims.js/scriptscripttypeimportmap{imports:{three:https://cdn.jsdelivr.net/npm/three0.154.0/build/three.module.js,three/addons/:https://cdn.jsdelivr.net/npm/three0.154.0/examples/jsm/}}/scriptscriptsrchttps://cdn.jsdelivr.net/npm/mediapipe/camera_utils/camera_utils.jscrossoriginanonymous/scriptscriptsrchttps://cdn.jsdelivr.net/npm/mediapipe/control_utils/control_utils.jscrossoriginanonymous/scriptscriptsrchttps://cdn.jsdelivr.net/npm/mediapipe/drawing_utils/drawing_utils.jscrossoriginanonymous/scriptscriptsrchttps://cdn.jsdelivr.net/npm/mediapipe/hands/hands.jscrossoriginanonymous/scriptstylebody{margin:0;overflow:hidden;background-color:#020205;font-family:Segoe UI,sans-serif;}#canvas-container{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1;}/* --- HUD 摄像头 (右下角) --- */.cam-container{position:absolute;bottom:20px;right:20px;width:240px;height:180px;z-index:50;border-radius:12px;overflow:hidden;border:1px solidrgba(0,255,255,0.3);background:rgba(0,0,0,0.8);box-shadow:0 0 20pxrgba(0,255,255,0.1);transition:opacity 0.3s;pointer-events:none;}#video-element, #output-canvas{position:absolute;top:0;left:0;width:100%;height:100%;transform:scaleX(-1);object-fit:cover;}#output-canvas{z-index:2;}.cam-label{position:absolute;top:5px;left:8px;font-family:monospace;font-size:10px;color:#00ffff;z-index:3;text-shadow:0 0 2px black;}/* --- UI 通用 --- */.glass-panel{background:rgba(10,10,20,0.85);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:1px solidrgba(255,255,255,0.15);border-radius:20px;box-shadow:0 8px 32pxrgba(0,0,0,0.6);pointer-events:auto;}.control-btn{transition:all 0.4scubic-bezier(0.4,0,0.2,1);position:relative;overflow:hidden;cursor:pointer;}.control-btn:hover{background:rgba(255,255,255,0.2);transform:translateY(-2px);box-shadow:0 0 20pxrgba(255,255,255,0.1);}.control-btn.active{background:linear-gradient(135deg,rgba(100,200,255,0.4),rgba(100,200,255,0.1));border:1px solidrgba(100,200,255,0.5);box-shadow:0 0 25pxrgba(79,209,197,0.3);text-shadow:0 0 8pxrgba(255,255,255,0.8);}/* 模式提示高亮 */.mode-item{transition:all 0.2s ease;opacity:0.4;transform:scale(0.95);font-weight:normal;}.mode-item.active{opacity:1;transform:scale(1.0);color:#22d3ee;font-weight:bold;text-shadow:0 0 10pxrgba(34,211,238,0.4);}/* 音乐按钮动画 */.playing-anim span{display:inline-block;width:3px;height:10px;background-color:#00ffff;margin:0 1px;animation:bounce 1s infinite ease-in-out;}.playing-anim span:nth-child(2){animation-delay:0.1s;}.playing-anim span:nth-child(3){animation-delay:0.2s;}keyframesbounce{0%, 100%{height:5px;}50%{height:15px;}}/* 颜色选择器 */.color-wrapper{position:relative;width:32px;height:32px;border-radius:50%;overflow:hidden;border:2px solidrgba(255,255,255,0.5);cursor:pointer;box-shadow:0 0 10pxrgba(0,0,0,0.3);}.color-wrapper:hover{transform:scale(1.1);border-color:#fff;}input[typecolor]{position:absolute;top:-50%;left:-50%;width:200%;height:200%;padding:0;margin:0;border:none;cursor:pointer;opacity:0;}#color-preview{width:100%;height:100%;background-color:#00ffff;}.loader{border:3px solidrgba(255,255,255,0.1);border-left-color:#00ffff;border-radius:50%;width:50px;height:50px;animation:spin 0.8s infinite;}keyframesspin{100%{transform:rotate(360deg);}}.custom-scroll::-webkit-scrollbar{height:4px;}.custom-scroll::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.2);border-radius:4px;}/style/headbodydividcanvas-container/divaudioidbgmloopsourcesrchttps://raw.githubusercontent.com/mrdoob/three.js/master/examples/sounds/376737_Skullbeatz___Bad_Cat_Maste.mp3typeaudio/mp3/audiodivclasscam-containerdivclasscam-labelLINK v2.6/divvideoidvideo-elementplaysinline/videocanvasidoutput-canvas/canvas/divdividloader-overlayclassfixed inset-0 z-50 flex flex-col items-center justify-center bg-black bg-opacity-95 transition-opacity duration-700divclassloader mb-6 shadow-[0_0_30px_rgba(0,255,255,0.3)]/divdivclasstext-transparent bg-clip-text bg-gradient-to-r from-cyan-300 to-blue-500 text-2xl font-bold tracking-widest uppercaseVisual Core/divdivclasstext-gray-500 text-xs mt-3 tracking-widestINITIALIZING INTERFACE v2.6.../div/divdivclassabsolute top-0 left-0 w-full h-full pointer-events-none z-40 p-4 md:p-8 flex flex-col justify-betweendivclassflex justify-between items-start pointer-events-autodivclassglass-panel p-5 animate-fade-in-downh1classtext-white text-2xl font-bold tracking-tight mb-2 drop-shadow-[0_0_10px_rgba(255,255,255,0.3)]粒子 · 幻境spanclasstext-xs text-cyan-400 align-topv2.6/span/h1divclassflex items-center gap-3 bg-black/30 rounded-full px-3 py-1 w-fit border border-white/5dividstatus-dotclassw-2 h-2 rounded-full bg-red-500 transition-all duration-500 shadow-[0_0_10px_red]/divspanidstatus-textclasstext-[10px] text-gray-300 font-mono uppercase tracking-widerOffline/span/divbuttononclicktoggleMusic()classmt-3 flex items-center gap-2 px-3 py-1.5 rounded bg-white/5 hover:bg-white/10 text-xs text-cyan-300 border border-cyan-500/30 transition-alldividmusic-iconclasstext-xs MUSIC OFF/divdividmusic-animclassplaying-anim hiddenspan/spanspan/spanspan/span/div/buttondivclasstext-[10px] text-gray-400 mt-4 font-mono border-t border-white/10 pt-2 flex flex-col gap-1.5dividmode-scaleclassmode-item active 五指张合: 能量爆发 (缩放)/divdividmode-rotateclassmode-item☝️ 食指滑动: 视角旋转 (移动)/divdividmode-rollclassmode-item✌️ 双指旋转: 平面翻转 (旋钮)/div/div/divbuttononclicktoggleFullScreen()classglass-panel p-4 text-white hover:text-cyan-300 control-btn rounded-full groupsvgxmlnshttp://www.w3.org/2000/svgclassh-6 w-6 group-hover:scale-110 transition-transformfillnoneviewBox0 0 24 24strokecurrentColorpathstroke-linecaproundstroke-linejoinroundstroke-width2dM4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4//svg/button/divdivclasspointer-events-auto flex flex-col md:flex-row gap-4 items-end md:items-center justify-center w-full pb-4divclassglass-panel p-2 flex gap-2 overflow-x-auto max-w-[70vw] custom-scrollbuttononclickchangeShape(sphere)classcontrol-btn active px-5 py-2 rounded-lg text-sm text-white font-semibold whitespace-nowrapdata-shapesphere星云球/buttonbuttononclickchangeShape(heart)classcontrol-btn px-5 py-2 rounded-lg text-sm text-white font-semibold whitespace-nowrapdata-shapeheart机械心/buttonbuttononclickchangeShape(saturn)classcontrol-btn px-5 py-2 rounded-lg text-sm text-white font-semibold whitespace-nowrapdata-shapesaturn土星环/buttonbuttononclickchangeShape(lotus)classcontrol-btn px-5 py-2 rounded-lg text-sm text-white font-semibold whitespace-nowrapdata-shapelotus能量莲/buttonbuttononclickchangeShape(galaxy)classcontrol-btn px-5 py-2 rounded-lg text-sm text-white font-semibold whitespace-nowrapdata-shapegalaxy黑洞/button/divdivclassglass-panel p-2 flex items-center justify-centerdivclasscolor-wrappertitleChange Colordividcolor-preview/divinputtypecoloridcolor-pickervalue#00ffffoninputupdateColor(this.value)/div/div/div/divscripttypemoduleimport*asTHREEfromthree;import{OrbitControls}fromthree/addons/controls/OrbitControls.js;import{EffectComposer}fromthree/addons/postprocessing/EffectComposer.js;import{RenderPass}fromthree/addons/postprocessing/RenderPass.js;import{UnrealBloomPass}fromthree/addons/postprocessing/UnrealBloomPass.js;// --- Configuration ---constPARTICLE_COUNT45000;constPARTICLE_SIZE0.18;constSATURN_BODY_RATIO0.3;// Stateletscene,camera,renderer,composer,particles,controls;lettargetPositions[];lettargetColors[];letcurrentShapesphere;lethandInfluence0;letisHandDetectedfalse;letclocknewTHREE.Clock();letuserBaseColornewTHREE.Color(0x00ffff);// InteractionletrotationVelocity{x:0,y:0,z:0};letisTrackingRollfalse;letpreviousRollAngle0;letisTrackingRotatefalse;letlastCursorPos{x:0,y:0};letcurrentStableModescale;letmodeFrameCounter0;// Music StateletisMusicPlayingfalse;functionlerp(start,end,amt){return(1-amt)*startamt*end;}// --- Music Control ---window.toggleMusicfunction(){constaudiodocument.getElementById(bgm);consticondocument.getElementById(music-icon);constanimdocument.getElementById(music-anim);if(isMusicPlaying){audio.pause();icon.innerText MUSIC OFF;icon.style.color#a5f3fc;anim.classList.add(hidden);isMusicPlayingfalse;}else{audio.volume0.5;audio.play().then((){icon.innerText PLAYING;icon.style.color#00ffff;anim.classList.remove(hidden);isMusicPlayingtrue;}).catch(e{console.error(Audio Play Error:,e);alert(无法播放音频请检查网络或浏览器权限。);});}}asyncfunctioninit(){scenenewTHREE.Scene();scene.fognewTHREE.FogExp2(0x020205,0.02);cameranewTHREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,0.1,1000);camera.position.z30;renderernewTHREE.WebGLRenderer({antialias:false,alpha:true,powerPreference:high-performance});renderer.setSize(window.innerWidth,window.innerHeight);renderer.setPixelRatio(Math.min(window.devicePixelRatio,1.5));document.getElementById(canvas-container).appendChild(renderer.domElement);constrenderScenenewRenderPass(scene,camera);constbloomPassnewUnrealBloomPass(newTHREE.Vector2(window.innerWidth,window.innerHeight),1.5,0.4,0.85);bloomPass.threshold0.05;bloomPass.strength1.4;bloomPass.radius0.6;composernewEffectComposer(renderer);composer.addPass(renderScene);composer.addPass(bloomPass);controlsnewOrbitControls(camera,renderer.domElement);controls.enableDampingtrue;controls.dampingFactor0.05;controls.autoRotatetrue;controls.autoRotateSpeed0.5;createParticles();awaitsetupMediaPipe();window.addEventListener(resize,onWindowResize);animate();}functioncreateParticles(){constgeometrynewTHREE.BufferGeometry();constpositionsnewFloat32Array(PARTICLE_COUNT*3);constcolorsnewFloat32Array(PARTICLE_COUNT*3);constinitialPosgetShapePositions(sphere);constinitialColorsgetShapeColors(sphere);for(leti0;iPARTICLE_COUNT;i){positions[i*3]initialPos[i*3];positions[i*31]initialPos[i*31];positions[i*32]initialPos[i*32];colors[i*3]initialColors[i*3];colors[i*31]initialColors[i*31];colors[i*32]initialColors[i*32];}geometry.setAttribute(position,newTHREE.BufferAttribute(positions,3));geometry.setAttribute(color,newTHREE.BufferAttribute(colors,3));constmaterialnewTHREE.PointsMaterial({size:PARTICLE_SIZE,map:createParticleTexture(),color:userBaseColor,transparent:true,opacity:0.8,blending:THREE.AdditiveBlending,depthWrite:false,vertexColors:true});particlesnewTHREE.Points(geometry,material);scene.add(particles);targetPositionsFloat32Array.from(initialPos);targetColorsFloat32Array.from(initialColors);}// --- 核心数学逻辑 (还原自 v2.1) ---functiongetShapePositions(type){constposnewFloat32Array(PARTICLE_COUNT*3);for(leti0;iPARTICLE_COUNT;i){letx,y,z;if(typesphere){constr10Math.random()*2;constthetaMath.random()*Math.PI*2;constphiMath.acos(2*Math.random()-1);xr*Math.sin(phi)*Math.cos(theta);yr*Math.sin(phi)*Math.sin(theta);zr*Math.cos(phi);if(iPARTICLE_COUNT*0.2){x*0.3;y*0.3;z*0.3;}}elseif(typeheart){consttMath.PI-2*Math.PI*Math.random();constu2*Math.PI*Math.random();x16*Math.pow(Math.sin(t),3);y13*Math.cos(t)-5*Math.cos(2*t)-2*Math.cos(3*t)-Math.cos(4*t);z6*Math.cos(t)*Math.sin(u)*Math.sin(t);constscale0.6;x*scale;y*scale;z*scale;if(Math.random()0.8){x*1.1;y*1.1;z*1.1;}}elseif(typesaturn){if(iPARTICLE_COUNT*SATURN_BODY_RATIO){constr5.5;constthetaMath.random()*Math.PI*2;constphiMath.acos(2*Math.random()-1);xr*Math.sin(phi)*Math.cos(theta);yr*0.9*Math.sin(phi)*Math.sin(theta);zr*Math.cos(phi);}else{constangleMath.random()*Math.PI*2;constringSelectorMath.random();letr,thickness;if(ringSelector0.45){r7Math.random()*3.5;thickness0.2;}elseif(ringSelector0.5){r10.5Math.random()*1.5;thickness0.1;if(Math.random()0.2){x0;y0;z0;pos[i*3]x;pos[i*31]y;pos[i*32]z;continue;}}else{r12Math.random()*5;thickness0.4;}r(Math.random()-0.5)*0.3;xr*Math.cos(angle);y(Math.random()-0.5)*thickness;zr*Math.sin(angle);consttilt0.4;consty_newy*Math.cos(tilt)-x*Math.sin(tilt);constx_newy*Math.sin(tilt)x*Math.cos(tilt);xx_new;yy_new;}}elseif(typelotus){constuMath.random()*Math.PI*2;constvMath.random();constpetals7;constrBase8*(0.50.5*Math.pow(Math.sin(petals*u*0.5),2))*v;xrBase*Math.cos(u);zrBase*Math.sin(u);y4*Math.pow(v,2)-2;if(iPARTICLE_COUNT*0.15){x(Math.random()-0.5);z(Math.random()-0.5);y(Math.random()-0.5)*10;}}elseif(typegalaxy){constarms3;constspini%arms;constangleOffset(spin/arms)*Math.PI*2;constdistMath.pow(Math.random(),0.5);constrdist*20;constangledist*10angleOffset;xr*Math.cos(angle);zr*Math.sin(angle);y(Math.random()-0.5)*(15-r)*0.2;if(r2)y*0.2;}pos[i*3]x;pos[i*31]y;pos[i*32]z;}returnpos;}functiongetShapeColors(type){constcolsnewFloat32Array(PARTICLE_COUNT*3);for(leti0;iPARTICLE_COUNT;i){letbrightness0.2Math.random()*0.8;letr,g,b;if(typesaturn){if(iPARTICLE_COUNT*SATURN_BODY_RATIO){r1.0;g0.7;b0.3;}else{r0.6;g0.8;b1.0;}r*brightness;g*brightness;b*brightness;}else{rbrightness;gbrightness;bbrightness;}cols[i*3]r;cols[i*31]g;cols[i*32]b;}returncols;}functioncreateParticleTexture(){constcanvasdocument.createElement(canvas);canvas.width32;canvas.height32;constcontextcanvas.getContext(2d);constgradientcontext.createRadialGradient(16,16,0,16,16,16);gradient.addColorStop(0,rgba(255,255,255,1));gradient.addColorStop(0.4,rgba(255,255,255,0.5));gradient.addColorStop(1,rgba(0,0,0,0));context.fillStylegradient;context.fillRect(0,0,32,32);returnnewTHREE.CanvasTexture(canvas);}functionanimate(){requestAnimationFrame(animate);consttimeclock.getElapsedTime();constpositionsparticles.geometry.attributes.position.array;constcolorsparticles.geometry.attributes.color.array;rotationVelocity.x*0.92;rotationVelocity.y*0.92;rotationVelocity.z*0.94;if(particles){particles.rotation.yrotationVelocity.y;particles.rotation.xrotationVelocity.x;particles.rotation.zrotationVelocity.z;}constlerpSpeed0.06;letscaleBaseisHandDetected?(0.2handInfluence*2.3):(1.0Math.sin(time*1.5)*0.05);for(leti0;iPARTICLE_COUNT;i){constidxi*3;lettxtargetPositions[idx];lettytargetPositions[idx1];lettztargetPositions[idx2];if(currentShapegalaxy){constangletime*(0.1(1.0-(Math.sqrt(tx*txtz*tz)/20))*0.5);constcosMath.cos(angle);constsinMath.sin(angle);constrxtx*cos-tz*sin;constrztx*sintz*cos;txrx;tzrz;}elseif(currentShapelotus){tyMath.sin(timetx)*0.5;}else{txMath.sin(time*2i)*0.05;tyMath.cos(time*3i)*0.05;}tx*scaleBase;ty*scaleBase;tz*scaleBase;positions[idx](tx-positions[idx])*lerpSpeed;positions[idx1](ty-positions[idx1])*lerpSpeed;positions[idx2](tz-positions[idx2])*lerpSpeed;if(targetColors.length0){colors[idx](targetColors[idx]-colors[idx])*0.03;colors[idx1](targetColors[idx1]-colors[idx1])*0.03;colors[idx2](targetColors[idx2]-colors[idx2])*0.03;}if(Math.random()0.9995){colors[idx]2.0;colors[idx1]2.0;colors[idx2]2.0;}if(colors[idx]1.5){colors[idx]*0.9;colors[idx1]*0.9;colors[idx2]*0.9;}}particles.geometry.attributes.position.needsUpdatetrue;particles.geometry.attributes.color.needsUpdatetrue;controls.update();composer.render();}asyncfunctionsetupMediaPipe(){constvideoElementdocument.getElementById(video-element);constcanvasElementdocument.getElementById(output-canvas);constcanvasCtxcanvasElement.getContext(2d);conststatusDotdocument.getElementById(status-dot);conststatusTextdocument.getElementById(status-text);// 获取之前被遗漏的手势提示元素constmodeScaleTextdocument.getElementById(mode-scale);constmodeRotateTextdocument.getElementById(mode-rotate);constmodeRollTextdocument.getElementById(mode-roll);consthandsnewHands({locateFile:(file)https://cdn.jsdelivr.net/npm/mediapipe/hands/${file}});hands.setOptions({maxNumHands:1,modelComplexity:0,minDetectionConfidence:0.5,minTrackingConfidence:0.5});hands.onResults((results){canvasCtx.save();canvasCtx.clearRect(0,0,canvasElement.width,canvasElement.height);canvasCtx.drawImage(results.image,0,0,canvasElement.width,canvasElement.height);if(results.multiHandLandmarksresults.multiHandLandmarks.length0){isHandDetectedtrue;statusDot.classNamew-2 h-2 rounded-full bg-cyan-400 shadow-[0_0_15px_cyan];statusText.innerTextLINK ESTABLISHED;statusText.classNametext-[10px] text-cyan-300 font-mono uppercase tracking-wider font-bold;constlandmarksresults.multiHandLandmarks[0];drawConnectors(canvasCtx,landmarks,HAND_CONNECTIONS,{color:#00ffff,lineWidth:2});drawLandmarks(canvasCtx,landmarks,{color:#ffffff,lineWidth:1,radius:3});constgetDist(i,j)Math.sqrt(Math.pow(landmarks[i].x-landmarks[j].x,2)Math.pow(landmarks[i].y-landmarks[j].y,2));constisIndexOpengetDist(8,0)getDist(5,0)*1.5;constisMiddleOpengetDist(12,0)getDist(9,0)*1.5;constisRingOpengetDist(16,0)getDist(13,0)*1.3;constisPinkyOpengetDist(20,0)getDist(17,0)*1.3;letdetectedModescale;if(isRingOpen||isPinkyOpen)detectedModescale;elseif(isIndexOpenisMiddleOpen)detectedModeroll;elseif(isIndexOpen!isMiddleOpen)detectedModerotate;if(detectedModecurrentStableMode)modeFrameCounter0;else{modeFrameCounter;if(modeFrameCounter8){currentStableModedetectedMode;modeFrameCounter0;isTrackingRollfalse;isTrackingRotatefalse;}}// 实时高亮当前模式[modeScaleText,modeRotateText,modeRollText].forEach(elel.classList.remove(active));if(currentStableModeroll)modeRollText.classList.add(active);elseif(currentStableModerotate)modeRotateText.classList.add(active);elsemodeScaleText.classList.add(active);if(currentStableModeroll){constdxlandmarks[8].x-landmarks[12].x;constdylandmarks[8].y-landmarks[12].y;constangleMath.atan2(dy,dx);if(!isTrackingRoll){previousRollAngleangle;isTrackingRolltrue;}else{letdeltaangle-previousRollAngle;if(deltaMath.PI)delta-2*Math.PI;if(delta-Math.PI)delta2*Math.PI;rotationVelocity.z-delta*0.15;previousRollAngleangle;}}elseif(currentStableModerotate){constcxlandmarks[8].x;constcylandmarks[8].y;if(!isTrackingRotate){lastCursorPos{x:cx,y:cy};isTrackingRotatetrue;}else{constdxcx-lastCursorPos.x;constdycy-lastCursorPos.y;rotationVelocity.y-dx*0.15;rotationVelocity.xdy*0.15;lastCursorPos{x:cx,y:cy};}}else{isTrackingRollfalse;isTrackingRotatefalse;lettotalDist0;[4,8,12,16,20].forEach(itotalDistgetDist(i,0));letopenAmt(totalDist/5-0.1)/(0.4-0.1);handInfluencelerp(handInfluence,Math.max(0,Math.min(1,openAmt)),0.1);}}else{isHandDetectedfalse;statusDot.classNamew-2 h-2 rounded-full bg-red-500 shadow-[0_0_10px_red];statusText.innerTextSCANNING...;statusText.classNametext-[10px] text-red-400 font-mono uppercase tracking-wider animate-pulse;handInfluencelerp(handInfluence,0.0,0.05);// 默认显示第一个模式[modeScaleText,modeRotateText,modeRollText].forEach(elel.classList.remove(active));modeScaleText.classList.add(active);}canvasCtx.restore();});constcameraUtilsnewCamera(videoElement,{onFrame:async(){awaithands.send({image:videoElement});},width:320,height:240});cameraUtils.start();videoElement.addEventListener(loadeddata,(){canvasElement.widthvideoElement.videoWidth;canvasElement.heightvideoElement.videoHeight;constloaderdocument.getElementById(loader-overlay);loader.style.opacity0;setTimeout(()loader.remove(),800);});}window.onWindowResize(){camera.aspectwindow.innerWidth/window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth,window.innerHeight);composer.setSize(window.innerWidth,window.innerHeight);};window.changeShape(shape){currentShapeshape;targetPositionsgetShapePositions(shape);targetColorsgetShapeColors(shape);if(shapesaturn){newTWEEN.Tween(particles.material.color).to({r:1,g:1,b:1},500).start();}else{newTWEEN.Tween(particles.material.color).to({r:userBaseColor.r,g:userBaseColor.g,b:userBaseColor.b},500).start();}document.querySelectorAll([data-shape]).forEach(btn{btn.classList.remove(active);if(btn.dataset.shapeshape)btn.classList.add(active);});};window.updateColor(hex){constcnewTHREE.Color(hex);userBaseColorc;document.getElementById(color-preview).style.backgroundColorhex;if(particlescurrentShape!saturn){particles.material.color.set(userBaseColor);}};window.toggleFullScreen(){if(!document.fullscreenElement)document.documentElement.requestFullscreen();elseif(document.exitFullscreen)document.exitFullscreen();};constTWEEN{Tween:function(obj){this.objobj;this.target{};this.duration1000;this.startTime0;this.tofunction(target,duration){this.targettarget;this.durationduration;returnthis;};this.startfunction(){this.startTimeperformance.now();this.initial{r:this.obj.r,g:this.obj.g,b:this.obj.b};requestAnimationFrame(this.update.bind(this));returnthis;};this.updatefunction(time){constelapsedtime-this.startTime;constprogressMath.min(elapsed/this.duration,1);constease1-Math.pow(1-progress,3);if(this.obj.r!undefined){this.obj.rthis.initial.r(this.target.r-this.initial.r)*ease;this.obj.gthis.initial.g(this.target.g-this.initial.g)*ease;this.obj.bthis.initial.b(this.target.b-this.initial.b)*ease;}if(progress1){requestAnimationFrame(this.update.bind(this));}};}};init();/script/body/html三、最初代版本的prompt用Three.js创建一个实时交互的3D粒子系统。 要求:1.通过摄像头检测双手张合控制粒子群的缩放与扩散2.提供UI面板可选择爱心/花朵/土星/佛像/玫瑰花等模型3.支持颜色选择器调整粒子颜色4.粒子需实时响应手势变化5.界面简洁现代包含全屏控制按钮四、手势控制原理在这个项目中手势识别和骨骼追踪的核心技术是由 Google 开发的 MediaPipe Hands 框架实现的。核心模型架构MediaPipe Hands。MediaPipe Hands 的后端其实包含了两个串行工作的深度学习模型(1)手掌检测模型 (Palm Detection Model)它的任务是分析全图找到手掌的位置画出一个框。因为手掌是刚体相对容易检测。这个模型只在第一帧或者系统跟丢手的时候才运行这大大节省了计算资源。(2)手部关键点模型 (Hand Landmark Model)它的任务是在手掌检测框内精准回归出 21 个 3D 关键点即手部的关节坐标。这些点包含了手腕、指关节、指尖等信息。