This commit is contained in:
36
src/App.vue
36
src/App.vue
@@ -178,13 +178,17 @@
|
||||
'--ray-hue': rayHue.toFixed(0)
|
||||
}"
|
||||
></div>
|
||||
<div
|
||||
class="pulse-rays"
|
||||
:style="{
|
||||
'--ray': rayLevel.toFixed(3),
|
||||
'--ray-hue': rayHue.toFixed(0)
|
||||
}"
|
||||
></div>
|
||||
<div class="pulse-tentacles">
|
||||
<span
|
||||
v-for="(level, index) in tentacleLevels"
|
||||
:key="index"
|
||||
class="tentacle"
|
||||
:style="{
|
||||
'--level': level.toFixed(3),
|
||||
'--index': index
|
||||
}"
|
||||
></span>
|
||||
</div>
|
||||
<audio
|
||||
ref="player"
|
||||
v-if="currentClipUrl"
|
||||
@@ -283,7 +287,8 @@ export default {
|
||||
mediaElement: null as HTMLAudioElement | null,
|
||||
rayLevel: 0,
|
||||
rayHue: 200,
|
||||
isAnswerClip: false
|
||||
isAnswerClip: false,
|
||||
tentacleLevels: Array.from({ length: 12 }, () => 0)
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
@@ -369,6 +374,7 @@ export default {
|
||||
this.frequencyData = new Uint8Array(analyser.frequencyBinCount)
|
||||
this.pulseLevel = 0
|
||||
this.rayLevel = 0
|
||||
this.tentacleLevels = this.tentacleLevels.map(() => 0)
|
||||
},
|
||||
teardownAudio() {
|
||||
if (this.rafId) {
|
||||
@@ -389,6 +395,7 @@ export default {
|
||||
this.isPlaying = false
|
||||
this.pulseLevel = 0
|
||||
this.rayLevel = 0
|
||||
this.tentacleLevels = this.tentacleLevels.map(() => 0)
|
||||
},
|
||||
startPulse() {
|
||||
if (!this.analyser || !this.analyserData || !this.frequencyData) return
|
||||
@@ -428,6 +435,19 @@ export default {
|
||||
this.rayLevel = this.rayLevel * 0.78 + rayTarget * 0.22
|
||||
const hueTarget = 180 + highAvg * 120
|
||||
this.rayHue = this.rayHue * 0.8 + hueTarget * 0.2
|
||||
|
||||
const bandCount = this.tentacleLevels.length
|
||||
const binSize = Math.max(1, Math.floor(freq.length / bandCount))
|
||||
for (let i = 0; i < bandCount; i += 1) {
|
||||
const start = i * binSize
|
||||
const end = i === bandCount - 1 ? freq.length : start + binSize
|
||||
let bandSum = 0
|
||||
for (let j = start; j < end; j += 1) bandSum += freq[j]
|
||||
const avg = bandSum / Math.max(1, end - start) / 255
|
||||
const shaped = Math.pow(Math.min(1, avg * 1.4), 1.6)
|
||||
this.tentacleLevels[i] =
|
||||
this.tentacleLevels[i] * 0.6 + shaped * 0.4
|
||||
}
|
||||
this.rafId = requestAnimationFrame(tick)
|
||||
}
|
||||
|
||||
|
||||
@@ -378,12 +378,14 @@ audio.hidden-audio {
|
||||
height: 96px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle at 30% 30%, #fbd72b, #f58b2b 60%, #1d3b8b);
|
||||
transform: scale(calc(1 + var(--pulse, 0) * 0.9));
|
||||
transform: translate(-50%, -50%) scale(calc(1 + var(--pulse, 0) * 0.9));
|
||||
box-shadow:
|
||||
0 0 calc(22px + var(--pulse, 0) * 140px) rgba(251, 215, 43, 0.6),
|
||||
0 0 calc(60px + var(--pulse, 0) * 240px) rgba(61, 214, 255, 0.45);
|
||||
transition: transform 0.06s ease-out;
|
||||
position: relative;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@@ -417,42 +419,39 @@ audio.hidden-audio {
|
||||
animation: pulseGlow 1.6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.pulse-rays {
|
||||
.pulse-tentacles {
|
||||
position: absolute;
|
||||
inset: -120px;
|
||||
border-radius: 50%;
|
||||
background:
|
||||
radial-gradient(circle at 50% 50%, hsla(var(--ray-hue, 200), 95%, 72%, 0.35) 0%, transparent 40%),
|
||||
radial-gradient(circle at 50% 50%, hsla(var(--ray-hue, 200), 90%, 68%, 0.25) 0%, transparent 55%),
|
||||
radial-gradient(circle at 50% 50%, hsla(var(--ray-hue, 200), 85%, 65%, 0.2) 0%, transparent 68%),
|
||||
radial-gradient(circle at 50% 50%, hsla(var(--ray-hue, 200), 80%, 60%, 0.16) 0%, transparent 80%),
|
||||
radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.08) 0%, transparent 30%);
|
||||
opacity: calc(0.18 + var(--ray, 0) * 0.65);
|
||||
filter: blur(calc(10px - var(--ray, 0) * 4px));
|
||||
transform: scale(calc(0.85 + var(--ray, 0) * 0.9));
|
||||
transition: opacity 0.12s ease-out, transform 0.12s ease-out, filter 0.12s ease-out;
|
||||
mix-blend-mode: screen;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.pulse-rays::before,
|
||||
.pulse-rays::after {
|
||||
content: '';
|
||||
.pulse-tentacles .tentacle {
|
||||
position: absolute;
|
||||
inset: 8%;
|
||||
border-radius: 50%;
|
||||
border: 2px solid hsla(var(--ray-hue, 200), 90%, 70%, 0.25);
|
||||
opacity: calc(0.1 + var(--ray, 0) * 0.6);
|
||||
transform: scale(calc(0.7 + var(--ray, 0) * 0.9));
|
||||
filter: blur(calc(2px + var(--ray, 0) * 2px));
|
||||
}
|
||||
|
||||
.pulse-rays::after {
|
||||
inset: 20%;
|
||||
border-width: 3px;
|
||||
opacity: calc(0.08 + var(--ray, 0) * 0.55);
|
||||
transform: scale(calc(0.8 + var(--ray, 0) * 1.1));
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 12px;
|
||||
height: calc(20px + var(--level, 0) * 50px);
|
||||
background: linear-gradient(
|
||||
to top,
|
||||
rgba(0, 0, 0, 0) 0%,
|
||||
hsla(var(--ray-hue, 200), 90%, 70%, 0.6) 45%,
|
||||
hsla(var(--ray-hue, 200), 95%, 75%, 0.95) 100%
|
||||
);
|
||||
border-radius: 999px;
|
||||
filter: blur(calc(1.5px - var(--level, 0) * 0.5));
|
||||
opacity: calc(0.25 + var(--level, 0) * 0.85);
|
||||
transform-origin: 50% 100%;
|
||||
transform:
|
||||
translate(-50%, calc(-20px - var(--level, 0) * 50px))
|
||||
rotate(calc(var(--index) * 30deg))
|
||||
scaleX(calc(0.7 + var(--level, 0) * 0.5));
|
||||
transition: height 0.08s ease-out, opacity 0.08s ease-out, transform 0.08s ease-out, filter 0.08s ease-out;
|
||||
mix-blend-mode: screen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user