diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/EyeViewportOverlay.cs b/Assets/Scripts/MiniGame/Peipei/Eye/EyeViewportOverlay.cs
index 4b90a49d7..2256549b0 100644
--- a/Assets/Scripts/MiniGame/Peipei/Eye/EyeViewportOverlay.cs
+++ b/Assets/Scripts/MiniGame/Peipei/Eye/EyeViewportOverlay.cs
@@ -1,403 +1,421 @@
-using System.Collections;
-using DG.Tweening;
-using UnityEngine;
-using UnityEngine.UI;
-
-namespace AibisDream
-{
- ///
- /// Mobile-friendly fullscreen eye viewport: elliptical sight + vertical ellipse blink.
- ///
- [DisallowMultipleComponent]
- [ExecuteAlways]
- public class EyeViewportOverlay : MonoBehaviour
- {
- private const string OverlaySortingLayer = "StartUI";
- private const float OverlayPlaneDistance = 10f;
-
- private static readonly int EyeWidthId = Shader.PropertyToID("_EyeWidth");
- private static readonly int EyeHeightId = Shader.PropertyToID("_EyeHeight");
- private static readonly int EdgeSoftnessId = Shader.PropertyToID("_EdgeSoftness");
- private static readonly int BlinkOpenId = Shader.PropertyToID("_BlinkOpen");
-
- /// 须低于 Persistence 中 UI Canvas(1) 与 Dialog Canvas(3)。
- [SerializeField] private int sortingOrder;
-
- private Canvas overlayCanvas;
- private Image overlayImage;
- private Material instanceMaterial;
- private EyeVisualSettings activeSettings;
- private Coroutine autoBlinkRoutine;
- private Tween blinkTween;
- private float blinkOpen = 1f;
- private bool moduleActive;
- private bool editorPreviewActive;
- private bool hierarchyReady;
- private bool lifecycleReady;
- private Coroutine deferPrepareRoutine;
-
- private void Start()
- {
- lifecycleReady = true;
- if (!Application.isPlaying)
- {
- return;
- }
-
- PrepareHierarchyIfNeeded();
- SetOverlayActive(false);
- }
-
- private void OnDestroy()
- {
- StopEffects();
- if (instanceMaterial != null)
- {
- Destroy(instanceMaterial);
- }
- }
-
- public void EnterModule(EyeVisualSettings settings)
- {
- moduleActive = true;
- editorPreviewActive = false;
- ShowOverlay(settings);
- }
-
- public void ExitModule()
- {
- moduleActive = false;
- if (editorPreviewActive)
- {
- return;
- }
-
- StopEffects();
- SetOverlayActive(false);
- activeSettings = null;
- }
-
- public void EnterEditorPreview(EyeVisualSettings settings)
- {
- editorPreviewActive = true;
- ShowOverlay(settings);
- }
-
- public void ExitEditorPreview()
- {
- editorPreviewActive = false;
- if (moduleActive)
- {
- ShowOverlay(activeSettings);
- return;
- }
-
- StopEffects();
- SetOverlayActive(false);
- activeSettings = null;
- }
-
- public void ApplySettings(EyeVisualSettings settings)
- {
- if (settings == null)
- {
- return;
- }
-
- if (!settings.enableViewportOverlay)
- {
- if (editorPreviewActive)
- {
- ExitEditorPreview();
- }
- else if (moduleActive)
- {
- ExitModule();
- }
-
- return;
- }
-
- PrepareHierarchyIfNeeded();
- if (instanceMaterial == null)
- {
- return;
- }
-
- activeSettings = settings;
- PushViewportParams(settings);
- SetBlinkOpen(blinkOpen);
-
- if (!overlayCanvas.gameObject.activeInHierarchy)
- {
- return;
- }
-
- if (settings.autoBlink && Application.isPlaying && (moduleActive || editorPreviewActive))
- {
- StartAutoBlink(settings);
- }
- else
- {
- StopAutoBlink();
- }
- }
-
- public Tween PlayBlink(float? totalDuration = null)
- {
- if (instanceMaterial == null || activeSettings == null)
- {
- return null;
- }
-
- blinkTween?.Kill();
-
- float closeDuration = activeSettings.blinkCloseDuration;
- float openDuration = activeSettings.blinkOpenDuration;
- if (totalDuration.HasValue)
- {
- float total = Mathf.Max(0.05f, totalDuration.Value);
- closeDuration = total * 0.42f;
- openDuration = total * 0.58f;
- }
-
- blinkTween = DOTween.Sequence()
- .Append(CreateBlinkTween(blinkOpen, 0f, closeDuration, Ease.InQuad))
- .Append(CreateBlinkTween(0f, 1f, openDuration, Ease.OutQuad))
- .OnComplete(() => SetBlinkOpen(1f));
-
- return blinkTween;
- }
-
- private void ShowOverlay(EyeVisualSettings settings)
- {
- if (settings == null || !settings.enableViewportOverlay)
- {
- ExitModule();
- return;
- }
-
- PrepareHierarchyIfNeeded();
- activeSettings = settings;
- ApplySettings(settings);
- if (!editorPreviewActive)
- {
- SetBlinkOpen(1f);
- }
-
- SetOverlayActive(true);
-
- if (settings.autoBlink && Application.isPlaying)
- {
- StartAutoBlink(settings);
- }
- }
-
- private void PushViewportParams(EyeVisualSettings settings)
- {
- instanceMaterial.SetFloat(EyeWidthId, settings.eyeWidth);
- instanceMaterial.SetFloat(EyeHeightId, settings.eyeHeight);
- instanceMaterial.SetFloat(EdgeSoftnessId, settings.edgeSoftness);
- }
-
- private Tween CreateBlinkTween(float from, float to, float duration, Ease ease)
- {
- blinkOpen = from;
- SetBlinkOpen(from);
- return DOTween.To(() => blinkOpen, value =>
- {
- blinkOpen = value;
- SetBlinkOpen(value);
- }, to, duration).SetEase(ease);
- }
-
- private void StartAutoBlink(EyeVisualSettings settings)
- {
- StopAutoBlink();
- if (!settings.autoBlink)
- {
- return;
- }
-
- autoBlinkRoutine = StartCoroutine(AutoBlinkRoutine(settings));
- }
-
- private IEnumerator AutoBlinkRoutine(EyeVisualSettings settings)
- {
- while (enabled && overlayCanvas != null && overlayCanvas.gameObject.activeInHierarchy)
- {
- float min = Mathf.Max(1f, settings.autoBlinkInterval.x);
- float max = Mathf.Max(min, settings.autoBlinkInterval.y);
- yield return new WaitForSeconds(Random.Range(min, max));
-
- Tween blink = PlayBlink();
- if (blink != null)
- {
- yield return blink.WaitForCompletion();
- }
- }
- }
-
- private void StopEffects()
- {
- blinkTween?.Kill();
- blinkTween = null;
- StopAutoBlink();
- }
-
- private void StopAutoBlink()
- {
- if (autoBlinkRoutine == null)
- {
- return;
- }
-
- StopCoroutine(autoBlinkRoutine);
- autoBlinkRoutine = null;
- }
-
- public void SetBlinkOpenPreview(float value)
- {
- SetBlinkOpen(value);
- }
-
- public float GetBlinkOpenPreview() => blinkOpen;
-
- private void SetBlinkOpen(float value)
- {
- blinkOpen = Mathf.Clamp01(value);
- instanceMaterial?.SetFloat(BlinkOpenId, blinkOpen);
- }
-
- private void SetOverlayActive(bool active)
- {
- if (overlayCanvas != null)
- {
- overlayCanvas.gameObject.SetActive(active);
- }
- }
-
- private void PrepareHierarchyIfNeeded()
- {
- if (hierarchyReady && overlayCanvas != null)
- {
- return;
- }
-
- if (Application.isPlaying && !lifecycleReady)
- {
- ScheduleDeferredPrepare();
- return;
- }
-
- EnsureOverlayHierarchy();
- hierarchyReady = overlayCanvas != null;
- }
-
- private void ScheduleDeferredPrepare()
- {
- if (deferPrepareRoutine != null || !isActiveAndEnabled)
- {
- return;
- }
-
- deferPrepareRoutine = StartCoroutine(DeferredPrepareHierarchy());
- }
-
- private IEnumerator DeferredPrepareHierarchy()
- {
- yield return null;
- deferPrepareRoutine = null;
- EnsureOverlayHierarchy();
- hierarchyReady = overlayCanvas != null;
-
- if (activeSettings != null && instanceMaterial != null)
- {
- PushViewportParams(activeSettings);
- SetBlinkOpen(blinkOpen);
- }
- }
-
- private void EnsureOverlayHierarchy()
- {
- if (overlayCanvas == null)
- {
- var canvasGo = new GameObject("EyeViewportOverlayCanvas");
- canvasGo.transform.SetParent(transform, false);
-
- overlayCanvas = canvasGo.AddComponent