讨论

量子纠缠空间游戏

来自 Wikiprompt,自由的提示词百科全书

loshu2000

2026年5月17日

量子纠缠空间游戏 A prompt to build a single-file Three.js game where players match 3D particle clusters by spatial orientation, with physics-based fusion effects.

提示词内容收藏

🌐
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Quantum Entanglement</title> <style> body { margin: 0; overflow: hidden; font-family: 'Inter', system-ui, -apple-system, sans-serif; background: #f5f7fa; } #info { position: absolute; top: 20px; left: 50%; transform: translateX(-50%); background: rgba(255, 255, 255, 0.7); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-radius: 40px; padding: 12px 28px; color: #1a2b3c; font-weight: 400; letter-spacing: 0.3px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.06); border: 1px solid rgba(255, 255, 255, 0.9); z-index: 10; pointer-events: none; text-align: center; font-size: 0.95rem; backdrop-filter: blur(8px); white-space: nowrap; } #info span { font-weight: 600; color: #0f1c2b; } #status { position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); background: rgba(255, 255, 255, 0.6); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border-radius: 60px; padding: 10px 24px; color: #2c3e50; font-size: 0.9rem; border: 1px solid rgba(255, 255, 255, 0.8); box-shadow: 0 4px 20px rgba(0, 0, 0, 0.04); z-index: 10; pointer-events: none; letter-spacing: 0.2px; backdrop-filter: blur(8px); } #status strong { font-weight: 600; color: #1a2b3c; } canvas { display: block; } .instruction { position: absolute; bottom: 90px; left: 50%; transform: translateX(-50%); color: #5a6b7b; font-size: 0.8rem; background: rgba(255,255,255,0.4); padding: 6px 16px; border-radius: 40px; backdrop-filter: blur(4px); border: 1px solid rgba(255,255,255,0.5); pointer-events: none; white-space: nowrap; letter-spacing: 0.2px; } </style> </head> <body> <div id="info">🌀 <span>QUANTUM ENTANGLEMENT</span> , unfold two identical clusters</div> <div id="status">⚡ <strong>0</strong> / 2 matched</div> <div class="instruction">drag to rotate · click to unfold</div> <!-- three.js from CDN --> <script type="importmap"> { "imports": { "three": "https://unpkg.com/three@0.128.0/build/three.module.js", "three/addons/": "https://unpkg.com/three@0.128.0/examples/jsm/" } } </script> <script type="module"> import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js'; // --- setup scene, camera, renderers --- const scene = new THREE.Scene(); scene.background = new THREE.Color(0xf5f7fa); // pure white void with subtle tint const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(8, 6, 12); camera.lookAt(0, 0, 0); const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: false }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = false; renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); document.body.appendChild(renderer.domElement); // CSS2DRenderer for subtle labels (optional, but we use for clarity) const labelRenderer = new CSS2DRenderer(); labelRenderer.setSize(window.innerWidth, window.innerHeight); labelRenderer.domElement.style.position = 'absolute'; labelRenderer.domElement.style.top = '0px'; labelRenderer.domElement.style.left = '0px'; labelRenderer.domElement.style.pointerEvents = 'none'; document.body.appendChild(labelRenderer.domElement); // --- controls (for rotation via drag) --- const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.05; controls.autoRotate = false; controls.enableZoom = true; controls.rotateSpeed = 0.8; controls.target.set(0, 0, 0); controls.maxPolarAngle = Math.PI / 2; // --- lighting for frosted glass / transmission effect --- const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); scene.add(ambientLight); const dirLight = new THREE.DirectionalLight(0xffffff, 1.2); dirLight.position.set(5, 10, 7); scene.add(dirLight); const backLight = new THREE.DirectionalLight(0xe0f0ff, 0.8); backLight.position.set(-5, 0, -5); scene.add(backLight); // subtle fill const fillLight = new THREE.PointLight(0xffffff, 0.3); fillLight.position.set(0, 5, 5); scene.add(fillLight); // --- helper: create frosted glass material (transmission-like) --- function createFrostedMaterial(color = 0xffffff, opacity = 0.35) { return new THREE.MeshPhysicalMaterial({ color: color, metalness: 0.1, roughness: 0.25, transmission: 0.9, thickness: 0.5, transparent: true, opacity: opacity, clearcoat: 0.1, clearcoatRoughness: 0.4, envMapIntensity: 1.0, specularIntensity: 0.3, side: THREE.DoubleSide }); } // --- data: define 6 clusters with unique geometric patterns (some identical) --- // each cluster: geometry type, size, color, and a signature (orientation + topology) // we will use quaternion orientation stored as euler for simplicity, but we compare using quaternion dot. // For matching, we need identical topology AND orientation (within tolerance) // We'll create 6 clusters: 3 pairs (identical topology+orientation) // Each cluster has a "signature" = geometry type + rotation (euler) + scale (uniform) // To make it interesting, we use different geometries: Icosahedron, Octahedron, TorusKnot, etc. // But we need pairs: so we duplicate geometry+rotation+scale. // Define cluster prototypes const prototypes = [ { geo: 'icosa', scale: 1.0, color: 0xc0e0ff, euler: [0.5, 0.2, 0.1] }, // pair A { geo: 'octa', scale: 0.9, color: 0xffd9b0, euler: [0.1, 0.8, 0.3] }, // pair B { geo: 'torus', scale: 0.8, color: 0xd0f0c0, euler: [0.3, 0.4, 0.9] } // pair C ]; // Create 6 clusters: two of each prototype const clusters = []; const clusterGroup = new THREE.Group(); scene.add(clusterGroup); // positions arranged in a loose 3D grid const positions = [ [-2.5, 1.2, -1.5], [2.5, 1.0, 1.8], [-2.0, -1.5, 2.2], [2.2, -1.2, -2.0], [0.5, 2.0, -2.5], [-0.8, -2.0, -0.5] ]; // store cluster data for interaction const clusterData = []; // helper to create geometry based on type function makeGeometry(type, scale) { let geo; switch(type) { case 'icosa': geo = new THREE.IcosahedronGeometry(1.0, 0); break; case 'octa': geo = new THREE.OctahedronGeometry(1.0, 0); break; case 'torus': geo = new THREE.TorusKnotGeometry(0.7, 0.25, 64, 8, 2, 3); break; default: geo = new THREE.IcosahedronGeometry(1.0, 0); } return geo; } // create clusters prototypes.forEach((proto, idx) => { for (let copy = 0; copy < 2; copy++) { const pos = positions[clusterData.length]; const geo = makeGeometry(proto.geo, proto.scale); const mat = createFrostedMaterial(proto.color, 0.4); const mesh = new THREE.Mesh(geo, mat); mesh.scale.set(proto.scale, proto.scale, proto.scale); mesh.position.set(pos[0], pos[1], pos[2]); // set rotation from euler const euler = new THREE.Euler(proto.euler[0], proto.euler[1], proto.euler[2], 'XYZ'); mesh.quaternion.setFromEuler(euler); // store signature: we use quaternion + geometry type + scale as signature const signature = { geoType: proto.geo, scale: proto.scale, quat: mesh.quaternion.clone(), color: proto.color }; // add to scene clusterGroup.add(mesh); // store data clusterData.push({ mesh: mesh, signature: signature, unfolded: false, matched: false, originalPos: mesh.position.clone(), originalQuat: mesh.quaternion.clone(), // for animation velocity: new THREE.Vector3(), isImploding: false, implodeTarget: null }); } }); // add some floating particles for atmosphere (volumetric light trails effect) const particleGeo = new THREE.BufferGeometry(); const particleCount = 400; const particlePos = new Float32Array(particleCount * 3); for (let i = 0; i < particleCount * 3; i += 3) { particlePos[i] = (Math.random() - 0.5) * 20; particlePos[i+1] = (Math.random() - 0.5) * 15; particlePos[i+2] = (Math.random() - 0.5) * 20; } particleGeo.setAttribute('position', new THREE.BufferAttribute(particlePos, 3)); const particleMat = new THREE.PointsMaterial({ color: 0x88aaff, size: 0.08, transparent: true, opacity: 0.25, blending: THREE.AdditiveBlending }); const particles = new THREE.Points(particleGeo, particleMat); scene.add(particles); // light trails (simple lines) const trailMat = new THREE.LineBasicMaterial({ color: 0x88aaff, opacity: 0.15, transparent: true }); for (let i = 0; i < 12; i++) { const points = []; const start = new THREE.Vector3((Math.random()-0.5)*8, (Math.random()-0.5)*6, (Math.random()-0.5)*8); const end = new THREE.Vector3((Math.random()-0.5)*8, (Math.random()-0.5)*6, (Math.random()-0.5)*8); points.push(start, end); const lineGeo = new THREE.BufferGeometry().setFromPoints(points); const line = new THREE.Line(lineGeo, trailMat); scene.add(line); } // --- interaction state --- let selectedCluster = null; // currently unfolded cluster (first) let matchCount = 0; const statusEl = document.querySelector('#status strong'); // raycasting const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); // click handler renderer.domElement.addEventListener('click', (event) => { // compute mouse pos mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(mouse, camera); const meshes = clusterData.filter(d => !d.matched).map(d => d.mesh); const intersects = raycaster.intersectObjects(meshes); if (intersects.length > 0) { const hitMesh = intersects[0].object; const data = clusterData.find(d => d.mesh === hitMesh); if (!data || data.matched) return; // toggle unfold: if already unfolded, ignore (or we can allow re-click to deselect? but spec says unfold) if (!data.unfolded) { // unfold: scale up slightly and change opacity? we'll animate scale data.unfolded = true; // animate scale to 1.3x data.mesh.scale.multiplyScalar(1.3); // change emissive? not needed // if no selected cluster, set as first if (!selectedCluster) { selectedCluster = data; } else { // we have two unfolded clusters -> check match const first = selectedCluster; const second = data; // compare signatures: geometry type, scale, and quaternion orientation (dot product) const sig1 = first.signature; const sig2 = second.signature; // topology: geometry type and scale const topologyMatch = (sig1.geoType === sig2.geoType) && (Math.abs(sig1.scale - sig2.scale) < 0.01); // orientation: quaternion dot product absolute value close to 1 (within tolerance) const quatDot = Math.abs(sig1.quat.dot(sig2.quat)); const orientationMatch = quatDot > 0.98; // allow small tolerance if (topologyMatch && orientationMatch) { // MATCH! trigger implosion effect triggerImplosion(first, second); // mark both as matched first.matched = true; second.matched = true; matchCount += 2; statusEl.textContent = matchCount; // reset selected selectedCluster = null; // if all matched (6 clusters -> 3 pairs) -> show win if (matchCount === 6) { setTimeout(() => { alert('✨ Entanglement achieved! All clusters fused.'); }, 300); } } else { // mismatch: reset unfold (scale back) and clear selection first.unfolded = false; second.unfolded = false; first.mesh.scale.multiplyScalar(1/1.3); second.mesh.scale.multiplyScalar(1/1.3); selectedCluster = null; } } } else { // if already unfolded, clicking again could deselect? but we keep simple: ignore // optionally we could allow toggling off, but spec says unfold, so we keep. } } }); // --- implosion effect: create particles and destroy meshes --- function triggerImplosion(clusterA, clusterB) { // create particle burst at midpoint const mid = new THREE.Vector3().addVectors(clusterA.mesh.position, clusterB.mesh.position).multiplyScalar(0.5); // create 60 particles const particleCount = 80; const positions = new Float32Array(particleCount * 3); const colors = new Float32Array(particleCount * 3); const velocities = []; for (let i = 0; i < particleCount; i++) { // random direction const theta = Math.random() * Math.PI * 2; const phi = Math.acos(2 * Math.random() - 1); const r = 0.5 + Math.random() * 1.5; const x = mid.x + r * Math.sin(phi) * Math.cos(theta); const y = mid.y + r * Math.sin(phi) * Math.sin(theta); const z = mid.z + r * Math.cos(phi); positions[i*3] = x; positions[i*3+1] = y; positions[i*3+2] = z; // color: white/blue colors[i*3] = 0.8 + 0.2 * Math.random(); colors[i*3+1] = 0.9 + 0.1 * Math.random(); colors[i*3+2] = 1.0; // velocity towards mid (implosion) const dir = new THREE.Vector3(mid.x - x, mid.y - y, mid.z - z).normalize(); const speed = 0.08 + Math.random() * 0.1; velocities.push(dir.multiplyScalar(speed)); } const pGeo = new THREE.BufferGeometry(); pGeo.setAttribute('position', new THREE.BufferAttribute(positions, 3)); pGeo.setAttribute('color', new THREE.BufferAttribute(colors, 3)); const pMat = new THREE.PointsMaterial({ size: 0.12, vertexColors: true, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false }); const particleSystem = new THREE.Points(pGeo, pMat); scene.add(particleSystem); // animate particles: move towards mid and shrink const startPositions = positions.slice(); let frame = 0; const maxFrames = 60; function animateParticles() { frame++; const posAttr = particleSystem.geometry.attributes.position; const posArray = posAttr.array; for (let i = 0; i < particleCount; i++) { // move towards mid const idx = i*3; const dx = mid.x - posArray[idx]; const dy = mid.y - posArray[idx+1]; const dz = mid.z - posArray[idx+2]; const dist = Math.sqrt(dx*dx + dy*dy + dz*dz); if (dist > 0.01) { const speed = 0.1; posArray[idx] += dx * speed; posArray[idx+1] += dy * speed; posArray[idx+2] += dz * speed; } } posAttr.needsUpdate = true; // shrink size pMat.size = Math.max(0.02, 0.12 * (1 - frame/maxFrames)); if (frame < maxFrames) { requestAnimationFrame(animateParticles); } else { scene.remove(particleSystem); pGeo.dispose(); pMat.dispose(); } } animateParticles(); // destroy meshes (hide them) clusterA.mesh.visible = false; clusterB.mesh.visible = false; // also remove from clusterData? but we keep for reference } // --- animation loop --- function animate() { requestAnimationFrame(animate); // subtle rotation of particles particles.rotation.y += 0.0002; // update controls controls.update(); // render renderer.render(scene, camera); labelRenderer.render(scene, camera); } animate(); // --- resize handler --- window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); labelRenderer.setSize(window.innerWidth, window.innerHeight); }); // --- add some floating glow lines (volumetric light trails) --- // (already added some lines, but we can add more dynamic ones) // we'll add a few more lines with additive blending for (let i = 0; i < 8; i++) { const points = []; const start = new THREE.Vector3((Math.random()-0.5)*12, (Math.random()-0.5)*8, (Math.random()-0.5)*12); const end = new THREE.Vector3((Math.random()-0.5)*12, (Math.random()-0.5)*8, (Math.random()-0.5)*12); points.push(start, end); const lineGeo = new THREE.BufferGeometry().setFromPoints(points); const lineMat = new THREE.LineBasicMaterial({ color: 0xccddff, opacity: 0.1, transparent: true }); const line = new THREE.Line(lineGeo, lineMat); scene.add(line); } // small floating orbs for ambiance const orbGeo = new THREE.SphereGeometry(0.08, 6, 6); const orbMat = new THREE.MeshStandardMaterial({ color: 0xffffff, emissive: 0x88aaff, emissiveIntensity: 0.3 }); for (let i = 0; i < 20; i++) { const orb = new THREE.Mesh(orbGeo, orbMat); orb.position.set((Math.random()-0.5)*14, (Math.random()-0.5)*10, (Math.random()-0.5)*14); scene.add(orb); } // final touch: add a faint grid or void? keep pure white. console.log('Quantum Entanglement ready.'); </script> </body> </html>

登录以查看完整提示词

继续使用:

登录即表示你同意我们的 使用条款 和 隐私政策

用法

此提示词专为 coding 设计。复制上方内容并粘贴到你常用的 AI 工具中。

为获得最佳效果,可将占位符(方括号或大写字母标示)替换为你的具体需求。

参考资料

分类:coding| prompts.chat| three-js| web-game

讨论