Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -0,0 +1,335 @@
// modules/canvas-animations/InteractiveEffects.js
import { CanvasManager } from './CanvasManager.js';
import { useEvent } from '../../core/useEvent.js';
import { Logger } from '../../core/logger.js';
/**
* Interactive Canvas Effects - Mouse/touch interactions, hover effects
*/
export const InteractiveEffects = {
/**
* Initialize interactive canvas
*/
init(canvas, config) {
const manager = new CanvasManager(canvas);
const effectType = config.effect || 'ripple';
const state = {
mouse: { x: 0, y: 0, isOver: false },
effects: [],
lastTime: 0
};
this.setupInteractionEvents(canvas, manager, state, config);
this.startAnimationLoop(manager, state, effectType, config);
Logger.info('[InteractiveEffects] Initialized with effect:', effectType);
},
/**
* Setup mouse/touch interaction events
*/
setupInteractionEvents(canvas, manager, state, config) {
// Mouse events
useEvent(canvas, 'mousemove', (e) => {
const pos = manager.getMousePosition(e);
state.mouse.x = pos.x;
state.mouse.y = pos.y;
if (config.effect === 'trail') {
this.addTrailPoint(state, pos.x, pos.y);
}
}, 'interactive-effects');
useEvent(canvas, 'mouseenter', () => {
state.mouse.isOver = true;
}, 'interactive-effects');
useEvent(canvas, 'mouseleave', () => {
state.mouse.isOver = false;
}, 'interactive-effects');
useEvent(canvas, 'click', (e) => {
const pos = manager.getMousePosition(e);
this.addClickEffect(state, pos.x, pos.y, config);
}, 'interactive-effects');
// Touch events for mobile
useEvent(canvas, 'touchstart', (e) => {
e.preventDefault();
const touch = e.touches[0];
const pos = manager.getMousePosition(touch);
this.addClickEffect(state, pos.x, pos.y, config);
}, 'interactive-effects');
useEvent(canvas, 'touchmove', (e) => {
e.preventDefault();
const touch = e.touches[0];
const pos = manager.getMousePosition(touch);
state.mouse.x = pos.x;
state.mouse.y = pos.y;
state.mouse.isOver = true;
if (config.effect === 'trail') {
this.addTrailPoint(state, pos.x, pos.y);
}
}, 'interactive-effects');
useEvent(canvas, 'touchend', () => {
state.mouse.isOver = false;
}, 'interactive-effects');
},
/**
* Start animation loop
*/
startAnimationLoop(manager, state, effectType, config) {
const animate = (timestamp) => {
const deltaTime = timestamp - state.lastTime;
state.lastTime = timestamp;
manager.clear();
switch (effectType) {
case 'ripple':
this.renderRippleEffect(manager, state, config);
break;
case 'trail':
this.renderTrailEffect(manager, state, config);
break;
case 'particles':
this.renderParticleEffect(manager, state, config, deltaTime);
break;
case 'magnetic':
this.renderMagneticEffect(manager, state, config);
break;
default:
this.renderRippleEffect(manager, state, config);
}
// Update effects
this.updateEffects(state.effects, deltaTime);
requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
},
/**
* Add click effect (ripple, explosion, etc.)
*/
addClickEffect(state, x, y, config) {
const effect = {
x,
y,
age: 0,
maxAge: config.duration || 1000,
type: 'click',
intensity: config.intensity || 1
};
state.effects.push(effect);
},
/**
* Add trail point for mouse trail effect
*/
addTrailPoint(state, x, y) {
const point = {
x,
y,
age: 0,
maxAge: 500,
type: 'trail'
};
state.effects.push(point);
// Limit trail length
const trailLength = 20;
const trailPoints = state.effects.filter(e => e.type === 'trail');
if (trailPoints.length > trailLength) {
const oldestIndex = state.effects.indexOf(trailPoints[0]);
state.effects.splice(oldestIndex, 1);
}
},
/**
* Render ripple effect
*/
renderRippleEffect(manager, state, config) {
const { ctx } = manager;
// Draw active ripples
state.effects.forEach(effect => {
if (effect.type === 'click') {
const progress = effect.age / effect.maxAge;
const radius = progress * (config.maxRadius || 100);
const opacity = (1 - progress) * 0.8;
ctx.save();
ctx.globalAlpha = opacity;
ctx.strokeStyle = config.color || 'rgba(100, 150, 255, 1)';
ctx.lineWidth = config.lineWidth || 3;
ctx.beginPath();
ctx.arc(effect.x / manager.options.pixelRatio, effect.y / manager.options.pixelRatio, radius, 0, Math.PI * 2);
ctx.stroke();
ctx.restore();
}
});
// Draw hover effect
if (state.mouse.isOver) {
ctx.save();
ctx.globalAlpha = 0.3;
ctx.fillStyle = config.hoverColor || 'rgba(100, 150, 255, 0.3)';
ctx.beginPath();
ctx.arc(
state.mouse.x / manager.options.pixelRatio,
state.mouse.y / manager.options.pixelRatio,
config.hoverRadius || 30,
0,
Math.PI * 2
);
ctx.fill();
ctx.restore();
}
},
/**
* Render trail effect
*/
renderTrailEffect(manager, state, config) {
const { ctx } = manager;
const trailPoints = state.effects.filter(e => e.type === 'trail');
if (trailPoints.length < 2) return;
ctx.save();
ctx.strokeStyle = config.color || 'rgba(100, 150, 255, 0.8)';
ctx.lineWidth = config.lineWidth || 5;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
// Draw trail path
ctx.beginPath();
trailPoints.forEach((point, index) => {
const progress = 1 - (point.age / point.maxAge);
const x = point.x / manager.options.pixelRatio;
const y = point.y / manager.options.pixelRatio;
ctx.globalAlpha = progress * 0.8;
if (index === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
});
ctx.stroke();
ctx.restore();
},
/**
* Render particle effect
*/
renderParticleEffect(manager, state, config, deltaTime) {
const { ctx } = manager;
// Spawn particles on mouse move
if (state.mouse.isOver && Math.random() < 0.1) {
const particle = {
x: state.mouse.x,
y: state.mouse.y,
vx: (Math.random() - 0.5) * 4,
vy: (Math.random() - 0.5) * 4,
age: 0,
maxAge: 1000,
size: Math.random() * 5 + 2,
type: 'particle'
};
state.effects.push(particle);
}
// Update and draw particles
state.effects.forEach(effect => {
if (effect.type === 'particle') {
// Update position
effect.x += effect.vx;
effect.y += effect.vy;
effect.vy += 0.1; // Gravity
const progress = effect.age / effect.maxAge;
const opacity = (1 - progress) * 0.8;
ctx.save();
ctx.globalAlpha = opacity;
ctx.fillStyle = config.color || 'rgba(100, 150, 255, 1)';
ctx.beginPath();
ctx.arc(
effect.x / manager.options.pixelRatio,
effect.y / manager.options.pixelRatio,
effect.size * (1 - progress * 0.5),
0,
Math.PI * 2
);
ctx.fill();
ctx.restore();
}
});
},
/**
* Render magnetic effect
*/
renderMagneticEffect(manager, state, config) {
const { ctx } = manager;
const { width, height } = manager.getSize();
if (!state.mouse.isOver) return;
// Draw magnetic field lines
const centerX = width / 2;
const centerY = height / 2;
const mouseX = state.mouse.x / manager.options.pixelRatio;
const mouseY = state.mouse.y / manager.options.pixelRatio;
ctx.save();
ctx.strokeStyle = config.color || 'rgba(100, 150, 255, 0.6)';
ctx.lineWidth = 2;
const lines = 8;
for (let i = 0; i < lines; i++) {
const angle = (i / lines) * Math.PI * 2;
const startX = centerX + Math.cos(angle) * 50;
const startY = centerY + Math.sin(angle) * 50;
// Curve towards mouse
const controlX = (startX + mouseX) / 2 + Math.sin(angle) * 30;
const controlY = (startY + mouseY) / 2 + Math.cos(angle) * 30;
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.quadraticCurveTo(controlX, controlY, mouseX, mouseY);
ctx.stroke();
}
ctx.restore();
},
/**
* Update all effects (age and cleanup)
*/
updateEffects(effects, deltaTime) {
for (let i = effects.length - 1; i >= 0; i--) {
effects[i].age += deltaTime;
if (effects[i].age >= effects[i].maxAge) {
effects.splice(i, 1);
}
}
}
};