improvements

This commit is contained in:
Michal Vrba
2026-09-03 17:54:36 +02:00
parent 00aa94ea7c
commit 035da18584
14 changed files with 1006 additions and 52 deletions
+158 -3
View File
@@ -3,11 +3,23 @@
window.FaraonFx = (function () {
let audioCtx = null;
let isMuted = false;
let speedMultiplier = 1.0;
let particleCanvas = null;
let particleCtx = null;
let particles = [];
let animationFrameId = null;
function setSpeedLevel(level) {
switch (level) {
case 1: speedMultiplier = 0.7; break; // 0.5x
case 2: speedMultiplier = 0.85; break; // 0.75x
case 4: speedMultiplier = 1.5; break; // 1.5x
case 5: speedMultiplier = 2.4; break; // 2.5x Turbo
case 3:
default: speedMultiplier = 1.0; break;
}
}
function getAudioContext() {
if (!audioCtx) {
const AudioContext = window.AudioContext || window.webkitAudioContext;
@@ -168,6 +180,79 @@ window.FaraonFx = (function () {
triggerScreenShake(3);
}
function playIceCrack() {
if (isMuted) return;
const ctx = getAudioContext();
if (!ctx) return;
const now = ctx.currentTime;
// Sharp ice snap noise
const bufferSize = ctx.sampleRate * 0.12;
const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
const data = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
data[i] = (Math.random() * 2 - 1) * Math.exp(-i / (ctx.sampleRate * 0.02));
}
const noise = ctx.createBufferSource();
noise.buffer = buffer;
const filter = ctx.createBiquadFilter();
filter.type = 'highpass';
filter.frequency.setValueAtTime(3200, now);
const gain = ctx.createGain();
gain.gain.setValueAtTime(0.45, now);
gain.gain.exponentialRampToValueAtTime(0.001, now + 0.12);
noise.connect(filter);
filter.connect(gain);
gain.connect(ctx.destination);
noise.start(now);
// Resonant high crystal ringing
[2400, 3600, 4800].forEach((freq, idx) => {
const osc = ctx.createOscillator();
const oscGain = ctx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(freq + Math.random() * 200, now + idx * 0.02);
oscGain.gain.setValueAtTime(0.12, now + idx * 0.02);
oscGain.gain.exponentialRampToValueAtTime(0.001, now + idx * 0.02 + 0.22);
osc.connect(oscGain);
oscGain.connect(ctx.destination);
osc.start(now + idx * 0.02);
osc.stop(now + idx * 0.02 + 0.23);
});
triggerScreenShake(4);
}
function playLeafShield() {
if (isMuted) return;
const ctx = getAudioContext();
if (!ctx) return;
const now = ctx.currentTime;
[523.25, 659.25, 783.99, 1046.50].forEach((freq, idx) => {
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.type = 'triangle';
osc.frequency.setValueAtTime(freq, now + idx * 0.05);
gain.gain.setValueAtTime(0.2, now + idx * 0.05);
gain.gain.exponentialRampToValueAtTime(0.001, now + idx * 0.05 + 0.35);
osc.connect(gain);
gain.connect(ctx.destination);
osc.start(now + idx * 0.05);
osc.stop(now + idx * 0.05 + 0.36);
});
triggerScreenShake(2);
}
function playHornikChime() {
if (isMuted) return;
const ctx = getAudioContext();
@@ -386,7 +471,7 @@ window.FaraonFx = (function () {
opacity: 1
}
], {
duration: 420,
duration: Math.round(420 / speedMultiplier),
easing: 'cubic-bezier(0.175, 0.885, 0.32, 1.2)'
});
@@ -429,7 +514,7 @@ window.FaraonFx = (function () {
{ transform: `translate(-50%, -50%) translate3d(${dx * 0.5}px, ${dy * 0.5 - 30}px, 0) scale(1.15) rotate(10deg)`, opacity: 1, offset: 0.5 },
{ transform: `translate(-50%, -50%) translate3d(${dx}px, ${dy}px, 0) scale(0.6) rotate(0deg)`, opacity: 0.2 }
], {
duration: 380,
duration: Math.round(380 / speedMultiplier),
easing: 'cubic-bezier(0.25, 1, 0.5, 1)'
});
@@ -513,7 +598,7 @@ window.FaraonFx = (function () {
const midX = (startPos.x + endPos.x) / 2;
const midY = Math.min(startPos.y, endPos.y) - 35;
const duration = 380;
const duration = Math.round(380 / speedMultiplier);
const startTime = performance.now();
function step(currentTime) {
@@ -693,6 +778,71 @@ window.FaraonFx = (function () {
}
}
function triggerIceShatter(position) {
if (!particleCanvas) return;
let x = window.innerWidth / 2;
let y = window.innerHeight / 2;
if (typeof position === 'string') {
const elem = getSlotElement(position);
const coords = elem ? getElementCenter(elem) : getPositionCoords(position);
x = coords.x;
y = coords.y;
} else if (position && position.x && position.y) {
x = position.x;
y = position.y;
}
playIceCrack();
const colors = ['#00ffff', '#80d8ff', '#e0f7fa', '#ffffff', '#b2ebf2', '#87cefa'];
for (let i = 0; i < 40; i++) {
const angle = Math.random() * Math.PI * 2;
const speed = 3 + Math.random() * 10;
particles.push({
x: x + (Math.random() - 0.5) * 50,
y: y + (Math.random() - 0.5) * 40,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed - 2.5,
gravity: 0.22,
size: 6 + Math.random() * 9,
aspect: 0.35 + Math.random() * 1.5,
color: colors[Math.floor(Math.random() * colors.length)],
shape: Math.random() > 0.35 ? 'rect' : 'spark',
life: 1.1,
decay: 0.022 + Math.random() * 0.02,
rotation: Math.random() * Math.PI * 2,
vRot: (Math.random() - 0.5) * 0.4
});
}
}
function triggerLeafParticles(x, y, count = 35) {
if (!particleCanvas) return;
const startX = x || window.innerWidth / 2;
const startY = y || window.innerHeight / 2;
const colors = ['#2d6a4f', '#52b788', '#74c69d', '#b7e4c7', '#d8f3dc', '#ffd700'];
for (let i = 0; i < count; i++) {
const angle = Math.random() * Math.PI * 2;
const speed = 2.5 + Math.random() * 8;
particles.push({
x: startX + (Math.random() - 0.5) * 30,
y: startY + (Math.random() - 0.5) * 30,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed - 1.5,
gravity: 0.12,
size: 5 + Math.random() * 7,
aspect: 0.4 + Math.random() * 1.5,
color: colors[Math.floor(Math.random() * colors.length)],
shape: 'spark',
life: 1.0,
decay: 0.025 + Math.random() * 0.02,
rotation: Math.random() * Math.PI * 2,
vRot: (Math.random() - 0.5) * 0.3
});
}
}
function triggerBurnExplosion(x, y) {
if (!particleCanvas) return;
const colors = ['#ff0000', '#ff4500', '#ffaa00', '#333333', '#ffffff'];
@@ -1016,6 +1166,8 @@ window.FaraonFx = (function () {
playCardDraw,
playSevenStack,
playAceFreeze,
playIceCrack,
playLeafShield,
playHornikChime,
playBurnExplosion,
playVictory,
@@ -1029,6 +1181,8 @@ window.FaraonFx = (function () {
initParticles,
triggerFireParticles,
triggerIceParticles,
triggerIceShatter,
triggerLeafParticles,
triggerBurnExplosion,
triggerConfetti,
triggerCoinJackpot,
@@ -1037,6 +1191,7 @@ window.FaraonFx = (function () {
animateCardPlay,
animateCardDraw,
animateTurnTransition,
setSpeedLevel,
toggleMute
};
})();