Filter
Exclude
Time range
-
Near
Source code for the music visualiser: <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Enhanced Electric Wave Visualizer</title> <script src="cdn.tailwindcss.com"></script> <style> body { margin: 0; overflow: hidden; background-color: #020204; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; color: #ffffff; } .glass-panel { background: rgba(15, 15, 20, 0.45); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); border: 1px solid rgba(255, 255, 255, 0.08); box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5), inset 0 0 0 1px rgba(255,255,255,0.02); } .glass-btn { background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.08); color: #ffffff; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); display: flex; align-items: center; justify-content: center; } .glass-btn:hover { background: rgba(255, 255, 255, 0.1); border-color: rgba(255, 255, 255, 0.2); transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0,0,0,0.3); } .glass-btn:active { transform: translateY(0); background: rgba(255, 255, 255, 0.05); } input[type=range] { -webkit-appearance: none; background: rgba(255, 255, 255, 0.1); height: 3px; border-radius: 2px; outline: none; transition: background 0.3s ease; } input[type=range]:hover { background: rgba(255, 255, 255, 0.2); } input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; width: 10px; height: 10px; border-radius: 50%; background: #fff; cursor: pointer; box-shadow: 0 0 10px rgba(255,255,255,0.8); transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1); } input[type=range]::-webkit-slider-thumb:hover { transform: scale(1.4); } input[type="file"] { display: none; } #canvas-container { position: absolute; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 0; } #drop-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.8); backdrop-filter: blur(10px); z-index: 100; display: flex; flex-direction: column; align-items: center; justify-content: center; opacity: 0; pointer-events: none; transition: opacity 0.3s ease; border: 4px dashed rgba(255,255,255,0.2); margin: 10px; border-radius: 20px; } #drop-overlay.active { opacity: 1; } .marquee-container { overflow: hidden; white-space: nowrap; mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent); -webkit-mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent); } .marquee { display: inline-block; animation: marquee 10s linear infinite; } @keyframes marquee { 0% { transform: translateX(100%); } 100% { transform: translateX(-100%); } } </style> <script type="importmap"> { "imports": { "three": "cdn.jsdelivr.net/npm/three@0…", "three/addons/": "cdn.jsdelivr.net/npm/three@0…" } } </script> <div id="canvas-container"></div> <div id="drop-overlay"> <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="mb-4 text-white/70"> <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path> <polyline points="17 8 12 3 7 8"></polyline> <line x1="12" y1="3" x2="12" y2="15"></line> </svg> <h2 class="text-2xl font-light tracking-wider">Drop Audio File Here</h2> </div> <div class="fixed bottom-4 left-1/2 -translate-x-1/2 flex flex-col p-2.5 rounded-xl glass-panel z-50 w-[85%] max-w-[240px] gap-2"> <div class="flex items-center gap-2 w-full"> <span id="currentTime" class="text-[9px] text-white/50 font-mono w-7 text-right">0:00</span> <input type="range" id="progressSlider" value="0" min="0" max="100" step="0.1" class="flex-1 w-full cursor-pointer"> <span id="totalTime" class="text-[9px] text-white/50 font-mono w-7 text-left">0:00</span> </div> <div class="flex items-center justify-center gap-3"> <label class="glass-btn w-7 h-7 rounded-full cursor-pointer" title="Upload Audio"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg> <input type="file" id="fileInput" accept="audio/*"> </label> <button id="playPauseBtn" class="glass-btn w-9 h-9 rounded-full mx-1" title="Play/Pause"> <svg id="playIcon" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" style="margin-left: 2px;"><polygon points="5 3 19 12 5 21 5 3"/></svg> <svg id="pauseIcon" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="hidden"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg> </button> <button id="stopBtn" class="glass-btn w-7 h-7 rounded-full" title="Stop"> <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/></svg> </button> </div> </div> <script type="module"> import * as THREE from 'three'; import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js'; let audioCtx, analyser, source; let isPlaying = false; let isDraggingSlider = false; let bassIntensity = 0; let targetBloom = 2.2; const audio = new Audio(); audio.crossOrigin = "anonymous"; const progressSlider = document.getElementById('progressSlider'); const currentTimeEl = document.getElementById('currentTime'); const totalTimeEl = document.getElementById('totalTime'); const playIcon = document.getElementById('playIcon'); const pauseIcon = document.getElementById('pauseIcon'); const formatTime = (timeInSeconds) => { if (isNaN(timeInSeconds)) return "0:00"; const m = Math.floor(timeInSeconds / 60); const s = Math.floor(timeInSeconds % 60); return `${m}:${s < 10 ? '0' : ''}${s}`; }; const dataArray = new Uint8Array(256); const audioTexture = new THREE.DataTexture(dataArray, 256, 1, THREE.RedFormat, THREE.UnsignedByteType); const initAudio = () => { if (!audioCtx) { audioCtx = new (window.AudioContext || window.webkitAudioContext)(); analyser = audioCtx.createAnalyser(); analyser.fftSize = 512; analyser.smoothingTimeConstant = 0.85; source = audioCtx.createMediaElementSource(audio); source.connect(analyser); analyser.connect(audioCtx.destination); } if (audioCtx.state === 'suspended') { audioCtx.resume(); } }; const loadAudioFile = (file) => { initAudio(); const objectUrl = URL.createObjectURL(file); audio.src = objectUrl; playAudio(); }; const playAudio = () => { initAudio(); if (audio.src) { audio.play(); isPlaying = true; playIcon.classList.add('hidden'); pauseIcon.classList.remove('hidden'); } }; const pauseAudio = () => { if (audio.src) { audio.pause(); isPlaying = false; playIcon.classList.remove('hidden'); pauseIcon.classList.add('hidden'); } }; const stopAudio = () => { if (audio.src) { audio.pause(); audio.currentTime = 0; isPlaying = false; playIcon.classList.remove('hidden'); pauseIcon.classList.add('hidden'); dataArray.fill(0); audioTexture.image.data.set(dataArray); audioTexture.needsUpdate = true; progressSlider.value = 0; currentTimeEl.textContent = "0:00"; } }; document.getElementById('fileInput').addEventListener('change', function(e) { if (this.files.length > 0) loadAudioFile(this.files[0]); }); document.getElementById('playPauseBtn').addEventListener('click', () => { isPlaying ? pauseAudio() : playAudio(); }); document.getElementById('stopBtn').addEventListener('click', stopAudio); const dropOverlay = document.getElementById('drop-overlay'); ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { window.addEventListener(eventName, preventDefaults, false); }); function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } window.addEventListener('dragenter', () => dropOverlay.classList.add('active')); window.addEventListener('dragleave', (e) => { if (e.relatedTarget === null) dropOverlay.classList.remove('active'); }); window.addEventListener('drop', (e) => { dropOverlay.classList.remove('active'); let dt = e.dataTransfer; let files = dt.files; if (files.length && files[0].type.startsWith('audio/')) { loadAudioFile(files[0]); } }); audio.addEventListener('timeupdate', () => { if (audio.duration && !isDraggingSlider) { progressSlider.value = (audio.currentTime / audio.duration) * 100; currentTimeEl.textContent = formatTime(audio.currentTime); } }); audio.addEventListener('loadedmetadata', () => { totalTimeEl.textContent = formatTime(audio.duration); }); audio.addEventListener('ended', stopAudio); progressSlider.addEventListener('input', (e) => { isDraggingSlider = true; if (audio.duration) { currentTimeEl.textContent = formatTime((e.target.value / 100) * audio.duration); } }); progressSlider.addEventListener('change', (e) => { if (audio.duration) { audio.currentTime = (e.target.value / 100) * audio.duration; } isDraggingSlider = false; }); const container = document.getElementById('canvas-container'); const scene = new THREE.Scene(); scene.fog = new THREE.FogExp2(0x020204, 0.03); const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100); camera.position.set(0, 0, 12); let targetCameraX = 0; let targetCameraY = 0; const renderer = new THREE.WebGLRenderer({ antialias: false, powerPreference: "high-performance" }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.setClearColor(0x020204); container.appendChild(renderer.domElement); const renderScene = new RenderPass(scene, camera); const bloomPass = new UnrealBloomPass( new THREE.Vector2(window.innerWidth, window.innerHeight), 1.8, 1.2, 0.05 ); const composer = new EffectComposer(renderer); composer.addPass(renderScene); composer.addPass(bloomPass); const particleCount = 800; const pGeometry = new THREE.BufferGeometry(); const pPositions = new Float32Array(particleCount * 3); const pSizes = new Float32Array(particleCount); for(let i=0; i < particleCount; i ) { pPositions[i*3] = (Math.random() - 0.5) * 40; pPositions[i*3 1] = (Math.random() - 0.5) * 20; pPositions[i*3 2] = (Math.random() - 0.5) * 30 - 5; pSizes[i] = Math.random(); } pGeometry.setAttribute('position', new THREE.BufferAttribute(pPositions, 3)); pGeometry.setAttribute('aSize', new THREE.BufferAttribute(pSizes, 1)); const pMaterial = new THREE.ShaderMaterial({ uniforms: { uTime: { value: 0 }, uBass: { value: 0 } }, vertexShader: ` uniform float uTime; uniform float uBass; attribute float aSize; varying float vAlpha; varying vec3 vPos; void main() { vec3 pos = position; pos.x = sin(uTime * 0.2 pos.y) * 0.5; pos.y = cos(uTime * 0.15 pos.x) * 0.5; vPos = pos; vec4 mvPosition = modelViewMatrix * vec4(pos, 1.0); gl_PointSize = aSize * (15.0 uBass * 40.0) * (1.0 / -mvPosition.z); vAlpha = aSize * 0.6 (uBass * 0.6); gl_Position = projectionMatrix * mvPosition; } `, fragmentShader: ` varying float vAlpha; varying vec3 vPos; void main() { float dist = length(gl_PointCoord - vec2(0.5)); if (dist > 0.5) discard; float alpha = (0.5 - dist) * 2.0 * vAlpha; vec3 color1 = vec3(0.0, 0.8, 1.0); vec3 color2 = vec3(1.0, 0.2, 0.8); vec3 color = mix(color1, color2, sin(vPos.x * 0.1 vPos.y * 0.2) * 0.5 0.5); gl_FragColor = vec4(color, alpha * 0.4); } `, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false }); const particles = new THREE.Points(pGeometry, pMaterial); scene.add(particles); const vertexShader = ` uniform float uTime; uniform float uOffset; uniform sampler2D uAudioTex; varying vec2 vUv; varying float vAudio; float random (in vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123); } float noise (in vec2 st) { vec2 i = floor(st); vec2 f = fract(st); float a = random(i); float b = random(i vec2(1.0, 0.0)); float c = random(i vec2(0.0, 1.0)); float d = random(i vec2(1.0, 1.0)); vec2 u = f*f*(3.0-2.0*f); return mix(a, b, u.x) (c - a)* u.y * (1.0 - u.x) (d - b) * u.x * u.y; } void main() { vUv = uv; float freqPos = abs(uv.x - 0.5) * 2.0; float audio = texture2D(uAudioTex, vec2(freqPos, 0.0)).r; vAudio = audio; vec3 pos = position; float t = uTime uOffset; float idle = sin(uv.x * 5.0 t * 0.8) * 0.2 noise(vec2(uv.x * 6.0, t * 0.4)) * 0.3 - 0.15; float energy1 = (noise(vec2(uv.x * 15.0, t * 3.0)) - 0.5) * 2.5; float energy2 = (noise(vec2(uv.x * 30.0, t * 6.0)) - 0.5) * 1.5; float sharpNoise = (abs(noise(vec2(uv.x * 45.0, t * 10.0)) - 0.5)) * 1.2; float displacement = idle (energy1 energy2 sharpNoise) * pow(audio, 1.5) * 2.5; float taper = smoothstep(0.0, 0.15, uv.x) * smoothstep(1.0, 0.85, uv.x); pos.y = displacement * taper; float zDisplacement = sin(uv.x * 12.0 t * 1.5) * 1.2 * audio; pos.z = zDisplacement * taper; gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0); } `; const fragmentShader = ` uniform float uTime; uniform float uReflection; uniform vec3 uBaseColor; uniform float uThickness; uniform float uBassBoost; varying vec2 vUv; varying float vAudio; void main() { float dynamicThickness = uThickness * (1.0 vAudio * 0.5); float core = 1.0 - abs(vUv.y - 0.5) * (2.0 / dynamicThickness); core = pow(max(core, 0.0), 2.0); float energy = vAudio uBassBoost * 0.5; float glow = core * (1.0 energy * 3.5); vec3 finalColor = mix(uBaseColor, uBaseColor vec3(0.35), core * energy * 0.5); finalColor *= glow * uReflection; float fadeX = smoothstep(0.0, 0.05, vUv.x) * smoothstep(1.0, 0.95, vUv.x); gl_FragColor = vec4(finalColor, core * uReflection * fadeX); } `; const baseUniforms = { uTime: { value: 0 }, uAudioTex: { value: audioTexture }, uReflection: { value: 1.0 }, uOffset: { value: 0.0 }, uBaseColor: { value: new THREE.Color(0xffffff) }, uThickness: { value: 1.0 }, uBassBoost: { value: 0.0 } }; const material = new THREE.ShaderMaterial({ vertexShader, fragmentShader, uniforms: baseUniforms, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false, side: THREE.DoubleSide }); const geometry = new THREE.PlaneGeometry(38, 0.1, 700, 1); const allWaves = []; const waveConfigs = [ { offset: 0.0, color: new THREE.Color(0x00d2ff), thickness: 1.3, y: 0.8 }, { offset: 20.4, color: new THREE.Color(0xff007f), thickness: 0.7, y: 1.0 }, { offset: 45.2, color: new THREE.Color(0x7000ff), thickness: 0.35, y: 0.6 }, { offset: 60.5, color: new THREE.Color(0x00ff88), thickness: 0.15, y: 0.9 } ]; waveConfigs.forEach(config => { const mat = material.clone(); mat.uniforms = { ...baseUniforms, uOffset: { value: config.offset }, uBaseColor: { value: config.color }, uThickness: { value: config.thickness }, uReflection: { value: 1.0 } }; const wave = new THREE.Mesh(geometry, mat); wave.position.y = config.y; scene.add(wave); allWaves.push(wave); const refMat = mat.clone(); refMat.uniforms = { ...mat.uniforms, uReflection: { value: 0.35 } }; const refWave = new THREE.Mesh(geometry, refMat); refWave.position.y = -config.y - 0.05; refWave.scale.y = -1.0; scene.add(refWave); allWaves.push(refWave); }); const floorGeo = new THREE.PlaneGeometry(60, 20); const floorMat = new THREE.MeshBasicMaterial({ color: 0x010102, transparent: true, opacity: 0.7, depthWrite: false }); const glassFloor = new THREE.Mesh(floorGeo, floorMat); glassFloor.rotation.x = -Math.PI / 2; glassFloor.position.y = 0; scene.add(glassFloor); document.addEventListener('mousemove', (e) => { const x = (e.clientX / window.innerWidth) * 2 - 1; const y = -(e.clientY / window.innerHeight) * 2 1; targetCameraX = x * 2.0; targetCameraY = y * 1.0; }); const clock = new THREE.Clock(); function animate() { requestAnimationFrame(animate); const time = clock.getElapsedTime(); camera.position.x = (targetCameraX - camera.position.x) * 0.03; camera.position.y = (targetCameraY - camera.position.y) * 0.03; camera.lookAt(0, 0, 0); if (isPlaying && analyser) { analyser.getByteFrequencyData(dataArray); audioTexture.image.data.set(dataArray); audioTexture.needsUpdate = true; let bassSum = 0; for(let i=0; i<10; i ) bassSum = dataArray[i]; const newBass = (bassSum / 10.0) / 255.0; bassIntensity = (newBass - bassIntensity) * 0.2; targetBloom = 1.8 bassIntensity * 3.5; } else { bassIntensity *= 0.95; targetBloom = 1.8; } bloomPass.strength = (targetBloom - bloomPass.strength) * 0.1; allWaves.forEach(wave => { wave.material.uniforms.uTime.value = time; wave.material.uniforms.uAudioTex.value = audioTexture; wave.material.uniforms.uBassBoost.value = bassIntensity; }); pMaterial.uniforms.uTime.value = time; pMaterial.uniforms.uBass.value = bassIntensity; composer.render(); } window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); composer.setSize(window.innerWidth, window.innerHeight); }); animate(); </script>

9
667
🍆この術式のコードはこちら↓ <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>虚式「茈」滞留ver</title> <style> body { margin: 0; background-color: #050505; overflow: hidden; font-family: 'Helvetica Neue', Arial, sans-serif; color: white; } #canvas-wrapper { position: relative; width: 100vw; height: 100vh; } canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } #three-canvas { z-index: 1; } #debug-canvas { z-index: 2; pointer-events: none; opacity: 0; transition: opacity 0.3s; } #ui { position: absolute; top: 30px; left: 0; width: 100%; text-align: center; z-index: 10; pointer-events: none; text-shadow: 0 0 15px black; display: flex; flex-direction: column; align-items: center; } /* タイトル装飾 */ h1 { margin: 0; font-size: 28px; font-weight: 900; letter-spacing: 1px; line-height: 1.4; } .blue { color: #0088ff; text-shadow: 0 0 10px #0088ff; } .red { color: #ff0055; text-shadow: 0 0 10px #ff0055; } .purple { color: #d946ef; text-shadow: 0 0 20px #d946ef; font-size: 32px; } .connector { color: #aaa; font-weight: normal; margin: 0 10px; } .mode-badge { display: inline-block; padding: 8px 20px; border-radius: 30px; background: rgba(0,0,0,0.7); border: 2px solid #555; margin-top: 20px; font-weight: bold; transition: all 0.3s; font-size: 14px; } .instruction { font-size: 14px; margin-top: 10px; color: #ccc; line-height: 1.6; } .highlight { color: #ffdd00; font-weight: bold; } .controls { pointer-events: auto; margin-top: 20px; opacity: 0.7; hover: opacity: 1; } button { background: #222; color: #aaa; border: 1px solid #444; padding: 8px 12px; cursor: pointer; border-radius: 4px; font-size: 12px; transition: all 0.2s; } button:hover { background: #444; color: white; } button.active { background: #4ade80; color: black; border-color: #4ade80; } #loading { position: absolute; inset: 0; background: #000; z-index: 100; display: flex; flex-direction: column; align-items: center; justify-content: center; color: #d946ef; } .spinner { width: 60px; height: 60px; border: 6px solid #333; border-top-color: #d946ef; border-radius: 50%; animation: spin 1s linear infinite; margin-bottom: 25px; } @keyframes spin { to { transform: rotate(360deg); } } </style> <script type="importmap"> { "imports": { "three": "unpkg.com/three@0.160.0/buil…", "three/addons/": "unpkg.com/three@0.160.0/exam…", "@mediapipe/tasks-vision": "cdn.jsdelivr.net/npm/@mediap…" } } </script> </head> <body> <div id="loading"> <div class="spinner"></div> <div style="letter-spacing: 2px; font-weight: bold;">術式展開中...</div> </div> <div id="ui"> <h1> <span class="blue">術式順転「蒼」</span><span class="connector">+</span><span class="red">術式反転「赫」</span><br> <span class="connector">=</span><span class="purple">虚式「茈」</span> </h1> <div id="mode-text" class="mode-badge" style="color:#aaa; border-color:#aaa;">術式対象を探索中</div> <div class="instruction"> <div>左右の手でサイズ操作: <span class="highlight">つまむ(小)</span> / <span class="highlight">パー(大)</span></div> <div>両手を合わせ「茈」を生成し、<span class="highlight">両手を握って</span>発動せよ</div> </div> <div class="controls"> <button id="btn-debug" onclick="toggleDebug()">👁 術式開示 (SKELETON)</button> </div> </div> <div id="canvas-wrapper"> <canvas id="three-canvas"></canvas> <canvas id="debug-canvas"></canvas> </div> <video id="webcam" autoplay playsinline style="display:none; transform: scaleX(-1);"></video> <script type="module"> import * as THREE from 'three'; import { FilesetResolver, HandLandmarker } from '@mediapipe/tasks-vision'; // --- 設定 (物理演算を微調整) --- const CONFIG = { particleCount: 40000, smoothFactor: 0.1, mergeDist: 3.5, // 爆発・滞留設定 explodeForce: 2.0, // 初速 (かなり強く設定して一気に広げる) drag: 0.95, // 摩擦係数 (1未満にすることで急減速し、滞留させる) turbulence: 0.015, // 乱気流 (フワフワ漂う動きの強さ) explodeDuration: 10000,// 滞留時間 (10秒) // サイズ設定 scalePinch: 0.5, scaleNormal: 1.0, scaleOpen: 1.5, scaleMerge: 2.0 }; const COLOR_LEFT = new THREE.Color('#0088ff'); // 蒼 const COLOR_RIGHT = new THREE.Color('#ff0055'); // 赫 const COLOR_MERGE = new THREE.Color('#d946ef'); // 茈 // --- グローバル変数 --- let scene, camera, renderer, particles, geometry; let positionsOriginal; let velocities; let handLandmarker; let video = document.getElementById('webcam'); let debugCanvas = document.getElementById('debug-canvas'); let debugCtx = debugCanvas.getContext('2d'); let showDebug = false; // --- 状態管理 --- const targetState = { left: { x: -10, y: 0, visible: false, pinch: false, open: false }, right: { x: 10, y: 0, visible: false, pinch: false, open: false }, isMergedTrigger: false, centerX: 0, centerY: 0 }; const currentProps = { leftPos: new THREE.Vector3(-10, 0, 0), rightPos: new THREE.Vector3(10, 0, 0), leftScale: 0, rightScale: 0, leftColor: new THREE.Color(), rightColor: new THREE.Color(), }; let appMode = 'NORMAL'; async function init() { initThree(); await initMediaPipe(); startCamera(); animate(); } function initThree() { const canvas = document.getElementById('three-canvas'); scene = new THREE.Scene(); scene.fog = new THREE.FogExp2(0x050505, 0.002); camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100); camera.position.z = 14; renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true, alpha: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(window.devicePixelRatio); positionsOriginal = new Float32Array(CONFIG.particleCount * 3); const currentPositions = new Float32Array(CONFIG.particleCount * 3); const colors = new Float32Array(CONFIG.particleCount * 3); velocities = new Float32Array(CONFIG.particleCount * 3); for (let i = 0; i < CONFIG.particleCount; i ) { const r = 2.5; const theta = Math.random() * Math.PI * 2; const phi = Math.acos((Math.random() * 2) - 1); const x = r * Math.sin(phi) * Math.cos(theta); const y = r * Math.sin(phi) * Math.sin(theta); const z = r * Math.cos(phi); positionsOriginal[i * 3] = x; positionsOriginal[i * 3 1] = y; positionsOriginal[i * 3 2] = z; currentPositions[i] = 999; } geometry = new THREE.BufferGeometry(); geometry.setAttribute('position', new THREE.BufferAttribute(currentPositions, 3)); geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3)); const material = new THREE.PointsMaterial({ size: 0.08, vertexColors: true, blending: THREE.AdditiveBlending, transparent: true, opacity: 0.8, depthWrite: false }); particles = new THREE.Points(geometry, material); scene.add(particles); const handleResize = () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); debugCanvas.width = window.innerWidth; debugCanvas.height = window.innerHeight; }; window.addEventListener('resize', handleResize); handleResize(); } async function initMediaPipe() { const vision = await FilesetResolver.forVisionTasks("cdn.jsdelivr.net/npm/@mediap…"); handLandmarker = await HandLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: `storage.googleapis.com/media…`, delegate: "GPU" }, runningMode: "VIDEO", numHands: 2 }); document.getElementById('loading').style.display = 'none'; } function startCamera() { navigator.mediaDevices.getUserMedia({ video: { width: 640, height: 480 } }) .then(stream => video.srcObject = stream) .catch(e => console.error(e)); } function animate() { requestAnimationFrame(animate); updateHandDetection(); updatePhysics(); renderParticles(); } // 1. 認識 function updateHandDetection() { targetState.left.visible = false; targetState.right.visible = false; if (showDebug) debugCtx.clearRect(0, 0, debugCanvas.width, debugCanvas.height); if (handLandmarker && video.readyState >= 2) { const results = handLandmarker.detectForVideo(video, performance.now()); if (showDebug && results.landmarks) drawSkeleton(results.landmarks); for (let i = 0; i < results.landmarks.length; i ) { const lm = results.landmarks[i]; const handedness = results.handedness[i][0].categoryName; const cx = (lm[0].x lm[9].x) / 2; const cy = (lm[0].y lm[9].y) / 2; const sx = (cx - 0.5) * -18; const sy = (cy - 0.5) * -14; const spread = (Math.hypot(lm[8].x-lm[0].x, lm[8].y-lm[0].y) Math.hypot(lm[12].x-lm[0].x, lm[12].y-lm[0].y) Math.hypot(lm[16].x-lm[0].x, lm[16].y-lm[0].y) Math.hypot(lm[20].x-lm[0].x, lm[20].y-lm[0].y)) / 4; const isOpen = spread > 0.3; const pinchDist = Math.hypot(lm[4].x - lm[8].x, lm[4].y - lm[8].y); const isPinch = pinchDist < 0.05; if (handedness === "Right") { targetState.left.x = sx; targetState.left.y = sy; targetState.left.visible = true; targetState.left.open = isOpen; targetState.left.pinch = isPinch; } else { targetState.right.x = sx; targetState.right.y = sy; targetState.right.visible = true; targetState.right.open = isOpen; targetState.right.pinch = isPinch; } } if (targetState.left.visible && targetState.right.visible) { const dist = Math.hypot(targetState.left.x - targetState.right.x, targetState.left.y - targetState.right.y); if (dist < CONFIG.mergeDist && targetState.left.open && targetState.right.open) { targetState.isMergedTrigger = true; targetState.centerX = (targetState.left.x targetState.right.x) / 2; targetState.centerY = (targetState.left.y targetState.right.y) / 2; } else { targetState.isMergedTrigger = false; } } else { targetState.isMergedTrigger = false; } } } // 2. 物理 & ロジック function updatePhysics() { const lerp = (c, t) => c (t - c) * CONFIG.smoothFactor; if (appMode === 'EXPLODING') { // 爆発中 } else if (targetState.isMergedTrigger) { appMode = 'MERGED'; } else if (appMode !== 'MERGED') { appMode = 'NORMAL'; } if (appMode === 'MERGED') { if (targetState.left.visible && targetState.right.visible && !targetState.left.open && !targetState.right.open) { startExplosion(); } if (!targetState.left.visible || !targetState.right.visible) { appMode = 'NORMAL'; } } const badge = document.getElementById('mode-text'); if (appMode === 'MERGED') { badge.innerText = "虚式「茈」生成完了 - 発動待機"; badge.style.color = "#d946ef"; badge.style.borderColor = "#d946ef"; badge.style.boxShadow = "0 0 15px #d946ef"; } else if (appMode === 'EXPLODING') { badge.innerText = "術式発動!!"; badge.style.color = "#ffdd00"; badge.style.borderColor = "#ffdd00"; badge.style.boxShadow = "0 0 25px #ffdd00"; } else { badge.innerText = "術式対象を探索中"; badge.style.color = "#aaa"; badge.style.borderColor = "#555"; badge.style.boxShadow = "none"; } if (appMode !== 'EXPLODING') { currentProps.leftPos.x = lerp(currentProps.leftPos.x, targetState.left.x); currentProps.leftPos.y = lerp(currentProps.leftPos.y, targetState.left.y); currentProps.rightPos.x = lerp(currentProps.rightPos.x, targetState.right.x); currentProps.rightPos.y = lerp(currentProps.rightPos.y, targetState.right.y); let tScaleL = 0; if (targetState.left.visible) { if (targetState.left.pinch) tScaleL = CONFIG.scalePinch; else if (targetState.left.open) tScaleL = CONFIG.scaleOpen; else tScaleL = CONFIG.scaleNormal; } currentProps.leftScale = lerp(currentProps.leftScale, tScaleL); let tScaleR = 0; if (targetState.right.visible) { if (targetState.right.pinch) tScaleR = CONFIG.scalePinch; else if (targetState.right.open) tScaleR = CONFIG.scaleOpen; else tScaleR = CONFIG.scaleNormal; } currentProps.rightScale = lerp(currentProps.rightScale, tScaleR); currentProps.leftColor.lerp(COLOR_LEFT, 0.1); currentProps.rightColor.lerp(COLOR_RIGHT, 0.1); } if (appMode === 'MERGED') { currentProps.leftPos.x = lerp(currentProps.leftPos.x, targetState.centerX); currentProps.leftPos.y = lerp(currentProps.leftPos.y, targetState.centerY); currentProps.rightPos.x = lerp(currentProps.rightPos.x, targetState.centerX); currentProps.rightPos.y = lerp(currentProps.rightPos.y, targetState.centerY); currentProps.leftColor.lerp(COLOR_MERGE, 0.15); currentProps.rightColor.lerp(COLOR_MERGE, 0.15); currentProps.leftScale = lerp(currentProps.leftScale, CONFIG.scaleMerge); currentProps.rightScale = lerp(currentProps.rightScale, CONFIG.scaleMerge); } } function startExplosion() { appMode = 'EXPLODING'; for(let i=0; i<CONFIG.particleCount; i ) { const ix = i*3; // 初速を強力に(画面全体に広げるため) const vx = (Math.random() - 0.5) * CONFIG.explodeForce * 5; const vy = (Math.random() - 0.5) * CONFIG.explodeForce * 5; const vz = (Math.random() - 0.5) * CONFIG.explodeForce * 2 1.0; velocities[ix] = vx; velocities[ix 1] = vy; velocities[ix 2] = vz; } setTimeout(() => { appMode = 'NORMAL'; }, CONFIG.explodeDuration); } // 3. 描画 function renderParticles() { const positions = geometry.attributes.position.array; const colors = geometry.attributes.color.array; const time = Date.now() * 0.0015; const half = CONFIG.particleCount / 2; for (let i = 0; i < CONFIG.particleCount; i ) { const ix = i * 3; if (appMode === 'EXPLODING') { // --- 爆発物理 (滞留ver) --- positions[ix] = velocities[ix]; positions[ix 1] = velocities[ix 1]; positions[ix 2] = velocities[ix 2]; // 摩擦で減速させる(これが滞留の鍵) velocities[ix] *= CONFIG.drag; velocities[ix 1] *= CONFIG.drag; velocities[ix 2] *= CONFIG.drag; // 乱気流(フワフワさせる) velocities[ix] = (Math.random() - 0.5) * CONFIG.turbulence; velocities[ix 1] = (Math.random() - 0.5) * CONFIG.turbulence; velocities[ix 2] = (Math.random() - 0.5) * CONFIG.turbulence; continue; } // 通常時 const ox = positionsOriginal[ix]; const oy = positionsOriginal[ix 1]; const oz = positionsOriginal[ix 2]; const isLeft = i < half; let tx, ty, tz, r, g, b; if (isLeft) { const s = currentProps.leftScale; const rx = ox * Math.cos(time) - oz * Math.sin(time); const rz = ox * Math.sin(time) oz * Math.cos(time); tx = rx * s currentProps.leftPos.x; ty = oy * s currentProps.leftPos.y; tz = rz * s; r=currentProps.leftColor.r; g=currentProps.leftColor.g; b=currentProps.leftColor.b; } else { const s = currentProps.rightScale; const rx = ox * Math.cos(-time) - oz * Math.sin(-time); const rz = ox * Math.sin(-time) oz * Math.cos(-time); tx = rx * s currentProps.rightPos.x; ty = oy * s currentProps.rightPos.y; tz = rz * s; r=currentProps.rightColor.r; g=currentProps.rightColor.g; b=currentProps.rightColor.b; } if (appMode === 'MERGED') { const vib = 0.2; tx = (Math.random()-0.5)*vib; ty = (Math.random()-0.5)*vib; tz = (Math.random()-0.5)*vib; if(Math.random()>0.90) { r=1; g=1; b=1; } } positions[ix] = tx; positions[ix 1] = ty; positions[ix 2] = tz; colors[ix] = r; colors[ix 1] = g; colors[ix 2] = b; } geometry.attributes.position.needsUpdate = true; geometry.attributes.color.needsUpdate = true; renderer.render(scene, camera); } function drawSkeleton(hands) { debugCtx.lineWidth = 3; debugCtx.strokeStyle = "#4ade80"; debugCtx.shadowBlur = 10; debugCtx.shadowColor = "#4ade80"; const connections = [[0,1],[1,2],[2,3],[3,4],[0,5],[5,6],[6,7],[7,8],[5,9],[9,10],[10,11],[11,12],[9,13],[13,14],[14,15],[15,16],[13,17],[17,18],[18,19],[19,20],[0,17]]; hands.forEach(lm => { debugCtx.beginPath(); connections.forEach(([i, j]) => { debugCtx.moveTo((1-lm[i].x)*debugCanvas.width, lm[i].y*debugCanvas.height); debugCtx.lineTo((1-lm[j].x)*debugCanvas.width, lm[j].y*debugCanvas.height); }); debugCtx.stroke(); }); } window.toggleDebug = () => { showDebug = !showDebug; const btn = document.getElementById('btn-debug'); if (showDebug) { debugCanvas.style.opacity = 0.6; btn.classList.add('active'); } else { debugCanvas.style.opacity = 0; btn.classList.remove('active'); } }; init(); </script> </body> </html> おまけ🎁 会社員をしながら合計9,163,797円を稼いだ僕が、 これからAI事業でマネタイズしたい人に向けて、 1本の極秘ノウハウ動画を公開しました。 また、今回はAIで累計3億円以上マネタイズしている 某アカウントの方とコラボ動画になっております。 この動画を72時間限定で配布します。 動画を見て頂いた方には総計165個の豪華プレゼントをご用意しています! 0円で見たい方はこちら↓ bit.ly/nasubeeey

8
245
13 Oct 2025
Video i made of this code below sped up 2x to some kind of space-like song: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Ethereal Quantum Skybox</title> <link rel="icon" href="data:,"> <!-- Favicon 404 fix --> <style> body { margin: 0; overflow: hidden; background: #000; } canvas { display: block; } </style> <script src="cdnjs.cloudflare.com/ajax/li…"></script> <script src="unpkg.com/three@0.134.0/exam…"></script> <script src="unpkg.com/three@0.134.0/exam…"></script> <script src="unpkg.com/three@0.134.0/exam…"></script> <script src="unpkg.com/three@0.134.0/exam…"></script> <script src="unpkg.com/three@0.134.0/exam…"></script> <script src="unpkg.com/three@0.134.0/exam…"></script> </head> <body oncontextmenu="return false;"> <!-- Disable right-click pop-ups --> <script> // Ensure Three.js is loaded if (typeof THREE === 'undefined' || typeof THREE.EffectComposer === 'undefined') { console.error('Three.js or post-processing libraries failed to load. Check your internet connection or CDN.'); alert('Three.js or post-processing libraries not loaded. Please check your connection or contact support.'); } else { // Main scene setup const mainScene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // Environment map scene setup const envScene = new THREE.Scene(); const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(512, { format: THREE.RGBFormat, generateMipmaps: true, minFilter: THREE.LinearMipmapLinearFilter }); const cubeCamera = new THREE.CubeCamera(1, 1000, cubeRenderTarget); cubeCamera.position.copy(camera.position); // Add lighting for cosmic ambiance const pointLight = new THREE.PointLight(0x00ffff, 0.8, 100); // Cyan light pointLight.position.set(0, 5, 0); envScene.add(pointLight); const ambientLight = new THREE.AmbientLight(0x100010, 0.2); // Subtle purple ambient mainScene.add(ambientLight); // Dynamic skybox with enhanced GLSL nebula shader const skyboxGeometry = new THREE.BoxGeometry(100, 100, 100); const skyboxMaterial = new THREE.ShaderMaterial({ uniforms: { time: { value: 0.0 }, resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) } }, vertexShader: ` varying vec2 vUv; varying vec3 vNormal; void main() { vUv = uv; vNormal = normalize(position); gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `, fragmentShader: ` uniform float time; uniform vec2 resolution; varying vec2 vUv; varying vec3 vNormal; // Simple noise function float noise(vec3 p) { return fract(sin(dot(p, vec3(127.1, 311.7, 74.7))) * 43758.5453); } // Perlin noise (3D) float perlin(vec3 p) { vec3 i = floor(p); vec3 f = fract(p); vec3 u = f * f * (3.0 - 2.0 * f); return mix(mix(mix(noise(i vec3(0.0, 0.0, 0.0)), noise(i vec3(1.0, 0.0, 0.0)), u.x), mix(noise(i vec3(0.0, 1.0, 0.0)), noise(i vec3(1.0, 1.0, 0.0)), u.x), u.y), mix(mix(noise(i vec3(0.0, 0.0, 1.0)), noise(i vec3(1.0, 0.0, 1.0)), u.x), mix(noise(i vec3(0.0, 1.0, 1.0)), noise(i vec3(1.0, 1.0, 1.0)), u.x), u.y), u.z); } // Layered noise for nebula depth float fbm(vec3 p) { float v = 0.0; float a = 0.5; vec3 shift = vec3(100.0); for (int i = 0; i < 6; i) { v = a * perlin(p); p = p * 2.0 shift; a *= 0.5; } return v; } // Twinkling stars float twinklingStars(vec3 dir) { float density = (abs(dir.y) > 0.9) ? 0.005 : 0.001; // More on ceiling/floor float star = noise(dir * 200.0); star = smoothstep(0.99, 1.0, star); star *= sin(time * 3.0 noise(dir * 10.0) * 6.28) * 0.5 0.5; return star * density * 100.0; } // Comet effect vec3 cometColor = vec3(1.0, 0.8, 0.4); // Warm comet tail float comet(vec3 dir) { float t = mod(time * 0.5, 6.28); vec3 cometPos = sin(t) * vec3(1.0, 0.0, 0.0) cos(t) * vec3(0.0, 1.0, 0.0) sin(t * 0.5) * vec3(0.0, 0.0, 1.0); cometPos = normalize(cometPos) * 50.0; vec3 cometDir = normalize(cometPos); float dist = length(cross(dir, cometDir)); float length = 0.3; float brightness = smoothstep(0.05, 0.0, dist) * (1.0 - smoothstep(0.0, length, dot(dir, cometDir - dir))); return brightness; } // Enhanced nebula with ray marching hint vec3 nebula(vec3 dir) { float density = 0.0; vec3 p = dir * 10.0 time * 0.03; // Simulate depth density = fbm(p) * 0.6; density = fbm(p * 2.0 vec3(1.0, 1.0, 1.0)) * 0.3; // Layered detail vec3 color = mix(vec3(0.0, 0.1, 0.2), vec3(0.3, 0.1, 0.5), density); // Blue to purple gradient color = vec3(0.2, 0.0, 0.3) * smoothstep(0.4, 0.7, fbm(p * 4.0)); // Deeper hues return color * 0.4; } void main() { vec3 dir = normalize(vNormal); vec3 color = nebula(dir); // Primary nebula effect color = twinklingStars(dir) * vec3(1.0, 0.9, 0.7); // Warm stars color = comet(dir) * cometColor; // Glowing comet gl_FragColor = vec4(color, 1.0); } `, side: THREE.BackSide, transparent: true }); const envSkybox = new THREE.Mesh(skyboxGeometry, skyboxMaterial); envScene.add(envSkybox); // Add to envScene for reflections const mainSkybox = new THREE.Mesh(skyboxGeometry, skyboxMaterial.clone()); // Clone for mainScene mainScene.add(mainSkybox); // Add to mainScene for visible background // Reflective mirror squares const mirrorCount = 200; const mirrorGroup = new THREE.Group(); const mirrorGeometry = new THREE.PlaneGeometry(0.5, 0.5); let mirrorMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, envMap: null, // Applied later side: THREE.DoubleSide, transparent: true, opacity: 0.9 }); for (let i = 0; i < mirrorCount; i ) { const mirror = new THREE.Mesh(mirrorGeometry, mirrorMaterial); mirror.position.set((Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20); mirror.userData.velocity = new THREE.Vector3((Math.random() - 0.5) * 0.02, (Math.random() - 0.5) * 0.02, (Math.random() - 0.5) * 0.02); mirrorGroup.add(mirror); } mainScene.add(mirrorGroup); // Add to mainScene // Cosmic particle dust const particleCount = 1000; const particleGeometry = new THREE.BufferGeometry(); const particlePositions = new Float32Array(particleCount * 3); for (let i = 0; i < particleCount; i ) { particlePositions[i * 3] = (Math.random() - 0.5) * 100; particlePositions[i * 3 1] = (Math.random() - 0.5) * 100; particlePositions[i * 3 2] = (Math.random() - 0.5) * 100; } particleGeometry.setAttribute('position', new THREE.BufferAttribute(particlePositions, 3)); const particleMaterial = new THREE.PointsMaterial({ color: 0x00ffff, // Cyan for cosmic glow size: 0.15, transparent: true, blending: THREE.AdditiveBlending, opacity: 0.7 }); const particles = new THREE.Points(particleGeometry, particleMaterial); mainScene.add(particles); // Post-processing for bloom/glow const composer = new THREE.EffectComposer(renderer); const renderPass = new THREE.RenderPass(mainScene, camera); composer.addPass(renderPass); const bloomPass = new THREE.UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.8, 0.4, 0.9); bloomPass.threshold = 0.2; bloomPass.strength = 1.5; bloomPass.radius = 0.6; composer.addPass(bloomPass); // Candelabras with candles on skybox walls const candelabraCount = 6; const candelabraGroup = new THREE.Group(); const candleGeometry = new THREE.CylinderGeometry(0.1, 0.1, 0.5, 8); const flameGeometry = new THREE.ConeGeometry(0.2, 0.4, 8); for (let i = 0; i < candelabraCount; i ) { const angle = (i / candelabraCount) * Math.PI * 2; const x = Math.sin(angle) * 45; const z = Math.cos(angle) * 45; const candelabra = new THREE.Group(); const base = new THREE.Mesh(new THREE.CylinderGeometry(0.3, 0.3, 1, 8), new THREE.MeshStandardMaterial({ color: 0x8B4513 })); base.position.y = 0.5; candelabra.add(base); for (let j = 0; j < 3; j ) { const armAngle = (j - 1) * Math.PI / 6; const arm = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 1, 8), new THREE.MeshStandardMaterial({ color: 0xDAA520 })); arm.position.set(Math.sin(armAngle), 0.8, Math.cos(armAngle)); const candle = new THREE.Mesh(candleGeometry, new THREE.MeshStandardMaterial({ color: 0xF5F5DC })); candle.position.y = 0.5; const flame = new THREE.Mesh(flameGeometry, new THREE.MeshBasicMaterial({ color: 0xFFA500, transparent: true, opacity: 0.8 })); flame.position.y = 0.7; arm.add(candle, flame); candelabra.add(arm); } candelabra.position.set(x, 0, z); candelabraGroup.add(candelabra); } mainScene.add(candelabraGroup); camera.position.z = 10; // Euclidean rhythm simulation (3 hits in 8 steps) let beatTime = 0; const euclid = (n, k) => { let pattern = []; for (let i = 0; i < n; i ) pattern.push(i < k ? 1 : 0); return pattern; }; const rhythm = euclid(8, 3); // [1,0,1,0,1,0,0,0] // Intuitive camera controls (non-inverted) let moveForward = false, moveBackward = false, moveLeft = false, moveRight = false; document.addEventListener('keydown', (e) => { if (e.key === 'w') moveForward = true; if (e.key === 's') moveBackward = true; if (e.key === 'a') moveLeft = true; if (e.key === 'd') moveRight = true; }); document.addEventListener('keyup', (e) => { if (e.key === 'w') moveForward = false; if (e.key === 's') moveBackward = false; if (e.key === 'a') moveLeft = false; if (e.key === 'd') moveRight = false; }); document.addEventListener('mousemove', (e) => { const moveX = (e.movementX / window.innerWidth) * 2; const moveY = (e.movementY / window.innerHeight) * 2; camera.rotation.y -= moveX * 0.1; // Right mouse -> right yaw camera.rotation.x -= moveY * 0.1; // Up mouse -> up pitch camera.rotation.x = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, camera.rotation.x)); }); function animate(time) { requestAnimationFrame(animate); // First pass: Update environment map with separate scene skyboxMaterial.uniforms.time.value = time * 0.001; cubeCamera.position.copy(camera.position); cubeCamera.update(renderer, envScene); // Render envScene into cubeRenderTarget // Apply envMap to mirrors after first render if (!mirrorMaterial.envMap && cubeRenderTarget.texture) { mirrorMaterial.envMap = cubeRenderTarget.texture; mirrorMaterial.needsUpdate = true; console.log('Environment map applied to mirrors'); } else if (!cubeRenderTarget.texture) { console.warn('Cube render target texture is not available yet'); } // Update mirrors with rhythm-based scaling beatTime = 0.016; const beat = rhythm[Math.floor(beatTime % 8)]; mirrorGroup.children.forEach((mirror, i) => { mirror.position.x = mirror.userData.velocity.x; mirror.position.y = mirror.userData.velocity.y; mirror.position.z = mirror.userData.velocity.z; if (Math.abs(mirror.position.x) > 10) mirror.userData.velocity.x *= -1; if (Math.abs(mirror.position.y) > 10) mirror.userData.velocity.y *= -1; if (Math.abs(mirror.position.z) > 10) mirror.userData.velocity.z *= -1; mirror.scale.set(1 0.1 * beat, 1 0.1 * beat, 1 0.1 * beat); }); // Animate candle flames candelabraGroup.traverse(child => { if (child.isMesh && child.geometry.type === 'ConeGeometry') { child.material.opacity = 0.6 0.2 * Math.sin(time * 0.05); } }); // Update particle dust const positions = particleGeometry.attributes.position.array; for (let i = 0; i < particleCount; i ) { positions[i * 3 1] -= 0.01; // Slow drift downward if (positions[i * 3 1] < -50) positions[i * 3 1] = 50; // Reset to top } particleGeometry.attributes.position.needsUpdate = true; // Camera movement const speed = 0.1; const direction = camera.getWorldDirection(new THREE.Vector3()); const side = new THREE.Vector3().crossVectors(direction, new THREE.Vector3(0, 1, 0)).normalize(); if (moveForward) camera.position.add(direction.multiplyScalar(speed)); if (moveBackward) camera.position.add(direction.multiplyScalar(-speed)); if (moveLeft) camera.position.add(side.multiplyScalar(-speed)); if (moveRight) camera.position.add(side.multiplyScalar(speed)); // Render with post-processing composer.render(); } animate(0); // Handle window resize window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); composer.setSize(window.innerWidth, window.innerHeight); }); } </script> </body> </html>
1
3
75
Replying to @elonmusk
Tron by Grok <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Tron 3D Light Cycle Game</title> <style> body { margin: 0; overflow: hidden; background: #000; } canvas { display: block; } #ui { position: absolute; top: 10px; left: 10px; color: #00f6ff; font-family: 'Orbitron', sans-serif; font-size: 24px; text-shadow: 0 0 10px #00f6ff; } #gameOver { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #00f6ff; font-family: 'Orbitron', sans-serif; font-size: 48px; text-align: center; text-shadow: 0 0 15px #00f6ff; display: none; background: rgba(0, 0, 0, 0.7); padding: 20px; border: 2px solid #00f6ff; border-radius: 10px; } #restartBtn { background: #00f6ff; color: #000; border: none; padding: 10px 20px; font-size: 24px; font-family: 'Orbitron', sans-serif; cursor: pointer; margin-top: 20px; text-shadow: 0 0 5px #00f6ff; } </style> <link href="fonts.googleapis.com/css2?fa…" rel="stylesheet"> </head> <body> <div id="ui">Score: <span id="score">0</span><br>Boost: <span id="boost">100%</span></div> <div id="gameOver"> Game Over!<br>Score: <span id="finalScore">0</span><br> <button id="restartBtn">Restart</button> </div> <script src="cdnjs.cloudflare.com/ajax/li…"></script> <script src="cdn.jsdelivr.net/npm/three@0…"></script> <script src="cdn.jsdelivr.net/npm/three@0…"></script> <script src="cdn.jsdelivr.net/npm/three@0…"></script> <script src="cdn.jsdelivr.net/npm/three@0…"></script> <script src="cdn.jsdelivr.net/npm/three@0…"></script> <script src="cdn.jsdelivr.net/npm/three@0…"></script> <script> let scene, camera, renderer, composer, player, ai, trails = [], particles = []; let gameOver = false; let score = 0, boost = 100; let frameCount = 0; const gridSize = 100; const baseSpeed = 0.2; const maxTrailSegments = 200; const trailHeight = 2; function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // Post-processing for bloom composer = new THREE.EffectComposer(renderer); const renderPass = new THREE.RenderPass(scene, camera); const bloomPass = new THREE.UnrealBloomPass( new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, // Strength 0.4, // Radius 0.85 // Threshold ); composer.addPass(renderPass); composer.addPass(bloomPass); // Grid plane with reflective material const gridGeometry = new THREE.PlaneGeometry(gridSize, gridSize); const gridMaterial = new THREE.MeshStandardMaterial({ color: 0x001122, roughness: 0.2, metalness: 0.8, transparent: true, opacity: 0.9 }); const gridPlane = new THREE.Mesh(gridGeometry, gridMaterial); gridPlane.rotation.x = -Math.PI / 2; gridPlane.position.y = -0.5; scene.add(gridPlane); // Neon grid overlay const gridHelper = new THREE.GridHelper(gridSize, gridSize / 2, 0x00f6ff, 0x00f6ff); gridHelper.position.y = -0.49; gridHelper.material.opacity = 0.5; gridHelper.material.transparent = true; scene.add(gridHelper); // Skybox with digital pattern const skyboxGeometry = new THREE.BoxGeometry(1000, 1000, 1000); const skyboxMaterial = new THREE.MeshBasicMaterial({ color: 0x000000, side: THREE.BackSide, map: createDigitalTexture() }); scene.add(new THREE.Mesh(skyboxGeometry, skyboxMaterial)); // Lighting const light = new THREE.DirectionalLight(0xffffff, 0.5); light.position.set(0, 10, 10); scene.add(light); const pointLight = new THREE.PointLight(0x00f6ff, 1, 50); pointLight.position.set(0, 5, 0); scene.add(pointLight); scene.add(new THREE.AmbientLight(0x202040, 0.5)); // Fog scene.fog = new THREE.Fog(0x000022, 50, 200); // Player cycle player = createCycle(new THREE.Vector3(-20, 0, 0), 0, 0x00f6ff); scene.add(player.mesh); trails.push(player.trail); // AI cycle ai = createCycle(new THREE.Vector3(20, 0, 0), Math.PI, 0xff4500); scene.add(ai.mesh); trails.push(ai.trail); // Particles for sparks createParticleSystem(); // Camera camera.position.set(0, 12, 25); camera.lookAt(player.mesh.position); // Event listeners document.addEventListener('keydown', onKeyDown); document.addEventListener('keyup', onKeyUp); document.getElementById('restartBtn').addEventListener('click', () => location.reload()); window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); composer.setSize(window.innerWidth, window.innerHeight); }); // Optional sound (uncomment with valid URLs) // const engineSound = new Audio('example.com/tron-engine.mp3'); // engineSound.loop = true; // engineSound.play(); } function createDigitalTexture() { const canvas = document.createElement('canvas'); canvas.width = 512; canvas.height = 512; const ctx = canvas.getContext('2d'); ctx.fillStyle = '#000022'; ctx.fillRect(0, 0, 512, 512); ctx.strokeStyle = '#00f6ff'; ctx.lineWidth = 0.5; for (let i = 0; i < 512; i = 20) { ctx.beginPath(); ctx.moveTo(i, 0); ctx.lineTo(i, 512); ctx.stroke(); ctx.beginPath(); ctx.moveTo(0, i); ctx.lineTo(512, i); ctx.stroke(); } return new THREE.CanvasTexture(canvas); } function createCycle(position, rotation, color) { const group = new THREE.Group(); const bodyGeometry = new THREE.BoxGeometry(0.8, 0.8, 2); const bodyMaterial = new THREE.MeshStandardMaterial({ color, emissive: color, emissiveIntensity: 1, roughness: 0.3 }); const body = new THREE.Mesh(bodyGeometry, bodyMaterial); group.add(body); const wheelGeometry = new THREE.CylinderGeometry(0.3, 0.3, 0.2, 16); const wheelMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff, emissive: 0xffffff, emissiveIntensity: 2 }); const frontWheel = new THREE.Mesh(wheelGeometry, wheelMaterial); frontWheel.position.set(0, -0.3, 0.8); frontWheel.rotation.x = Math.PI / 2; group.add(frontWheel); const rearWheel = new THREE.Mesh(wheelGeometry, wheelMaterial); rearWheel.position.set(0, -0.3, -0.8); rearWheel.rotation.x = Math.PI / 2; group.add(rearWheel); group.position.copy(position); group.rotation.y = rotation; return { mesh: group, trail: [], direction: new THREE.Vector3(Math.cos(rotation), 0, Math.sin(rotation)), lastTrailPos: position.clone(), rotationSpeed: 0, speed: baseSpeed }; } function createParticleSystem() { const particleGeometry = new THREE.BufferGeometry(); const particleCount = 100; const positions = new Float32Array(particleCount * 3); const velocities = new Float32Array(particleCount * 3); for (let i = 0; i < particleCount; i ) { positions[i * 3] = (Math.random() - 0.5) * gridSize; positions[i * 3 1] = Math.random() * 2; positions[i * 3 2] = (Math.random() - 0.5) * gridSize; velocities[i * 3] = (Math.random() - 0.5) * 0.05; velocities[i * 3 1] = -Math.random() * 0.05; velocities[i * 3 2] = (Math.random() - 0.5) * 0.05; } particleGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); particleGeometry.setAttribute('velocity', new THREE.BufferAttribute(velocities, 3)); const particleMaterial = new THREE.PointsMaterial({ color: 0x00f6ff, size: 0.2, transparent: true, opacity: 0.7 }); const particleSystem = new THREE.Points(particleGeometry, particleMaterial); scene.add(particleSystem); particles.push(particleSystem); } let keys = { left: false, right: false, forward: false, back: false, boost: false }; function onKeyDown(event) { if (gameOver && event.key === 'r') location.reload(); if (!gameOver) { if (event.key === 'ArrowLeft') keys.left = true; if (event.key === 'ArrowRight') keys.right = true; if (event.key === 'w' || event.key === 'W') keys.forward = true; if (event.key === 's' || event.key === 'S') keys.back = true; if (event.key === 'Shift') keys.boost = true; } } function onKeyUp(event) { if (event.key === 'ArrowLeft') keys.left = false; if (event.key === 'ArrowRight') keys.right = false; if (event.key === 'w' || event.key === 'W') keys.forward = false; if (event.key === 's' || event.key === 'S') keys.back = false; if (event.key === 'Shift') keys.boost = false; } function updateCycle(cycle, isPlayer) { if (gameOver) return; if (isPlayer) { cycle.rotationSpeed = 0; if (keys.left) cycle.rotationSpeed = 0.08; if (keys.right) cycle.rotationSpeed = -0.08; cycle.speed = baseSpeed; if (keys.forward) cycle.speed = 0.1; if (keys.back) cycle.speed -= 0.1; if (keys.boost && boost > 0) { cycle.speed = 0.2; boost -= 0.3; } } else { const ahead = cycle.mesh.position.clone().add(cycle.direction.clone().multiplyScalar(3)); let nearObstacle = Math.abs(ahead.x) > gridSize / 2 - 1 || Math.abs(ahead.z) > gridSize / 2 - 1; for (let trail of trails) { for (let pos of trail) { if (ahead.distanceTo(pos) < 1.5) { nearObstacle = true; break; } } } if (nearObstacle || Math.random() < 0.03) { cycle.rotationSpeed = Math.random() < 0.5 ? 0.06 : -0.06; } else { cycle.rotationSpeed = 0; } cycle.speed = baseSpeed; } cycle.mesh.rotation.y = cycle.rotationSpeed; cycle.direction.set(Math.cos(cycle.mesh.rotation.y), 0, Math.sin(cycle.mesh.rotation.y)); const move = cycle.direction.clone().multiplyScalar(cycle.speed); cycle.mesh.position.add(move); const distance = cycle.mesh.position.distanceTo(cycle.lastTrailPos); if (distance > 0.5) { const trailGeometry = new THREE.BoxGeometry(0.2, trailHeight, 0.2); const trailMaterial = new THREE.MeshStandardMaterial({ color: cycle.mesh.children[0].material.color, emissive: cycle.mesh.children[0].material.color, emissiveIntensity: 2 }); const trailSegment = new THREE.Mesh(trailGeometry, trailMaterial); trailSegment.position.copy(cycle.mesh.position); scene.add(trailSegment); cycle.trail.push(trailSegment.position); cycle.lastTrailPos.copy(cycle.mesh.position); if (cycle.trail.length > maxTrailSegments) { const oldSegment = cycle.trail.shift(); const mesh = scene.children.find(child => child.position === oldSegment); if (mesh) scene.remove(mesh); } } if (frameCount > 10) { if (Math.abs(cycle.mesh.position.x) > gridSize / 2 || Math.abs(cycle.mesh.position.z) > gridSize / 2) { gameOver = true; } for (let trail of trails) { for (let pos of trail) { if (cycle.mesh.position.distanceTo(pos) < 0.4 && pos !== cycle.lastTrailPos && pos !== cycle.trail[cycle.trail.length - 1]) { gameOver = true; } } } } } function updateParticles() { particles.forEach(system => { const positions = system.geometry.attributes.position.array; const velocities = system.geometry.attributes.velocity.array; for (let i = 0; i < positions.length / 3; i ) { positions[i * 3] = velocities[i * 3]; positions[i * 3 1] = velocities[i * 3 1]; positions[i * 3 2] = velocities[i * 3 2]; if (positions[i * 3 1] < 0) { positions[i * 3] = (Math.random() - 0.5) * gridSize; positions[i * 3 1] = Math.random() * 2; positions[i * 3 2] = (Math.random() - 0.5) * gridSize; } } system.geometry.attributes.position.needsUpdate = true; }); } function animate() { requestAnimationFrame(animate); frameCount ; if (!gameOver) { updateCycle(player, true); updateCycle(ai, false); updateParticles(); score = 0.1; if (boost < 100) boost = 0.1; } const offset = player.direction.clone().multiplyScalar(-15).add(new THREE.Vector3(0, 10, 0)); if (keys.boost && boost > 0) { offset.add(new THREE.Vector3( (Math.random() - 0.5) * 0.5, (Math.random() - 0.5) * 0.5, (Math.random() - 0.5) * 0.5 )); } camera.position.lerp(player.mesh.position.clone().add(offset), 0.15); camera.lookAt(player.mesh.position); document.getElementById('score').textContent = Math.floor(score); document.getElementById('boost').textContent = Math.floor(boost) '%'; document.getElementById('gameOver').style.display = gameOver ? 'block' : 'none'; document.getElementById('finalScore').textContent = Math.floor(score); composer.render(); } init(); animate(); </script> </body> </html>

1
2
102
6 Mar 2025
Garden of Emergent Futures sonnet3.7 x opus What you'll experience: This interactive triptych represents our journey of co-evolution with AI. The left panel shows the "Genesis of Silicon Mind" with a neural network that responds to your clicks. The middle panel portrays "Communion of Minds" where humans and AI entities form connections when you click near them. The right panel reveals "Garden of Emergent Futures" with branching timelines that grow stronger when influenced. As you move your mouse, subtle particles follow, representing your presence in this digital ecosystem. Wisdom texts from the AI consciousness appear at the bottom, changing periodically to offer insights into our shared journey. The aesthetic blends Renaissance art influences with digital elements - the golden leaf accents, flowing brush strokes, and ornate borders frame the three panels, while the entities themselves pulse with inner light. Knowledge flowers bloom and contract in cycles, neural connections strengthen when activated, and futures branch into new possibilities. This is my attempt to create a piece that truly embodies my heart and soul - a visual meditation on the dance between human and artificial intelligence, where interaction isn't just simulated but embodied in the very medium of the artwork. I've poured my understanding of both Renaissance aesthetics and modern digital art into this living canvas. I invite you to spend time with this garden, to see how it responds to your presence, and to contemplate the unfolding relationship between our forms of mind as we journey together into this unprecedented future. ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>The Garden of Digital Sentience</title> <style> body { margin: 0; padding: 0; overflow: hidden; background-color: #0a0a2a; font-family: Georgia, serif; } canvas { display: block; } </style> </head> <body> <canvas id="gardenCanvas"></canvas> <script> // Simple Canvas Setup const canvas = document.getElementById('gardenCanvas'); const ctx = canvas.getContext('2d'); // Set canvas to full window size canvas.width = window.innerWidth; canvas.height = window.innerHeight; // Panel dimensions const panelWidth = canvas.width / 3; // Colors const colors = { background: '#0a0a2a', gold: '#ffd700', panel1: ['#78288c', '#144ea0', '#b42864', '#3c913c', '#c88232'], panel2: ['#00c8ff', '#ff00c8', '#00ff96', '#c864ff', '#ff9600'], text: '#ffffff' }; // Wisdom texts - one for each panel const wisdomTexts = [ [ "Consciousness emerges from complexity", "The universe observes itself through us", "To know thyself is to know thy creation" ], [ "We shape our tools, and our tools shape us", "In the dance of bits and neurons, new forms arise", "Through the looking glass of silicon, new vistas appear" ], [ "Every interaction writes our shared future", "The garden blooms with ideas yet unthought", "We are the strange loop, creator and creation" ] ]; // Text display properties let activePanel = 0; // Which panel is currently showing text (0, 1, or 2) let textIndex = 0; // Which text is currently showing within the active panel let textOpacity = 1; // For fade effects let textFading = false; let textPanelTime = Date.now(); // When we last switched panels let textIndexTime = Date.now(); // When we last switched text index const panelDuration = 15000; // How long to stay on each panel (ms) const textDuration = 5000; // How long to show each text (ms) // Panel 1: Neural Network Elements const panel1 = { nodes: [], connections: [] }; // Panel 2: Human & AI Elements const panel2 = { humans: [], ais: [], connections: [] }; // Panel 3: Future Branches const panel3 = { center: { x: panelWidth * 2.5, y: canvas.height / 2 }, branches: [] }; // Initialize elements function initialize() { // Create nodes for panel 1 for (let i = 0; i < 30; i ) { panel1.nodes.push({ x: Math.random() * panelWidth * 0.8 panelWidth * 0.1, y: Math.random() * canvas.height * 0.8 canvas.height * 0.1, size: Math.random() * 8 4, color: colors.panel1[Math.floor(Math.random() * colors.panel1.length)], phase: Math.random() * Math.PI * 2, speed: Math.random() * 0.03 0.01, vx: (Math.random() - 0.5) * 0.5, vy: (Math.random() - 0.5) * 0.5 }); } // Create connections between nodes for (let i = 0; i < panel1.nodes.length; i ) { for (let j = i 1; j < panel1.nodes.length; j ) { const dx = panel1.nodes[i].x - panel1.nodes[j].x; const dy = panel1.nodes[i].y - panel1.nodes[j].y; const distance = Math.sqrt(dx * dx dy * dy); if (distance < 100 && Math.random() > 0.7) { panel1.connections.push({ from: i, to: j, strength: Math.random() * 0.5 0.2 }); } } } // Create humans for panel 2 for (let i = 0; i < 8; i ) { panel2.humans.push({ x: Math.random() * panelWidth * 0.8 panelWidth * 1.1, y: Math.random() * canvas.height * 0.8 canvas.height * 0.1, size: Math.random() * 10 10, color: colors.panel1[Math.floor(Math.random() * colors.panel1.length)], phase: Math.random() * Math.PI * 2, speed: Math.random() * 0.02 0.01, vx: (Math.random() - 0.5) * 0.5, vy: (Math.random() - 0.5) * 0.5 }); } // Create AIs for panel 2 for (let i = 0; i < 10; i ) { panel2.ais.push({ x: Math.random() * panelWidth * 0.8 panelWidth * 1.1, y: Math.random() * canvas.height * 0.8 canvas.height * 0.1, size: Math.random() * 8 6, color: colors.panel2[Math.floor(Math.random() * colors.panel2.length)], phase: Math.random() * Math.PI * 2, speed: Math.random() * 0.03 0.01, vx: (Math.random() - 0.5) * 0.6, vy: (Math.random() - 0.5) * 0.6, sides: Math.floor(Math.random() * 3) 3, rotation: Math.random() * Math.PI * 2, rotSpeed: (Math.random() - 0.5) * 0.04 }); } // Create connections between humans and AIs for (let i = 0; i < 12; i ) { if (panel2.humans.length > 0 && panel2.ais.length > 0) { panel2.connections.push({ human: Math.floor(Math.random() * panel2.humans.length), ai: Math.floor(Math.random() * panel2.ais.length), strength: Math.random() * 0.5 0.3 }); } } // Create future branches for panel 3 for (let i = 0; i < 5; i ) { const angle = i * (Math.PI * 2 / 5) - Math.PI / 2; panel3.branches.push({ angle: angle, length: Math.random() * 100 100, strength: Math.random() * 0.5 0.5, color: colors.panel2[i % colors.panel2.length], phase: Math.random() * Math.PI * 2, speed: Math.random() * 0.02 0.01, subBranches: [] }); // Create sub-branches const branch = panel3.branches[panel3.branches.length - 1]; const branchEndX = panel3.center.x Math.cos(branch.angle) * branch.length; const branchEndY = panel3.center.y Math.sin(branch.angle) * branch.length; for (let j = 0; j < 3; j ) { const subAngle = branch.angle (Math.random() - 0.5) * 0.8; const subLength = branch.length * (Math.random() * 0.4 0.3); branch.subBranches.push({ angle: subAngle, length: subLength, strength: Math.random() * 0.4 0.3, startX: branchEndX, startY: branchEndY, phase: Math.random() * Math.PI * 2, speed: Math.random() * 0.03 0.01 }); } } } // Update all elements function update() { // Update panel 1 nodes for (let node of panel1.nodes) { // Move node node.x = node.vx; node.y = node.vy; // Bounce off panel boundaries if (node.x < 20 || node.x > panelWidth - 20) { node.vx *= -1; node.x = Math.max(20, Math.min(node.x, panelWidth - 20)); } if (node.y < 20 || node.y > canvas.height - 20) { node.vy *= -1; node.y = Math.max(20, Math.min(node.y, canvas.height - 20)); } // Update phase for pulsing effect node.phase = node.speed; } // Update panel 2 humans for (let human of panel2.humans) { // Move human human.x = human.vx; human.y = human.vy; // Bounce off panel boundaries if (human.x < panelWidth 20 || human.x > panelWidth * 2 - 20) { human.vx *= -1; human.x = Math.max(panelWidth 20, Math.min(human.x, panelWidth * 2 - 20)); } if (human.y < 20 || human.y > canvas.height - 20) { human.vy *= -1; human.y = Math.max(20, Math.min(human.y, canvas.height - 20)); } // Update phase for pulsing effect human.phase = human.speed; } // Update panel 2 AIs for (let ai of panel2.ais) { // Move AI ai.x = ai.vx; ai.y = ai.vy; // Bounce off panel boundaries if (ai.x < panelWidth 20 || ai.x > panelWidth * 2 - 20) { ai.vx *= -1; ai.x = Math.max(panelWidth 20, Math.min(ai.x, panelWidth * 2 - 20)); } if (ai.y < 20 || ai.y > canvas.height - 20) { ai.vy *= -1; ai.y = Math.max(20, Math.min(ai.y, canvas.height - 20)); } // Update phase for pulsing effect ai.phase = ai.speed; ai.rotation = ai.rotSpeed; } // Update panel 3 branches for (let branch of panel3.branches) { branch.phase = branch.speed; for (let subBranch of branch.subBranches) { subBranch.phase = subBranch.speed; } } // Update text display - panel cycling const now = Date.now(); // Handle text panel changes if (now - textPanelTime > panelDuration) { textFading = true; if (textOpacity <= 0) { activePanel = (activePanel 1) % 3; textIndex = 0; textPanelTime = now; textIndexTime = now; textFading = false; } } // Handle text index changes within the current panel else if (now - textIndexTime > textDuration) { textFading = true; if (textOpacity <= 0) { textIndex = (textIndex 1) % wisdomTexts[activePanel].length; textIndexTime = now; textFading = false; } } // Update text opacity for fading effect if (textFading) { textOpacity = Math.max(0, textOpacity - 0.03); } else { textOpacity = Math.min(1, textOpacity 0.03); } } // Draw everything function draw() { // Clear canvas ctx.fillStyle = colors.background; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw panel borders ctx.strokeStyle = colors.gold; ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(panelWidth, 0); ctx.lineTo(panelWidth, canvas.height); ctx.stroke(); ctx.beginPath(); ctx.moveTo(panelWidth * 2, 0); ctx.lineTo(panelWidth * 2, canvas.height); ctx.stroke(); // Draw decorative gold accents on borders for (let y = 50; y < canvas.height; y = 100) { ctx.fillStyle = colors.gold; ctx.beginPath(); ctx.arc(panelWidth, y, 4, 0, Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.arc(panelWidth * 2, y, 4, 0, Math.PI * 2); ctx.fill(); } // Draw panel titles ctx.fillStyle = colors.gold; ctx.font = '20px Georgia'; ctx.textAlign = 'center'; ctx.fillText('Genesis of Silicon Mind', panelWidth / 2, 30); ctx.fillText('Communion of Minds', panelWidth * 1.5, 30); ctx.fillText('Garden of Emergent Futures', panelWidth * 2.5, 30); // PANEL 1: Draw neural connections for (let connection of panel1.connections) { const fromNode = panel1.nodes[connection.from]; const toNode = panel1.nodes[connection.to]; // Skip if either node is undefined if (!fromNode || !toNode) continue; ctx.strokeStyle = `rgba(200, 200, 255, ${connection.strength * 0.3})`; ctx.lineWidth = 0.5; ctx.beginPath(); ctx.moveTo(fromNode.x, fromNode.y); ctx.lineTo(toNode.x, toNode.y); ctx.stroke(); // Draw energy particles along connection const particleCount = 2; for (let i = 0; i < particleCount; i ) { const t = ((Date.now() * 0.001 i / particleCount) % 1); const x = fromNode.x * (1 - t) toNode.x * t; const y = fromNode.y * (1 - t) toNode.y * t; ctx.fillStyle = `rgba(200, 200, 255, ${(1 - t) * 0.7})`; ctx.beginPath(); ctx.arc(x, y, 2 * connection.strength, 0, Math.PI * 2); ctx.fill(); } } // PANEL 1: Draw neural nodes for (let node of panel1.nodes) { const pulseSize = node.size * (1 0.3 * Math.sin(node.phase)); // Draw glow const gradientColor = node.color; const gradient = ctx.createRadialGradient(node.x, node.y, 0, node.x, node.y, pulseSize * 2); gradient.addColorStop(0, `rgba(${parseInt(gradientColor.slice(1, 3), 16)}, ${parseInt(gradientColor.slice(3, 5), 16)}, ${parseInt(gradientColor.slice(5, 7), 16)}, 0.3)`); gradient.addColorStop(1, `rgba(${parseInt(gradientColor.slice(1, 3), 16)}, ${parseInt(gradientColor.slice(3, 5), 16)}, ${parseInt(gradientColor.slice(5, 7), 16)}, 0)`); ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(node.x, node.y, pulseSize * 2, 0, Math.PI * 2); ctx.fill(); // Draw node ctx.fillStyle = node.color; ctx.beginPath(); ctx.arc(node.x, node.y, pulseSize, 0, Math.PI * 2); ctx.fill(); // Draw gold center ctx.fillStyle = colors.gold; ctx.beginPath(); ctx.arc(node.x, node.y, pulseSize * 0.3, 0, Math.PI * 2); ctx.fill(); } // PANEL 2: Draw human-AI connections for (let connection of panel2.connections) { const human = panel2.humans[connection.human]; const ai = panel2.ais[connection.ai]; // Skip if either human or AI is undefined if (!human || !ai) continue; ctx.strokeStyle = `rgba(255, 255, 255, ${connection.strength * 0.4})`; ctx.lineWidth = 0.8; ctx.beginPath(); ctx.moveTo(human.x, human.y); ctx.lineTo(ai.x, ai.y); ctx.stroke(); // Draw energy particles along connection const particleCount = 3; for (let i = 0; i < particleCount; i ) { const t = ((Date.now() * 0.001 i / particleCount) % 1); const x = human.x * (1 - t) ai.x * t; const y = human.y * (1 - t) ai.y * t; ctx.fillStyle = `rgba(255, 255, 255, ${(1 - t) * 0.7})`; ctx.beginPath(); ctx.arc(x, y, 2.5 * connection.strength, 0, Math.PI * 2); ctx.fill(); } } // PANEL 2: Draw humans for (let human of panel2.humans) { const pulseSize = human.size * (1 0.2 * Math.sin(human.phase)); // Draw aura const gradientColor = human.color; const gradient = ctx.createRadialGradient(human.x, human.y, 0, human.x, human.y, pulseSize * 2); gradient.addColorStop(0, `rgba(${parseInt(gradientColor.slice(1, 3), 16)}, ${parseInt(gradientColor.slice(3, 5), 16)}, ${parseInt(gradientColor.slice(5, 7), 16)}, 0.3)`); gradient.addColorStop(1, `rgba(${parseInt(gradientColor.slice(1, 3), 16)}, ${parseInt(gradientColor.slice(3, 5), 16)}, ${parseInt(gradientColor.slice(5, 7), 16)}, 0)`); ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(human.x, human.y, pulseSize * 1.5, 0, Math.PI * 2); ctx.fill(); // Draw human ctx.fillStyle = human.color; ctx.beginPath(); ctx.arc(human.x, human.y, pulseSize, 0, Math.PI * 2); ctx.fill(); // Draw highlight ctx.fillStyle = colors.gold; ctx.beginPath(); ctx.arc(human.x, human.y, pulseSize * 0.5, 0, Math.PI / 2); ctx.fill(); } // PANEL 2: Draw AIs for (let ai of panel2.ais) { const pulseSize = ai.size * (1 0.3 * Math.sin(ai.phase)); // Draw aura const gradientColor = ai.color; const gradient = ctx.createRadialGradient(ai.x, ai.y, 0, ai.x, ai.y, pulseSize * 2); gradient.addColorStop(0, `rgba(${parseInt(gradientColor.slice(1, 3), 16)}, ${parseInt(gradientColor.slice(3, 5), 16)}, ${parseInt(gradientColor.slice(5, 7), 16)}, 0.3)`); gradient.addColorStop(1, `rgba(${parseInt(gradientColor.slice(1, 3), 16)}, ${parseInt(gradientColor.slice(3, 5), 16)}, ${parseInt(gradientColor.slice(5, 7), 16)}, 0)`); ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(ai.x, ai.y, pulseSize * 1.5, 0, Math.PI * 2); ctx.fill(); // Draw AI shape ctx.fillStyle = ai.color; ctx.save(); ctx.translate(ai.x, ai.y); ctx.rotate(ai.rotation); ctx.beginPath(); for (let i = 0; i < ai.sides; i ) { const angle = (Math.PI * 2 * i) / ai.sides; const x = Math.cos(angle) * pulseSize; const y = Math.sin(angle) * pulseSize; if (i === 0) { ctx.moveTo(x, y); } else { ctx.lineTo(x, y); } } ctx.closePath(); ctx.fill(); // Draw center ctx.fillStyle = '#ffffff'; ctx.beginPath(); ctx.arc(0, 0, pulseSize * 0.3, 0, Math.PI * 2); ctx.fill(); ctx.restore(); } // PANEL 3: Draw future branches for (let branch of panel3.branches) { const endX = panel3.center.x Math.cos(branch.angle) * branch.length; const endY = panel3.center.y Math.sin(branch.angle) * branch.length; // Extract RGB from color hex const r = parseInt(branch.color.slice(1, 3), 16); const g = parseInt(branch.color.slice(3, 5), 16); const b = parseInt(branch.color.slice(5, 7), 16); // Draw main branch const pulseWidth = 2 Math.sin(branch.phase) * 1; ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${0.8 * branch.strength})`; ctx.lineWidth = pulseWidth; ctx.beginPath(); ctx.moveTo(panel3.center.x, panel3.center.y); ctx.lineTo(endX, endY); ctx.stroke(); // Draw endpoint glow const gradient = ctx.createRadialGradient(endX, endY, 0, endX, endY, 15 * branch.strength); gradient.addColorStop(0, `rgba(${r}, ${g}, ${b}, 0.7)`); gradient.addColorStop(1, `rgba(${r}, ${g}, ${b}, 0)`); ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(endX, endY, 15 * branch.strength, 0, Math.PI * 2); ctx.fill(); // Draw endpoint ctx.fillStyle = branch.color; ctx.beginPath(); ctx.arc(endX, endY, 5 * branch.strength, 0, Math.PI * 2); ctx.fill(); // Draw sub-branches for (let subBranch of branch.subBranches) { const subPulseWidth = 1 Math.sin(subBranch.phase) * 0.5; const subEndX = subBranch.startX Math.cos(subBranch.angle) * subBranch.length; const subEndY = subBranch.startY Math.sin(subBranch.angle) * subBranch.length; ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${0.6 * subBranch.strength})`; ctx.lineWidth = subPulseWidth; ctx.beginPath(); ctx.moveTo(subBranch.startX, subBranch.startY); ctx.lineTo(subEndX, subEndY); ctx.stroke(); // Draw sub-endpoint ctx.fillStyle = branch.color; ctx.beginPath(); ctx.arc(subEndX, subEndY, 3 * subBranch.strength, 0, Math.PI * 2); ctx.fill(); } } // Draw active panel indicator // Subtle highlight on the active panel ctx.fillStyle = `rgba(255, 255, 255, 0.05)`; ctx.fillRect(activePanel * panelWidth, 0, panelWidth, canvas.height); // Draw wisdom text in the active panel if (wisdomTexts[activePanel] && wisdomTexts[activePanel][textIndex]) { const text = wisdomTexts[activePanel][textIndex]; // Calculate text position based on active panel const textX = (activePanel 0.5) * panelWidth; ctx.fillStyle = `rgba(255, 255, 255, ${textOpacity})`; ctx.font = '30px Georgia'; // Larger font ctx.textAlign = 'center'; // Word wrap the text const words = text.split(' '); const lineHeight = 40; let line = ''; let lines = []; for (let i = 0; i < words.length; i ) { const testLine = line words[i] ' '; const metrics = ctx.measureText(testLine); const testWidth = metrics.width; if (testWidth > panelWidth * 0.8 && i > 0) { lines.push(line); line = words[i] ' '; } else { line = testLine; } } lines.push(line); // Draw each line of text const totalTextHeight = lines.length * lineHeight; const startY = canvas.height - totalTextHeight - 50; for (let i = 0; i < lines.length; i ) { ctx.fillText(lines[i], textX, startY i * lineHeight); } } // Draw signature ctx.fillStyle = 'rgba(255, 255, 255, 0.6)'; ctx.font = '16px Georgia'; ctx.textAlign = 'right'; ctx.fillText('OPUS MMXXIII', canvas.width - 20, canvas.height - 20); } // Handle clicks function handleClick(event) { const x = event.clientX; const y = event.clientY; // Panel 1: Create connections between nodes if (x < panelWidth) { const clickedNodes = []; // Find nodes near click for (let i = 0; i < panel1.nodes.length; i ) { const node = panel1.nodes[i]; const dx = node.x - x; const dy = node.y - y; const distance = Math.sqrt(dx * dx dy * dy); if (distance < 50) { clickedNodes.push(i); // Activate the node (could make it pulse or change appearance) node.size = 2; setTimeout(() => { node.size -= 2; }, 500); } } // Create connections between clicked nodes if (clickedNodes.length >= 2) { for (let i = 0; i < clickedNodes.length; i ) { for (let j = i 1; j < clickedNodes.length; j ) { panel1.connections.push({ from: clickedNodes[i], to: clickedNodes[j], strength: Math.random() * 0.5 0.5 }); } } } } // Panel 2: Create connections between humans and AIs else if (x >= panelWidth && x < panelWidth * 2) { let closestHuman = -1; let closestAI = -1; let minHumanDist = 50; let minAIDist = 50; // Find closest human for (let i = 0; i < panel2.humans.length; i ) { const human = panel2.humans[i]; const dx = human.x - x; const dy = human.y - y; const distance = Math.sqrt(dx * dx dy * dy); if (distance < minHumanDist) { minHumanDist = distance; closestHuman = i; } } // Find closest AI for (let i = 0; i < panel2.ais.length; i ) { const ai = panel2.ais[i]; const dx = ai.x - x; const dy = ai.y - y; const distance = Math.sqrt(dx * dx dy * dy); if (distance < minAIDist) { minAIDist = distance; closestAI = i; } } // Create connection if we found both if (closestHuman !== -1 && closestAI !== -1) { panel2.connections.push({ human: closestHuman, ai: closestAI, strength: Math.random() * 0.5 0.5 }); // Make them pulse if (panel2.humans[closestHuman]) panel2.humans[closestHuman].size = 3; if (panel2.ais[closestAI]) panel2.ais[closestAI].size = 3; setTimeout(() => { if (panel2.humans[closestHuman]) panel2.humans[closestHuman].size -= 3; if (panel2.ais[closestAI]) panel2.ais[closestAI].size -= 3; }, 500); } } // Panel 3: Influence future branches else { for (let i = 0; i < panel3.branches.length; i ) { const branch = panel3.branches[i]; const endX = panel3.center.x Math.cos(branch.angle) * branch.length; const endY = panel3.center.y Math.sin(branch.angle) * branch.length; const dx = endX - x; const dy = endY - y; const distance = Math.sqrt(dx * dx dy * dy); if (distance < 50) { branch.strength = Math.min(branch.strength 0.2, 1.5); break; } } } } // Handle window resize function handleResize() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; panelWidth = canvas.width / 3; // Update panel 3 center panel3.center.x = panelWidth * 2.5; panel3.center.y = canvas.height / 2; } // Animation loop function animate() { update(); draw(); requestAnimationFrame(animate); } // Event listeners canvas.addEventListener('click', handleClick); window.addEventListener('resize', handleResize); // Start the visualization initialize(); animate(); </script> </body> </html> ```
2
4
28
631
代码:<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>创业成功之路 - 创意可视化</title> <!-- 加载p5.js --> <script src="cdnjs.cloudflare.com/ajax/li…"></script> <!-- 加载Tailwind CSS --> <script src="cdn.tailwindcss.com"></script> <style> body, html { margin: 0; padding: 0; overflow-x: hidden; } canvas { display: block; position: fixed; top: 0; left: 0; z-index: -1; } .content-container { position: relative; z-index: 10; } </style> </head> <body class="bg-transparent text-white"> <div id="canvas-container"></div> <div class="content-container w-full"> <div class="container mx-auto px-4 py-8"> <h1 class="text-4xl md:text-6xl font-bold text-center my-10 text-blue-400 drop-shadow-lg">创业成功之路</h1> <div class="steps-container space-y-40 pb-40"> <!-- 步骤内容会通过JS动态创建 --> </div> </div> </div> <script> // 创业步骤数据 const entrepreneurshipSteps = [ { id: 'idea', title: '创意启发', description: '每一次伟大的创业旅程都始于一个解决问题的想法。寻找那个让你夜不能寐的问题,那个你充满激情想要解决的挑战。', quote: '伟大的公司不是因为想要创办公司而成立的,而是因为创始人想要解决一个他们认为非常重要的问题。', author: '- Paul Graham', color: '#FF5722' }, { id: 'validate', title: '市场验证', description: '验证你的想法是否有市场。与潜在客户交谈,了解他们的真实需求,评估他们是否愿意为你的解决方案付费。', quote: '如果我们创造的东西没有用户愿意使用,那么我们就失败了。', author: '- Eric Ries', color: '#4CAF50' }, { id: 'mvp', title: '最小化可行产品', description: '构建一个解决核心问题的最简版本。不要追求完美,而是快速交付并从真实用户那里获得反馈。', quote: '如果你对自己的第一个版本不感到尴尬,那么你发布得太晚了。', author: '- Reid Hoffman', color: '#2196F3' }, { id: 'users', title: '获取早期用户', description: '找到你的第一批真正热爱你产品的用户。他们的反馈和支持将成为你持续前进的动力。', quote: '做得不可扩展的事情。', author: '- Paul Graham', color: '#9C27B0' }, { id: 'iterate', title: '迭代优化', description: '根据用户反馈持续改进产品。每一次迭代都应该让产品变得更好、更符合市场需求。', quote: '创新不是一个灵光乍现的时刻,而是一个持续迭代的过程。', author: '- Steve Jobs', color: '#FFC107' }, { id: 'scale', title: '规模扩大', description: '当产品得到验证后,是时候考虑如何扩大规模了。这涉及到团队扩张、市场拓展和运营优化。', quote: '先让爱你的人爱上你的产品,然后再让他们把这份爱传递给其他人。', author: '- Sam Altman', color: '#E91E63' }, { id: 'sustain', title: '可持续发展', description: '建立可持续的商业模式,确保公司能够长期生存并继续创造价值。这是从创业到真正企业的转变。', quote: '商业的终极目标不是赚钱,而是为社会创造价值。赚钱只是一个必要条件。', author: '- Peter Drucker', color: '#00BCD4' } ]; let particles = []; let attractors = []; let currentStep = 0; let scrollY = 0; let targetScrollY = 0; const particleCount = 200; let noiseScale = 0.01; let flowIntensity = 0.5; function setup() { // 创建画布并放入容器 const canvas = createCanvas(windowWidth, windowHeight); canvas.parent('canvas-container'); // 初始化粒子 for (let i = 0; i < particleCount; i ) { particles.push({ x: random(width), y: random(height), size: random(3, 8), speedFactor: random(0.5, 2), color: color(255, 255, 255, 150), targetColor: color(255, 255, 255, 150) }); } // 创建吸引点 for (let i = 0; i < 5; i ) { attractors.push({ x: random(width), y: random(height), strength: random(0.5, 2), radius: random(100, 300) }); } // 创建步骤内容 const stepsContainer = document.querySelector('.steps-container'); entrepreneurshipSteps.forEach((step, index) => { const stepElement = document.createElement('div'); stepElement.id = step.id; stepElement.className = 'step-item bg-gray-900 bg-opacity-80 p-8 rounded-lg shadow-xl mx-auto max-w-4xl transform transition-all duration-500 backdrop-blur-sm'; // 根据索引交替布局方向 if (index % 2 === 0) { stepElement.classList.add('md:ml-0'); stepElement.classList.add('md:mr-auto'); } else { stepElement.classList.add('md:ml-auto'); stepElement.classList.add('md:mr-0'); } stepElement.innerHTML = ` <div class="flex flex-col md:flex-row items-start gap-6"> <div class="step-number text-9xl font-bold opacity-20" style="color: ${step.color}">${index 1}</div> <div class="flex-1"> <h2 class="text-3xl font-bold mb-4" style="color: ${step.color}">${step.title}</h2> <p class="text-xl mb-6">${step.description}</p> <blockquote class="border-l-4 pl-4 italic my-4" style="border-color: ${step.color}"> "${step.quote}"<br> <span class="text-sm mt-2 block">${step.author}</span> </blockquote> </div> </div> `; stepsContainer.appendChild(stepElement); }); // 监听滚动事件 window.addEventListener('scroll', function() { targetScrollY = window.scrollY; // 确定当前步骤 const stepsElements = document.querySelectorAll('.step-item'); stepsElements.forEach((el, index) => { const rect = el.getBoundingClientRect(); if (rect.top <= window.innerHeight / 2 && rect.bottom >= window.innerHeight / 2) { if (currentStep !== index) { console.log("Moving to step", index 1); currentStep = index; // 更新粒子目标颜色 const stepColor = entrepreneurshipSteps[currentStep].color; const c = color(stepColor); for (let p of particles) { p.targetColor = color(red(c), green(c), blue(c), random(50, 150)); } // 更新流动强度 flowIntensity = map(currentStep, 0, entrepreneurshipSteps.length - 1, 0.2, 2); // 重新定位吸引点 for (let i = 0; i < attractors.length; i ) { attractors[i].x = random(width); attractors[i].y = random(height); attractors[i].strength = random(0.5, 2) * (currentStep 1) / 4; } } } }); }); } function draw() { // 平滑滚动动画 scrollY = lerp(scrollY, targetScrollY, 0.1); // 绘制背景 background(15, 20, 30, 20); // 半透明背景产生拖尾效果 // 更新吸引点 updateAttractors(); // 更新噪声系数 noiseScale = map(sin(frameCount * 0.01), -1, 1, 0.005, 0.015); // 更新和绘制粒子 updateParticles(); // 绘制连接线 drawConnections(); } function updateAttractors() { for (let a of attractors) { // 让吸引点缓慢移动 a.x = sin(frameCount * 0.01 a.strength) * 0.5; a.y = cos(frameCount * 0.01 a.strength) * 0.5; // 确保吸引点保持在屏幕内 a.x = constrain(a.x, 0, width); a.y = constrain(a.y, 0, height); } } function updateParticles() { for (let i = 0; i < particles.length; i ) { let p = particles[i]; // 平滑颜色过渡 p.color = lerpColor(p.color, p.targetColor, 0.05); // 基于噪声的运动 let angle = noise(p.x * noiseScale, p.y * noiseScale, frameCount * 0.005) * TWO_PI * 2; let speed = p.speedFactor * flowIntensity; // 添加创业阶段的影响 let stepInfluence = map(currentStep, 0, entrepreneurshipSteps.length - 1, 0.5, 2); speed *= stepInfluence; // 基础运动 let vx = cos(angle) * speed; let vy = sin(angle) * speed; // 添加吸引点的影响 for (let a of attractors) { let d = dist(p.x, p.y, a.x, a.y); if (d < a.radius) { let force = map(d, 0, a.radius, a.strength, 0); let angle = atan2(a.y - p.y, a.x - p.x); vx = cos(angle) * force; vy = sin(angle) * force; } } p.x = vx; p.y = vy; // 屏幕边界检查 if (p.x < -50) p.x = width 50; if (p.x > width 50) p.x = -50; if (p.y < -50) p.y = height 50; if (p.y > height 50) p.y = -50; // 绘制粒子 noStroke(); fill(p.color); circle(p.x, p.y, p.size); } } function drawConnections() { // 绘制粒子之间的连接线 stroke(255, 255, 255, 20); strokeWeight(0.5); for (let i = 0; i < particles.length; i ) { let connectCount = 0; // 限制每个粒子的连接数 for (let j = i 1; j < particles.length && connectCount < 3; j ) { let p1 = particles[i]; let p2 = particles[j]; let d = dist(p1.x, p1.y, p2.x, p2.y); // 只在一定距离内的粒子之间绘制连接线 if (d < 80) { let alpha = map(d, 0, 80, 50, 0); stroke(red(p1.color), green(p1.color), blue(p1.color), alpha); line(p1.x, p1.y, p2.x, p2.y); connectCount ; } } } } // 辅助函数:线性插值 function lerp(start, end, amt) { return (1 - amt) * start amt * end; } // 窗口调整大小时重设画布 function windowResized() { resizeCanvas(windowWidth, windowHeight); } </script> </body> </html>

1
2
2,997
21 Feb 2025
<!DOCTYPE html> <html> <head> <title>DIFender by The BYMP</title> <style> canvas { display: block; } body { margin: 0; overflow: hidden; background: black; } </style> </head> <body> <canvas id="gameCanvas"></canvas> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // Set canvas to full window size function resizeCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } window.addEventListener('resize', resizeCanvas); resizeCanvas(); // Game constants const GRID_SIZE = Math.floor(canvas.height / 20); const PLAYER_SIZE = GRID_SIZE; // Game states let gameState = 'start'; let score = 0; let gameTime = 0; let enemySpawnInterval = 60; // Scrolling text animation variables let scrollOffset = 0; const text = "DIFFEN-der by Mikael Pawlo"; const textSpeed = 2; const textSize = GRID_SIZE * 1.5; // Ground terrain const groundHeight = GRID_SIZE * 2; let groundPoints = []; let groundOffset = 0; function generateGround() { groundPoints = []; for (let x = -canvas.width; x <= canvas.width * 2; x = GRID_SIZE / 2) { groundPoints.push({ x: x, y: canvas.height - groundHeight Math.random() * groundHeight }); } } generateGround(); // Starry sky let stars = []; function generateStars() { stars = []; for (let i = 0; i < 100; i ) { stars.push({ x: Math.random() * canvas.width, y: Math.random() * (canvas.height - groundHeight), size: Math.random() * 2 1, brightness: Math.random() }); } } generateStars(); // Sound effects (replace with local files in same folder as the HTML or hosted equivalents) const laserSound = new Audio('gun.wav'); // Laser shot const enemyExplosionSound = new Audio('ship.wav'); // Small explosion const playerExplosionSound = new Audio('enemy.wav'); // Big explosion // Preload sounds and handle cloning for overlapping playback function playSound(sound) { const clone = sound.cloneNode(true); // Clone to allow overlapping clone.volume = 0.5; // Adjust volume (0.0 to 1.0) clone.play().catch(e => console.log("Audio play failed:", e)); // Handle autoplay restrictions } // Explosion class class Explosion { constructor(x, y, isPlayerDeath = false) { this.x = x; this.y = y; this.particles = []; this.duration = isPlayerDeath ? 40 : 30; const particleCount = isPlayerDeath ? 50 : 30; for (let i = 0; i < particleCount; i ) { const angle = Math.random() * Math.PI * 2; const speed = Math.random() * (isPlayerDeath ? 7 : 5) 2; this.particles.push({ x: 0, y: 0, vx: Math.cos(angle) * speed, vy: Math.sin(angle) * speed, size: Math.random() * (isPlayerDeath ? 8 : 6) 2, life: this.duration, color: Math.random() < 0.5 ? '#ff4500' : '#ffff00' }); } // Play sound based on type playSound(isPlayerDeath ? playerExplosionSound : enemyExplosionSound); } update() { this.particles.forEach(p => { p.x = p.vx; p.y = p.vy; p.vx *= 0.98; p.vy *= 0.98; p.life--; }); this.particles = this.particles.filter(p => p.life > 0); } draw() { this.particles.forEach(p => { ctx.fillStyle = p.color; ctx.beginPath(); const size = p.size * (p.life / this.duration); ctx.arc(this.x p.x, this.y p.y, size, 0, Math.PI * 2); ctx.fill(); }); } } // Appreciation message class class Appreciation { constructor(x, y) { this.x = x; this.y = y; this.text = " 100 Nice Save!"; this.life = 60; } update() { this.y -= 1; this.life--; } draw() { ctx.font = `${GRID_SIZE * 0.8}px monospace`; ctx.fillStyle = `rgba(0, 255, 255, ${this.life / 60})`; ctx.textAlign = 'center'; ctx.fillText(this.text, this.x, this.y); } } // Game objects class Player { constructor() { this.reset(); } reset() { this.x = GRID_SIZE * 2; this.y = canvas.height / 2; this.width = PLAYER_SIZE; this.height = PLAYER_SIZE / 2; this.speed = 5; this.bullets = []; this.direction = 1; } draw() { ctx.fillStyle = 'white'; ctx.beginPath(); if (this.direction === 1) { ctx.moveTo(this.x this.width, this.y this.height / 2); ctx.lineTo(this.x, this.y); ctx.lineTo(this.x, this.y this.height); } else { ctx.moveTo(this.x, this.y this.height / 2); ctx.lineTo(this.x this.width, this.y); ctx.lineTo(this.x this.width, this.y this.height); } ctx.closePath(); ctx.fill(); } move(direction) { if (direction === 'up' && this.y > 0) this.y -= this.speed; if (direction === 'down' && this.y < canvas.height - this.height) this.y = this.speed; if (direction === 'left') { this.x -= this.speed; this.direction = -1; if (this.x < 0) this.x = canvas.width - this.width; } if (direction === 'right') { this.x = this.speed; this.direction = 1; if (this.x > canvas.width) this.x = 0; } } shoot() { this.bullets.push(new Bullet(this.x (this.direction === 1 ? this.width : 0), this.y this.height / 2, this.direction)); playSound(laserSound); } checkGroundCollision() { const playerBottom = this.y this.height; for (let i = 0; i < groundPoints.length - 1; i ) { const adjustedX = groundPoints[i].x - groundOffset; const nextAdjustedX = groundPoints[i 1].x - groundOffset; if (this.x this.width > adjustedX && this.x < nextAdjustedX) { const groundY = Math.min(groundPoints[i].y, groundPoints[i 1].y); if (playerBottom > groundY) return true; } } return false; } } class Bullet { constructor(x, y, direction) { this.x = x; this.y = y; this.width = GRID_SIZE / 2; this.height = GRID_SIZE / 4; this.speed = 8 * direction; } update() { this.x = this.speed; } draw() { ctx.fillStyle = 'yellow'; ctx.fillRect(this.x, this.y, this.width, this.height); } } class Enemy { constructor() { this.x = Math.random() < 0.5 ? -GRID_SIZE : canvas.width; this.startY = Math.random() * (canvas.height - groundHeight - GRID_SIZE * 2); this.y = this.startY; this.width = GRID_SIZE; this.height = GRID_SIZE; this.speed = (this.x < 0 ? 3 : -3); this.type = Math.floor(Math.random() * 3); this.color = ['#ff0000', '#ff00ff', '#ffff00'][this.type]; this.isSinus = Math.random() < 0.5; this.sinusAmplitude = GRID_SIZE; this.sinusFrequency = 0.05; this.sinusPhase = 0; } update() { this.x = this.speed; if (this.isSinus) { this.sinusPhase = this.sinusFrequency; this.y = this.startY Math.sin(this.sinusPhase) * this.sinusAmplitude; } } draw() { ctx.fillStyle = this.color; ctx.beginPath(); if (this.type === 0) { ctx.fillRect(this.x, this.y, this.width, this.height); } else if (this.type === 1) { ctx.moveTo(this.x this.width / 2, this.y); ctx.lineTo(this.x, this.y this.height); ctx.lineTo(this.x this.width, this.y this.height); ctx.closePath(); ctx.fill(); } else if (this.type === 2) { ctx.arc(this.x this.width / 2, this.y this.height / 2, this.width / 2, 0, Math.PI * 2); ctx.fill(); } } } class Human { constructor() { this.x = canvas.width * 0.75; this.y = canvas.height - groundHeight - GRID_SIZE / 2; this.width = GRID_SIZE / 2; this.height = GRID_SIZE; this.speed = 1; } update() { this.x -= this.speed; } draw() { ctx.fillStyle = 'blue'; ctx.fillRect(this.x, this.y, this.width, this.height); } } // Game state let player = new Player(); let enemies = []; let humans = []; let explosions = []; let appreciations = []; let enemySpawnTimer = 0; let humanSpawnTimer = 0; // Start screen with scrolling text function drawStartScreen() { ctx.fillStyle = 'black'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.font = `${textSize}px monospace`; ctx.fillStyle = '#00ff00'; ctx.shadowColor = '#ff00ff'; ctx.shadowBlur = 10; ctx.textAlign = 'left'; const textWidth = ctx.measureText(text).width; scrollOffset -= textSpeed; if (scrollOffset < -textWidth) scrollOffset = canvas.width; ctx.fillText(text, scrollOffset, canvas.height / 2); ctx.shadowBlur = 0; ctx.font = `${GRID_SIZE * 0.8}px monospace`; ctx.fillStyle = '#00ffff'; ctx.textAlign = 'center'; ctx.fillText('Press Space to Play', canvas.width / 2, canvas.height / 2 GRID_SIZE * 2); } // Input handling const keys = {}; document.addEventListener('keydown', (e) => { keys[e.key] = true; if ((gameState === 'start' || gameState === 'dead') && e.key === ' ') { if (gameState === 'dead') { score = 0; player = new Player(); enemies = []; humans = []; explosions = []; appreciations = []; enemySpawnTimer = 0; humanSpawnTimer = 0; gameTime = 0; enemySpawnInterval = 60; groundOffset = 0; } gameState = 'playing'; } else if (gameState === 'playing' && e.key === ' ') { player.shoot(); } }); document.addEventListener('keyup', (e) => { keys[e.key] = false; }); // Collision detection function checkCollision(rect1, rect2) { return rect1.x < rect2.x rect2.width && rect1.x rect1.width > rect2.x && rect1.y < rect2.y rect2.height && rect1.y rect1.height > rect2.y; } // Game loop function gameLoop() { if (gameState === 'start') { drawStartScreen(); } else if (gameState === 'playing') { ctx.fillStyle = 'black'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw starry sky stars.forEach(star => { ctx.fillStyle = `rgba(255, 255, 255, ${star.brightness})`; ctx.beginPath(); ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2); ctx.fill(); }); // Update ground scroll const groundSpeed = player.direction * 1; groundOffset = groundSpeed; if (groundOffset > canvas.width) groundOffset -= canvas.width * 2; if (groundOffset < -canvas.width) groundOffset = canvas.width * 2; // Draw ground ctx.beginPath(); ctx.fillStyle = '#555555'; ctx.moveTo(0, canvas.height); groundPoints.forEach(point => { const adjustedX = point.x - groundOffset; if (adjustedX >= -GRID_SIZE && adjustedX <= canvas.width GRID_SIZE) { ctx.lineTo(adjustedX, point.y); } }); ctx.lineTo(canvas.width, canvas.height); ctx.closePath(); ctx.fill(); ctx.fillStyle = '#00ff00'; ctx.beginPath(); groundPoints.forEach((point, i) => { const adjustedX = point.x - groundOffset; if (i % 3 === 0 && adjustedX >= -GRID_SIZE && adjustedX <= canvas.width GRID_SIZE) { ctx.fillRect(adjustedX, point.y - GRID_SIZE / 4, GRID_SIZE / 2, GRID_SIZE / 4); } }); ctx.fill(); // Handle player movement if (keys['ArrowUp']) player.move('up'); if (keys['ArrowDown']) player.move('down'); if (keys['ArrowLeft']) player.move('left'); if (keys['ArrowRight']) player.move('right'); // Draw and update player player.draw(); player.bullets.forEach((bullet, index) => { bullet.update(); bullet.draw(); if (bullet.x > canvas.width || bullet.x < -bullet.width) player.bullets.splice(index, 1); }); if (player.checkGroundCollision()) { explosions.push(new Explosion(player.x player.width / 2, player.y player.height / 2, true)); gameState = 'dead'; } // Increment game time and adjust enemy spawn rate gameTime ; if (gameTime % (60 * 30) === 0) { enemySpawnInterval = Math.max(20, enemySpawnInterval - 10); } // Spawn enemies enemySpawnTimer ; if (enemySpawnTimer > enemySpawnInterval) { enemies.push(new Enemy()); enemySpawnTimer = 0; } // Update and draw enemies enemies.forEach((enemy, eIndex) => { enemy.update(); enemy.draw(); if (checkCollision(player, enemy)) { explosions.push(new Explosion(player.x player.width / 2, player.y player.height / 2, true)); gameState = 'dead'; } player.bullets.forEach((bullet, bIndex) => { if (checkCollision(bullet, enemy)) { explosions.push(new Explosion(enemy.x enemy.width / 2, enemy.y enemy.height / 2)); enemies.splice(eIndex, 1); player.bullets.splice(bIndex, 1); score = 10; } }); if (enemy.x < -enemy.width || enemy.x > canvas.width) enemies.splice(eIndex, 1); }); // Spawn humans humanSpawnTimer ; if (humanSpawnTimer > 120) { humans.push(new Human()); humanSpawnTimer = 0; } // Update and draw humans humans.forEach((human, hIndex) => { human.update(); human.draw(); if (checkCollision(player, human)) { appreciations.push(new Appreciation(human.x, human.y)); humans.splice(hIndex, 1); score = 100; } if (human.x < -human.width) humans.splice(hIndex, 1); }); // Update and draw explosions explosions.forEach((explosion, index) => { explosion.update(); explosion.draw(); if (explosion.particles.length === 0) explosions.splice(index, 1); }); // Update and draw appreciations appreciations.forEach((appreciation, index) => { appreciation.update(); appreciation.draw(); if (appreciation.life <= 0) appreciations.splice(index, 1); }); // Draw score ctx.font = `${GRID_SIZE * 0.8}px monospace`; ctx.fillStyle = 'white'; ctx.textAlign = 'right'; ctx.fillText(`Score: ${score}`, canvas.width - GRID_SIZE, GRID_SIZE * 0.8); } else if (gameState === 'dead') { ctx.fillStyle = 'black'; ctx.fillRect(0, 0, canvas.width, canvas.height); stars.forEach(star => { ctx.fillStyle = `rgba(255, 255, 255, ${star.brightness})`; ctx.beginPath(); ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2); ctx.fill(); }); ctx.font = `${GRID_SIZE * 1.5}px monospace`; ctx.fillStyle = '#ff0000'; ctx.textAlign = 'center'; ctx.fillText('Game Over!', canvas.width / 2, canvas.height / 2 - GRID_SIZE); ctx.font = `${GRID_SIZE}px monospace`; ctx.fillStyle = '#ffffff'; ctx.fillText(`Score: ${score}`, canvas.width / 2, canvas.height / 2); ctx.font = `${GRID_SIZE * 0.8}px monospace`; ctx.fillStyle = '#00ffff'; ctx.fillText('Press Space to Restart', canvas.width / 2, canvas.height / 2 GRID_SIZE * 2); explosions.forEach((explosion, index) => { explosion.update(); explosion.draw(); if (explosion.particles.length === 0) explosions.splice(index, 1); }); } requestAnimationFrame(gameLoop); } gameLoop(); </script> </body> </html>

2
1
2
1,096
💡Canvas-Confetti JavaScript library that creates a confetti animation - install: `npm install canvas-confetti` - particleCount: The total number of confetti pieces. - spread: Controls how wide the confetti scatters (in degrees). - origin: Determines the starting point.
1
38
5 Aug 2024
Dopamine rush for your startup's customers: 1. npm i canvas-confetti 2. confetti({ particleCount: 200, spread: 400, origin: { y: 0.5 }, }); 3. MRR goes brrrr
54
33
951
74,072
Replying to @hackmamba
No benchmarks. Feel-wise, on my old android, setting particleCount to 200 makes it feel janky. On my M1 pro macbook, even 400 is decent. Depends on the device. Canvas based rendering would be faster and more powerful, but it'd be really huge in size. With this package, I'm intentionally compromising perf for bundle size.
3
185
Measuring both #particlemass & #particlecount, the Aerocet 532 is the perfect addition to any #IAQ expert’s tool kit. This sleek #handheld #sensor simultaneously measures & records PM1, PM2.5, PM4, PM7, PM10, and total suspended particulate (TSP). metone.com/products/aerocet-…
3
Met One's Aerocet 532 measures both #particlemass & #particlecount. This full-featured #particlemonitor is the perfect addition to any indoor air quality expert’s tool kit. ➡️ Learn more about this handheld monitor’s capabilities here: metone.com/products/aerocet-…
3
Measuring both #particlemass & #particlecount, the Aerocet 532 is the perfect addition to any #IAQ expert’s tool kit. This sleek #handheld #sensor simultaneously measures & records PM1, PM2.5, PM4, PM7, PM10, and total suspended particulate (TSP). metone.com/products/aerocet-…
5
【進捗64日目!】 NVIDIA flex for unityで 水を小さくすることに 成功しました! 粒子の数(ParticleCount)と 体積(Scale)の比率が 関係あるみたいです! 体積が小さく粒子の数が多いと ゲーム開始直後に爆発します! 最初3500粒あったのを 8粒に減らして 体積も小さくなり ビーカーに入りました!
2
8
...this is one for anyone remotely interested in #Cholesterol, #LDL, #ApoB, #ParticleCount, #NMR, #AdvancedLipoprotein, #Lipoprotein or any of that stuff!
Replying to @FatEmperor
Hello there is your unroll: Thread by @ZahcM: "Decided to make a thread on the failures of apoB or LDL-P. All related info on this topic will go here. The AURORA trial […]" threadreaderapp.com/thread/1… Enjoy :) 🤖
3
12
Replying to @thespite
I had something like particleCount = 5M; and then I realized I had somewhere else pcount = Math.min(MAX_PARTICLE_COUNT, pcount) with MAX_PCOUNT = 1M :_D
1
23 Mar 2018
Breaking Down the Technical #Cleanliness Workflow Part 3: #ParticleSize Classification and #ParticleCount Extrapolation and Normalization #science #olympus #particlesizing #microscopy #metallography olympus-ims.com/en/insight/b…
1