<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>SONIC_KINTSUGI_V7</title>
<style>
body { margin: 0; background: #000; overflow: hidden; display: flex; justify-content: center; align-items: center; height: 100vh; touch-action: none; font-family: 'Courier New', monospace; color: #ffcc00; }
canvas { display: block; position: absolute; top: 0; left: 0; }
#controls { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: rgba(0, 0, 0, 0.8); padding: 10px 15px; border-radius: 8px; border: 1px solid #ffcc00; z-index: 10; display: flex; flex-direction: column; align-items: center; gap: 5px; font-size: 11px; }
#exponentSlider { width: 120px; }
#startBtn { padding: 5px 10px; background: #ffcc00; border: none; border-radius: 4px; color: #000; cursor: pointer; font-weight: bold; margin-bottom: 5px; }
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<div id="controls">
<button id="startBtn">IGNITE RESONANCE</button>
<label>PHASE STATE:</label>
<input type="range" id="exponentSlider" min="0" max="1" step="0.01" value="1">
<span id="label">STABLE</span>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
let scene, camera, renderer, group, audioCtx, osc, gainNode, filter;
let time = 0, scatterHistory = 0;
const layers = [];
let exponentType = 1;
function initAudio() {
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
osc = audioCtx.createOscillator();
gainNode = audioCtx.createGain();
filter = audioCtx.createBiquadFilter();
osc.type = 'sine';
osc.frequency.setValueAtTime(60, audioCtx.currentTime); // Base Deep Hum
filter.type = 'lowpass';
osc.connect(filter);
filter.connect(gainNode);
gainNode.connect(audioCtx.destination);
gainNode.gain.setValueAtTime(0.01, audioCtx.currentTime);
osc.start();
document.getElementById('startBtn').style.display = 'none';
}
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
group = new THREE.Group();
scene.add(group);
for (let i = 0; i < 9; i++) {
const geometry = new THREE.TorusKnotGeometry(2, 0.25, 400, 50, i + 3, i + 2);
const material = new THREE.MeshStandardMaterial({
color: 0xffffff, wireframe: true, transparent: true, opacity: 0.1,
emissive: new THREE.Color(), emissiveIntensity: 0.5
});
const mesh = new THREE.Mesh(geometry, material);
group.add(mesh);
layers.push(mesh);
}
document.getElementById('exponentSlider').addEventListener('input', (e) => {
exponentType = parseFloat(e.target.value);
document.getElementById('label').textContent = exponentType < 0.5 ? "SCATTERING" : "STABLE";
});
document.getElementById('startBtn').addEventListener('click', initAudio);
animate();
}
function animate() {
requestAnimationFrame(animate);
time += 0.015;
if (exponentType < 0.9) scatterHistory += (1.0 - exponentType) * 0.03;
// Sync Audio to Phase and Gold
if (audioCtx) {
const freq = 60 - (scatterHistory * 0.5) + (exponentType * 10);
osc.frequency.setTargetAtTime(freq, audioCtx.currentTime, 0.1);
gainNode.gain.setTargetAtTime(0.05 + (1.0 - exponentType) * 0.1, audioCtx.currentTime, 0.1);
filter.frequency.setTargetAtTime(200 + (scatterHistory * 10), audioCtx.currentTime, 0.1);
}
camera.position.x = Math.sin(time * 0.05) * 0.8;
camera.position.y = Math.cos(time * 0.07) * 0.5;
camera.position.z = 10;
camera.lookAt(0, 0, 0);
layers.forEach((mesh, i) => {
const q = new THREE.Quaternion();
const axis = new THREE.Vector3(Math.sin(time*0.04+i), Math.cos(time*0.02+i), Math.sin(time*0.03)).normalize();
q.setFromAxisAngle(axis, 0.003 * exponentType);
mesh.quaternion.multiplyQuaternions(q, mesh.quaternion);
const scarIntensity = Math.min(scatterHistory * 0.05, 1.0);
const baseHue = (time * 0.01 + i / 9) % 1;
const traumaColor = new THREE.Color().setHSL(0.12, 1.0, 0.5);
const healthyColor = new THREE.Color().setHSL(baseHue, 0.8, 0.5);
mesh.material.emissive.lerpColors(healthyColor, traumaColor, scarIntensity);
mesh.scale.setScalar((1 + (1-exponentType) * 4) * (1 + Math.sin(time * 0.3 + i) * 0.05));
});
renderer.render(scene, camera);
}
init();
</script>
</body>
</html>