defragmentation / mandala_component.html
cjo93's picture
Update mandala_component.html
f9abdf9 verified
<div id="hexa-container" style="width: 100%; height: 100%; min-height: 300px; background: #000; border-radius: 12px; overflow: hidden; position: relative; border: 1px solid #222; box-shadow: 0 0 30px rgba(0,0,0,0.8);">
<canvas id="defragCanvas" style="width: 100%; height: 100%; display: block;"></canvas>
<div id="overlay" style="position: absolute; top: 20px; left: 20px; color: rgba(255,255,255,0.4); font-family: 'Courier New', monospace; font-size: 10px; pointer-events: none;">
SYSTEM: ONLINE<br>
AUDIO: ENABLED
</div>
</div>
<script>
class HexaMandala {
constructor(canvasId) {
this.canvas = document.getElementById(canvasId);
if (!this.canvas) return;
this.ctx = this.canvas.getContext('2d');
// Default State
this.hexCode = [1,0,1,0,1,0];
this.petalCount = 5;
this.element = 'water';
this.stability = 1.0;
this.speaking = false; // New: React to audio
this.time = 0;
this.resize();
this.initColors();
this.animate();
window.addEventListener('resize', () => this.resize());
}
resize() {
const parent = this.canvas.parentElement;
this.canvas.width = parent.clientWidth * window.devicePixelRatio;
this.canvas.height = parent.clientHeight * window.devicePixelRatio;
this.ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
this.width = parent.clientWidth;
this.height = parent.clientHeight;
}
initColors() {
this.colors = {
fire: { h: 10, s: 80, l: 50 },
earth: { h: 35, s: 60, l: 40 },
air: { h: 200, s: 70, l: 80 },
water: { h: 220, s: 90, l: 30 }
};
}
updateParams(hex, petals, elem, stab, isSpeaking) {
this.hexCode = hex || [1,1,1,1,1,1];
this.petalCount = petals || 5;
this.element = elem || 'water';
this.stability = stab !== undefined ? stab : 1.0;
if (isSpeaking !== undefined) this.speaking = isSpeaking;
}
drawHexRing(radius, index, isYang) {
this.ctx.beginPath();
if (isYang) {
this.ctx.arc(0, 0, radius, 0, Math.PI * 2);
this.ctx.lineWidth = 3;
this.ctx.strokeStyle = `rgba(255, 255, 255, ${0.15 + (index * 0.05)})`;
this.ctx.stroke();
} else {
this.ctx.setLineDash([5, 10]);
this.ctx.arc(0, 0, radius, 0, Math.PI * 2);
this.ctx.lineWidth = 2;
this.ctx.strokeStyle = `rgba(255, 255, 255, ${0.1 + (index * 0.05)})`;
this.ctx.stroke();
this.ctx.setLineDash([]);
}
}
animate() {
this.time += 0.01;
this.ctx.fillStyle = "#050505";
this.ctx.fillRect(0, 0, this.width, this.height);
this.ctx.save();
this.ctx.translate(this.width/2, this.height/2);
// Audio Reactivity (Pulse when speaking)
let audioPulse = this.speaking ? Math.sin(this.time * 10) * 5 : 0;
// Glitch Shake
if (this.stability < 0.5) {
let shake = (1.0 - this.stability) * 3;
this.ctx.translate((Math.random()-0.5)*shake, (Math.random()-0.5)*shake);
}
let baseR = Math.min(this.width, this.height) * 0.12;
// Draw Rings
this.hexCode.forEach((val, i) => {
let r = baseR + (i * 15) + audioPulse;
this.drawHexRing(r, i, val === 1);
});
// Draw Petals
let c = this.colors[this.element] || this.colors.water;
let count = this.petalCount;
for (let i = 0; i < count; i++) {
this.ctx.save();
let angle = (i / count) * Math.PI * 2 + (this.time * 0.1);
this.ctx.rotate(angle);
this.ctx.beginPath();
this.ctx.moveTo(0, 0);
this.ctx.quadraticCurveTo(baseR*1.5, baseR, 0, baseR*3 + audioPulse);
this.ctx.quadraticCurveTo(-baseR*1.5, baseR, 0, 0);
let alpha = 0.6 * this.stability;
this.ctx.fillStyle = `hsla(${c.h}, ${c.s}%, ${c.l}%, ${alpha})`;
this.ctx.fill();
this.ctx.restore();
}
this.ctx.restore();
requestAnimationFrame(() => this.animate());
}
}
// Initialize on load
setTimeout(() => {
window.hexa = new HexaMandala('defragCanvas');
}, 500);
</script>