116 lines
3.3 KiB
QML
116 lines
3.3 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import "../services" as S
|
|
import NovaStats as NS
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property bool running: false
|
|
property bool reducedMotion: S.ThemeUtil.reducedMotion
|
|
readonly property real wavePhase: fx.uWavePhase
|
|
|
|
ShaderEffect {
|
|
id: fx
|
|
anchors.fill: parent
|
|
fragmentShader: Quickshell.shellPath("modules/hex_wave.frag.qsb")
|
|
|
|
property real uSize: 50.0
|
|
// Gaussian tail margin: exp(-m²/40000) < 0.01 at m=500
|
|
readonly property real _waveMargin: 500
|
|
property real uWavePhase: -_waveMargin
|
|
property real uBreath: 0
|
|
property real uGlitch: 0
|
|
property real uGlitchSeed: 0.0
|
|
property vector4d uResolution: Qt.vector4d(width, height, 0, 0)
|
|
property color uC0: NS.ThemeService.base0C
|
|
property color uC1: NS.ThemeService.base0E
|
|
property color uC2: NS.ThemeService.base09
|
|
|
|
Connections {
|
|
target: root
|
|
function onRunningChanged() {
|
|
if (!root.running) {
|
|
fx.uWavePhase = -fx._waveMargin;
|
|
fx.uBreath = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Wave animation: 6s sweep + 8s pause
|
|
SequentialAnimation on uWavePhase {
|
|
loops: Animation.Infinite
|
|
running: root.running && !root.reducedMotion
|
|
NumberAnimation {
|
|
from: -fx._waveMargin
|
|
to: fx.width + fx._waveMargin
|
|
duration: 3000
|
|
easing.type: Easing.InOutSine
|
|
}
|
|
PauseAnimation {
|
|
duration: 8000
|
|
}
|
|
}
|
|
|
|
// Breathing pulse
|
|
SequentialAnimation on uBreath {
|
|
loops: Animation.Infinite
|
|
running: root.running && !root.reducedMotion
|
|
NumberAnimation {
|
|
from: 0
|
|
to: 1
|
|
duration: 2500
|
|
easing.type: Easing.InOutSine
|
|
}
|
|
NumberAnimation {
|
|
from: 1
|
|
to: 0
|
|
duration: 2500
|
|
easing.type: Easing.InOutSine
|
|
}
|
|
}
|
|
|
|
// Random subtle glitches - fire every 12-37s
|
|
Timer {
|
|
interval: 20000
|
|
repeat: true
|
|
running: !root.reducedMotion
|
|
onTriggered: {
|
|
interval = 12000 + Math.floor(Math.random() * 25000);
|
|
fx.uGlitchSeed = Math.random() * 1000.0;
|
|
_glitchAnim.start();
|
|
}
|
|
}
|
|
|
|
SequentialAnimation {
|
|
id: _glitchAnim
|
|
NumberAnimation {
|
|
target: fx
|
|
property: "uGlitch"
|
|
to: 0.7
|
|
duration: 50
|
|
easing.type: Easing.OutQuad
|
|
}
|
|
NumberAnimation {
|
|
target: fx
|
|
property: "uGlitch"
|
|
to: 0.15
|
|
duration: 50
|
|
}
|
|
NumberAnimation {
|
|
target: fx
|
|
property: "uGlitch"
|
|
to: 0.85
|
|
duration: 60
|
|
easing.type: Easing.OutQuad
|
|
}
|
|
NumberAnimation {
|
|
target: fx
|
|
property: "uGlitch"
|
|
to: 0
|
|
duration: 100
|
|
easing.type: Easing.InQuad
|
|
}
|
|
}
|
|
}
|
|
}
|