From 1810e2a4fe385eb142f0697b864fc2bdd5f12d46 Mon Sep 17 00:00:00 2001 From: zhengziyu54188 Date: Mon, 13 Jul 2026 14:25:15 +0800 Subject: [PATCH 01/11] test1 --- src/Web/index.html | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Web/index.html b/src/Web/index.html index 80951b4..e2d4943 100644 --- a/src/Web/index.html +++ b/src/Web/index.html @@ -336,20 +336,50 @@ ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; + // 逐段渲染(直线版 -- 保留备用) + // const lastIdx = pts.length - 1; + // for (let i = 0; i < lastIdx; i++) { + // const alphaStart = i / lastIdx; + // const alphaEnd = (i + 1) / lastIdx; + // const a0 = pts[i]; + // const a1 = pts[i + 1]; + // + // const segGrad = ctx.createLinearGradient(a0.x, a0.y, a1.x, a1.y); + // segGrad.addColorStop(0, `rgba(${this.color}, ${alphaStart})`); + // segGrad.addColorStop(1, `rgba(${this.color}, ${alphaEnd})`); + // + // ctx.beginPath(); + // ctx.moveTo(a0.x, a0.y); + // ctx.lineTo(a1.x, a1.y); + // ctx.strokeStyle = segGrad; + // ctx.stroke(); + // } + + // 逐段渲染(Catmull-Rom → Cubic Bezier 曲线版) + // 每段的透明度基于数组索引位置,而非空间位置 const lastIdx = pts.length - 1; for (let i = 0; i < lastIdx; i++) { - const alphaStart = i / lastIdx; - const alphaEnd = (i + 1) / lastIdx; const a0 = pts[i]; const a1 = pts[i + 1]; + // Catmull-Rom 控制点:CP1 = P_i + (P_{i+1} - P_{i-1}) / 6 + // CP2 = P_{i+1} - (P_{i+2} - P_i) / 6 + const prev = i > 0 ? pts[i - 1] : a0; + const next = i < lastIdx - 1 ? pts[i + 2] : a1; + const cp1x = a0.x + (a1.x - prev.x) / 6; + const cp1y = a0.y + (a1.y - prev.y) / 6; + const cp2x = a1.x - (next.x - a0.x) / 6; + const cp2y = a1.y - (next.y - a0.y) / 6; + + const alphaStart = i / lastIdx; + const alphaEnd = (i + 1) / lastIdx; const segGrad = ctx.createLinearGradient(a0.x, a0.y, a1.x, a1.y); segGrad.addColorStop(0, `rgba(${this.color}, ${alphaStart})`); segGrad.addColorStop(1, `rgba(${this.color}, ${alphaEnd})`); ctx.beginPath(); ctx.moveTo(a0.x, a0.y); - ctx.lineTo(a1.x, a1.y); + ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, a1.x, a1.y); ctx.strokeStyle = segGrad; ctx.stroke(); } From d197be530b8374e8c6e63ce9846d8141e642a15d Mon Sep 17 00:00:00 2001 From: zhengziyu54188 Date: Mon, 13 Jul 2026 15:12:08 +0800 Subject: [PATCH 02/11] test2 --- src/ConfigManager.cs | 3 ++ src/ControlPanelWindow.xaml | 4 ++ src/ControlPanelWindow.xaml.cs | 9 ++++ src/MainWindow.xaml.cs | 5 ++ src/OverlayManager.cs | 1 + src/Resources/Strings.en.resx | 6 +++ src/Resources/Strings.ja.resx | 6 +++ src/Resources/Strings.resx | 6 +++ src/Web/index.html | 90 +++++++++++++++++----------------- 9 files changed, 85 insertions(+), 45 deletions(-) diff --git a/src/ConfigManager.cs b/src/ConfigManager.cs index 7e5a9eb..c8ff05b 100644 --- a/src/ConfigManager.cs +++ b/src/ConfigManager.cs @@ -72,6 +72,7 @@ public static class ConfigManager public static double EffectOpacity { get; set; } = 1.0; public static double EffectSpeed { get; set; } = 1.0; public static bool UseLinkedAnimationSpeed { get; set; } = true; + public static bool ApplyCurveDraw { get; set; } = false; public static double TrailAnimationSpeed { get; set; } = 1.0; public static double ClickAnimationSpeed { get; set; } = 1.0; public static int TrailRefreshRate { get; set; } = 40; @@ -130,6 +131,7 @@ public static void Load() EffectOpacity = Math.Clamp(Convert.ToDouble(key.GetValue("EffectOpacity", 1.0)), 0.1, 1.0); EffectSpeed = Math.Clamp(Convert.ToDouble(key.GetValue("EffectSpeed", 1.0)), 0.2, 3.0); UseLinkedAnimationSpeed = Convert.ToBoolean(key.GetValue("UseLinkedAnimationSpeed", true)); + ApplyCurveDraw = Convert.ToBoolean(key.GetValue("ApplyCurveDraw", false)); TrailAnimationSpeed = Math.Clamp(Convert.ToDouble(key.GetValue("TrailAnimationSpeed", EffectSpeed)), 0.2, 3.0); ClickAnimationSpeed = Math.Clamp(Convert.ToDouble(key.GetValue("ClickAnimationSpeed", EffectSpeed)), 0.2, 3.0); TrailRefreshRate = Math.Clamp(Convert.ToInt32(key.GetValue("TrailRefreshRate", 40)), 10, 240); @@ -532,6 +534,7 @@ public static void ResetAndClear() EffectOpacity = 1.0; EffectSpeed = 1.0; UseLinkedAnimationSpeed = true; + ApplyCurveDraw = false; TrailAnimationSpeed = 1.0; ClickAnimationSpeed = 1.0; TrailRefreshRate = 40; diff --git a/src/ControlPanelWindow.xaml b/src/ControlPanelWindow.xaml index 03f3cda..571210e 100644 --- a/src/ControlPanelWindow.xaml +++ b/src/ControlPanelWindow.xaml @@ -524,6 +524,10 @@ Checked="LinkedAnimationSpeed_Changed" Unchecked="LinkedAnimationSpeed_Changed"/> + + + diff --git a/src/ControlPanelWindow.xaml.cs b/src/ControlPanelWindow.xaml.cs index 2e9e43a..f292419 100644 --- a/src/ControlPanelWindow.xaml.cs +++ b/src/ControlPanelWindow.xaml.cs @@ -584,6 +584,7 @@ private void LoadSettingsCore() SliderScale.Value = ConfigManager.EffectScale; SliderOpacity.Value = ConfigManager.EffectOpacity * 100; CheckLinkedAnimationSpeed.IsChecked = ConfigManager.UseLinkedAnimationSpeed; + CheckApplyCurveDraw.IsChecked = ConfigManager.ApplyCurveDraw; SliderSpeed.Value = ConfigManager.EffectSpeed; SliderTrailAnimSpeed.Value = ConfigManager.TrailAnimationSpeed; SliderClickAnimSpeed.Value = ConfigManager.ClickAnimationSpeed; @@ -1317,6 +1318,7 @@ private void ConfirmVisualReset_Click(object sender, RoutedEventArgs e) App.Overlay?.UpdateColor(ConfigManager.ParticleColor); App.Overlay?.UpdateEffectSettings(effectScale, effectOpacity, trailSp, clickSp); App.Overlay?.UpdateTrailRefreshRate(trailRefreshRate); + App.Overlay?.SetCurveDraw(CheckApplyCurveDraw.IsChecked ?? false); VisualResetOverlay.Visibility = Visibility.Collapsed; System.Windows.MessageBox.Show( @@ -1423,6 +1425,7 @@ private void SaveSettings_Click(object sender, RoutedEventArgs e) ConfigManager.Save("ClickTriggerType", clickType); ConfigManager.Save("EnableMiddleClickTrigger", middleClickEnabled); ConfigManager.Save("ScreenshotCompatibilityMode", screenshotCompatibilityEnabled); + ConfigManager.Save("ApplyCurveDraw", CheckApplyCurveDraw.IsChecked ?? false); string sidebarBackgroundPath = TxtSidebarBackgroundPath?.Text?.Trim() ?? string.Empty; if (!string.IsNullOrWhiteSpace(sidebarBackgroundPath)) @@ -1484,6 +1487,7 @@ private void SaveSettings_Click(object sender, RoutedEventArgs e) App.Overlay?.RefreshEnvironmentFilterState(); App.Overlay?.UpdateTouchMode(isTouchscreenEnabled); App.Overlay?.UpdateScreenshotCompatibilityMode(screenshotCompatibilityEnabled); + App.Overlay?.SetCurveDraw(CheckApplyCurveDraw.IsChecked ?? false); if (!previousEnabledScreenIds.SetEquals(selectedIds)) { App.Overlay?.RefreshScreenSelection(); @@ -1694,6 +1698,11 @@ private void EffectSlider_ValueChanged(object sender, RoutedPropertyChangedEvent if (!IsLoaded) return; } + private void CurveDraw_Changed(object sender, RoutedEventArgs e) + { + if (!IsLoaded) return; + } + private void LinkedAnimationSpeed_Changed(object sender, RoutedEventArgs e) { if (!IsLoaded || _suspendLinkedAnimationUiHandlers) diff --git a/src/MainWindow.xaml.cs b/src/MainWindow.xaml.cs index 14ca5cb..1ef778e 100644 --- a/src/MainWindow.xaml.cs +++ b/src/MainWindow.xaml.cs @@ -213,6 +213,11 @@ public void UpdateTrailRefreshRate(int hz) _ = hz; } + public void SetCurveDraw(bool enabled) + { + ExecuteScript($"window.ApplyCurveDraw = {(enabled ? "true" : "false")};"); + } + public void UpdateTouchMode(bool enabled) { ConfigManager.IsTouchscreenMode = enabled; diff --git a/src/OverlayManager.cs b/src/OverlayManager.cs index 6f59a6a..d6f20a3 100644 --- a/src/OverlayManager.cs +++ b/src/OverlayManager.cs @@ -146,6 +146,7 @@ public void UpdateScreenshotCompatibilityMode(bool enabled) ForEachOverlay(w => w.UpdateScreenshotCompatibilityMode(enabled)); SyncScreenshotCompatCaptureSurfaces(); } + public void SetCurveDraw(bool enabled) => ForEachOverlay(w => w.SetCurveDraw(enabled)); public bool IsEffectSuppressedByEnvironment() => _isSuppressedByEnvironment; public void RefreshEnvironmentFilterState() { diff --git a/src/Resources/Strings.en.resx b/src/Resources/Strings.en.resx index 0b7d3c8..a8fc855 100644 --- a/src/Resources/Strings.en.resx +++ b/src/Resources/Strings.en.resx @@ -586,6 +586,12 @@ Download now? When off, trail and click speeds are independent of trail refresh rate below. + + Use curved trail lines + + + Render trails as curves for smoother visuals at lower refresh rates. + Global opacity diff --git a/src/Resources/Strings.ja.resx b/src/Resources/Strings.ja.resx index 20b087c..f0720ce 100644 --- a/src/Resources/Strings.ja.resx +++ b/src/Resources/Strings.ja.resx @@ -586,6 +586,12 @@ オフにするとトレイルとクリックの速度を個別に設定できます(下の更新率とは別)。 + + 曲線トレイルを使用 + + + トレイルを曲線で描画し、低リフレッシュレートでの視覚体験を向上させます。 + 全体の不透明度 diff --git a/src/Resources/Strings.resx b/src/Resources/Strings.resx index fcafb17..7d8f9eb 100644 --- a/src/Resources/Strings.resx +++ b/src/Resources/Strings.resx @@ -586,6 +586,12 @@ 关闭此项后可单独加快或减慢拖尾衰减与移动粒子,而不影响点击波纹与爆发粒子,与下方「拖尾刷新率」不同。 + + 采用曲线拖尾 + + + 点击后拖尾渲染变为曲线,适合在低刷新率下使用以获得更好视觉体验。 + 全局不透明度 diff --git a/src/Web/index.html b/src/Web/index.html index e2d4943..74b1878 100644 --- a/src/Web/index.html +++ b/src/Web/index.html @@ -336,54 +336,54 @@ ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; - // 逐段渲染(直线版 -- 保留备用) - // const lastIdx = pts.length - 1; - // for (let i = 0; i < lastIdx; i++) { - // const alphaStart = i / lastIdx; - // const alphaEnd = (i + 1) / lastIdx; - // const a0 = pts[i]; - // const a1 = pts[i + 1]; - // - // const segGrad = ctx.createLinearGradient(a0.x, a0.y, a1.x, a1.y); - // segGrad.addColorStop(0, `rgba(${this.color}, ${alphaStart})`); - // segGrad.addColorStop(1, `rgba(${this.color}, ${alphaEnd})`); - // - // ctx.beginPath(); - // ctx.moveTo(a0.x, a0.y); - // ctx.lineTo(a1.x, a1.y); - // ctx.strokeStyle = segGrad; - // ctx.stroke(); - // } - - // 逐段渲染(Catmull-Rom → Cubic Bezier 曲线版) - // 每段的透明度基于数组索引位置,而非空间位置 const lastIdx = pts.length - 1; - for (let i = 0; i < lastIdx; i++) { - const a0 = pts[i]; - const a1 = pts[i + 1]; - - // Catmull-Rom 控制点:CP1 = P_i + (P_{i+1} - P_{i-1}) / 6 - // CP2 = P_{i+1} - (P_{i+2} - P_i) / 6 - const prev = i > 0 ? pts[i - 1] : a0; - const next = i < lastIdx - 1 ? pts[i + 2] : a1; - const cp1x = a0.x + (a1.x - prev.x) / 6; - const cp1y = a0.y + (a1.y - prev.y) / 6; - const cp2x = a1.x - (next.x - a0.x) / 6; - const cp2y = a1.y - (next.y - a0.y) / 6; - - const alphaStart = i / lastIdx; - const alphaEnd = (i + 1) / lastIdx; - const segGrad = ctx.createLinearGradient(a0.x, a0.y, a1.x, a1.y); - segGrad.addColorStop(0, `rgba(${this.color}, ${alphaStart})`); - segGrad.addColorStop(1, `rgba(${this.color}, ${alphaEnd})`); + // 每段的透明度基于数组索引位置,而非空间位置 + if (window.ApplyCurveDraw) { + // 逐段渲染(Catmull-Rom → Cubic Bezier 曲线版) + for (let i = 0; i < lastIdx; i++) { + const a0 = pts[i]; + const a1 = pts[i + 1]; + + // Catmull-Rom 控制点:CP1 = P_i + (P_{i+1} - P_{i-1}) / 6 + // CP2 = P_{i+1} - (P_{i+2} - P_i) / 6 + const prev = i > 0 ? pts[i - 1] : a0; + const next = i < lastIdx - 1 ? pts[i + 2] : a1; + const cp1x = a0.x + (a1.x - prev.x) / 6; + const cp1y = a0.y + (a1.y - prev.y) / 6; + const cp2x = a1.x - (next.x - a0.x) / 6; + const cp2y = a1.y - (next.y - a0.y) / 6; + + const alphaStart = i / lastIdx; + const alphaEnd = (i + 1) / lastIdx; + const segGrad = ctx.createLinearGradient(a0.x, a0.y, a1.x, a1.y); + segGrad.addColorStop(0, `rgba(${this.color}, ${alphaStart})`); + segGrad.addColorStop(1, `rgba(${this.color}, ${alphaEnd})`); - ctx.beginPath(); - ctx.moveTo(a0.x, a0.y); - ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, a1.x, a1.y); - ctx.strokeStyle = segGrad; - ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(a0.x, a0.y); + ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, a1.x, a1.y); + ctx.strokeStyle = segGrad; + ctx.stroke(); + } + } else { + // 逐段渲染(直线版) + for (let i = 0; i < lastIdx; i++) { + const alphaStart = i / lastIdx; + const alphaEnd = (i + 1) / lastIdx; + const a0 = pts[i]; + const a1 = pts[i + 1]; + + const segGrad = ctx.createLinearGradient(a0.x, a0.y, a1.x, a1.y); + segGrad.addColorStop(0, `rgba(${this.color}, ${alphaStart})`); + segGrad.addColorStop(1, `rgba(${this.color}, ${alphaEnd})`); + + ctx.beginPath(); + ctx.moveTo(a0.x, a0.y); + ctx.lineTo(a1.x, a1.y); + ctx.strokeStyle = segGrad; + ctx.stroke(); + } } - ctx.shadowColor = 'transparent'; } From 0efac2160d35ea887cdc28b2ce7cdc9e9b4e0778 Mon Sep 17 00:00:00 2001 From: zhengziyu54188 Date: Mon, 13 Jul 2026 15:36:01 +0800 Subject: [PATCH 03/11] final --- src/ControlPanelWindow.xaml | 2 +- src/Resources/Strings.en.resx | 2 +- src/Resources/Strings.ja.resx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ControlPanelWindow.xaml b/src/ControlPanelWindow.xaml index 571210e..c3916f7 100644 --- a/src/ControlPanelWindow.xaml +++ b/src/ControlPanelWindow.xaml @@ -526,7 +526,7 @@ - + diff --git a/src/Resources/Strings.en.resx b/src/Resources/Strings.en.resx index a8fc855..00c69d8 100644 --- a/src/Resources/Strings.en.resx +++ b/src/Resources/Strings.en.resx @@ -590,7 +590,7 @@ Download now? Use curved trail lines - Render trails as curves for smoother visuals at lower refresh rates. + Render trails as curves for smoother visuals at lower refresh rates. Recommended for 60Hz and above. Global opacity diff --git a/src/Resources/Strings.ja.resx b/src/Resources/Strings.ja.resx index f0720ce..4879bf2 100644 --- a/src/Resources/Strings.ja.resx +++ b/src/Resources/Strings.ja.resx @@ -590,7 +590,7 @@ 曲線トレイルを使用 - トレイルを曲線で描画し、低リフレッシュレートでの視覚体験を向上させます。 + トレイルを曲線で描画し、低リフレッシュレートでの視覚体験を向上させます。60Hz以上のリフレッシュレートでの使用を推奨します。 全体の不透明度 From e1dc06d14b9497ba4a28fecf5fc39d795e1ab604 Mon Sep 17 00:00:00 2001 From: zhengziyu54188 Date: Mon, 13 Jul 2026 16:49:37 +0800 Subject: [PATCH 04/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BASpark.csproj | 1 + src/ControlPanelWindow.xaml | 2 +- src/Resources/Strings.en.resx | 2 +- src/Resources/Strings.ja.resx | 2 +- src/Resources/Strings.resx | 2 +- tests/BASpark.Tests/BASpark.Tests.csproj | 1 + 6 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/BASpark.csproj b/src/BASpark.csproj index 2e05bcd..0975012 100644 --- a/src/BASpark.csproj +++ b/src/BASpark.csproj @@ -22,6 +22,7 @@ app.manifest Static + true diff --git a/src/ControlPanelWindow.xaml b/src/ControlPanelWindow.xaml index c3916f7..c899ff5 100644 --- a/src/ControlPanelWindow.xaml +++ b/src/ControlPanelWindow.xaml @@ -526,7 +526,7 @@ - + diff --git a/src/Resources/Strings.en.resx b/src/Resources/Strings.en.resx index 00c69d8..48179a7 100644 --- a/src/Resources/Strings.en.resx +++ b/src/Resources/Strings.en.resx @@ -590,7 +590,7 @@ Download now? Use curved trail lines - Render trails as curves for smoother visuals at lower refresh rates. Recommended for 60Hz and above. + Render trails as curves for smoother visuals at lower refresh rates. Recommended for 60Hz and above. If GPU usage is too high, try lowering the refresh rate and enabling this feature — the visual impact is minimal. Global opacity diff --git a/src/Resources/Strings.ja.resx b/src/Resources/Strings.ja.resx index 4879bf2..76ca4d0 100644 --- a/src/Resources/Strings.ja.resx +++ b/src/Resources/Strings.ja.resx @@ -590,7 +590,7 @@ 曲線トレイルを使用 - トレイルを曲線で描画し、低リフレッシュレートでの視覚体験を向上させます。60Hz以上のリフレッシュレートでの使用を推奨します。 + トレイルを曲線で描画し、低リフレッシュレートでの視覚体験を向上させます。60Hz以上のリフレッシュレートでの使用を推奨します。 GPU使用率が高い場合は、リフレッシュレートを下げてこの機能を有効にしてみてください。見た目への影響は最小限です。 全体の不透明度 diff --git a/src/Resources/Strings.resx b/src/Resources/Strings.resx index 7d8f9eb..21d97bd 100644 --- a/src/Resources/Strings.resx +++ b/src/Resources/Strings.resx @@ -590,7 +590,7 @@ 采用曲线拖尾 - 点击后拖尾渲染变为曲线,适合在低刷新率下使用以获得更好视觉体验。 + 点击后拖尾渲染变为曲线,适合在低刷新率下使用以获得更好视觉体验。建议在60Hz及以上刷新率时开启。 如果发现该应用显卡占用过高,可以降低刷新率同时开启该功能,对视觉效果影响不大。 全局不透明度 diff --git a/tests/BASpark.Tests/BASpark.Tests.csproj b/tests/BASpark.Tests/BASpark.Tests.csproj index 3adf019..73414c3 100644 --- a/tests/BASpark.Tests/BASpark.Tests.csproj +++ b/tests/BASpark.Tests/BASpark.Tests.csproj @@ -5,6 +5,7 @@ enable enable false + true From fbd0fd39f76d9f61ea4873117860c69513184b95 Mon Sep 17 00:00:00 2001 From: zhengziyu54188 Date: Mon, 13 Jul 2026 16:57:22 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=BA=86=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E7=9A=84=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BASpark.csproj | 1 - tests/BASpark.Tests/BASpark.Tests.csproj | 1 - 2 files changed, 2 deletions(-) diff --git a/src/BASpark.csproj b/src/BASpark.csproj index 0975012..2e05bcd 100644 --- a/src/BASpark.csproj +++ b/src/BASpark.csproj @@ -22,7 +22,6 @@ app.manifest Static - true diff --git a/tests/BASpark.Tests/BASpark.Tests.csproj b/tests/BASpark.Tests/BASpark.Tests.csproj index 73414c3..3adf019 100644 --- a/tests/BASpark.Tests/BASpark.Tests.csproj +++ b/tests/BASpark.Tests/BASpark.Tests.csproj @@ -5,7 +5,6 @@ enable enable false - true From 438a189aeaedf044a3d5e5a3b89de187212566ef Mon Sep 17 00:00:00 2001 From: zhengziyu54188 Date: Tue, 14 Jul 2026 14:06:49 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E8=BE=89=E5=85=89=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Web/index.html | 101 ++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 46 deletions(-) diff --git a/src/Web/index.html b/src/Web/index.html index 74b1878..433bd58 100644 --- a/src/Web/index.html +++ b/src/Web/index.html @@ -328,63 +328,72 @@ return; } - // 逐段渲染:每段的透明度基于数组索引位置,而非空间位置 + // 多 Pass 叠线替代 shadowBlur,降低 GPU 占用 + // 从外到内逐层绘制,每层线宽递减、透明度递增,模拟辉光效果 + + // 每段的透明度基于数组索引位置,而非空间位置 // 防止当鼠标锐角转动时,尾迹变淡后突然出现的问题 - ctx.lineWidth = 5.0; - ctx.shadowColor = `rgba(${this.color}, 0.6)`; - ctx.shadowBlur = 3; - ctx.shadowOffsetX = 0; - ctx.shadowOffsetY = 0; + const glowPasses = [ + { lineWidth: 18.0, alphaMul: 0.035 }, // 最外层辉光 + { lineWidth: 12.5, alphaMul: 0.10 }, // 中层辉光 + { lineWidth: 8.0, alphaMul: 0.28 }, // 内层辉光 + { lineWidth: 5.0, alphaMul: 1.0 }, // 核心线 + ]; const lastIdx = pts.length - 1; // 每段的透明度基于数组索引位置,而非空间位置 if (window.ApplyCurveDraw) { // 逐段渲染(Catmull-Rom → Cubic Bezier 曲线版) - for (let i = 0; i < lastIdx; i++) { - const a0 = pts[i]; - const a1 = pts[i + 1]; - - // Catmull-Rom 控制点:CP1 = P_i + (P_{i+1} - P_{i-1}) / 6 - // CP2 = P_{i+1} - (P_{i+2} - P_i) / 6 - const prev = i > 0 ? pts[i - 1] : a0; - const next = i < lastIdx - 1 ? pts[i + 2] : a1; - const cp1x = a0.x + (a1.x - prev.x) / 6; - const cp1y = a0.y + (a1.y - prev.y) / 6; - const cp2x = a1.x - (next.x - a0.x) / 6; - const cp2y = a1.y - (next.y - a0.y) / 6; - - const alphaStart = i / lastIdx; - const alphaEnd = (i + 1) / lastIdx; - const segGrad = ctx.createLinearGradient(a0.x, a0.y, a1.x, a1.y); - segGrad.addColorStop(0, `rgba(${this.color}, ${alphaStart})`); - segGrad.addColorStop(1, `rgba(${this.color}, ${alphaEnd})`); - - ctx.beginPath(); - ctx.moveTo(a0.x, a0.y); - ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, a1.x, a1.y); - ctx.strokeStyle = segGrad; - ctx.stroke(); + for (const pass of glowPasses) { + ctx.lineWidth = pass.lineWidth; + for (let i = 0; i < lastIdx; i++) { + const a0 = pts[i]; + const a1 = pts[i + 1]; + + // Catmull-Rom 控制点:CP1 = P_i + (P_{i+1} - P_{i-1}) / 6 + // CP2 = P_{i+1} - (P_{i+2} - P_i) / 6 + const prev = i > 0 ? pts[i - 1] : a0; + const next = i < lastIdx - 1 ? pts[i + 2] : a1; + const cp1x = a0.x + (a1.x - prev.x) / 6; + const cp1y = a0.y + (a1.y - prev.y) / 6; + const cp2x = a1.x - (next.x - a0.x) / 6; + const cp2y = a1.y - (next.y - a0.y) / 6; + + const alphaStart = (i / lastIdx) * pass.alphaMul; + const alphaEnd = ((i + 1) / lastIdx) * pass.alphaMul; + const segGrad = ctx.createLinearGradient(a0.x, a0.y, a1.x, a1.y); + segGrad.addColorStop(0, `rgba(${this.color}, ${alphaStart})`); + segGrad.addColorStop(1, `rgba(${this.color}, ${alphaEnd})`); + + ctx.beginPath(); + ctx.moveTo(a0.x, a0.y); + ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, a1.x, a1.y); + ctx.strokeStyle = segGrad; + ctx.stroke(); + } } } else { // 逐段渲染(直线版) - for (let i = 0; i < lastIdx; i++) { - const alphaStart = i / lastIdx; - const alphaEnd = (i + 1) / lastIdx; - const a0 = pts[i]; - const a1 = pts[i + 1]; - - const segGrad = ctx.createLinearGradient(a0.x, a0.y, a1.x, a1.y); - segGrad.addColorStop(0, `rgba(${this.color}, ${alphaStart})`); - segGrad.addColorStop(1, `rgba(${this.color}, ${alphaEnd})`); - - ctx.beginPath(); - ctx.moveTo(a0.x, a0.y); - ctx.lineTo(a1.x, a1.y); - ctx.strokeStyle = segGrad; - ctx.stroke(); + for (const pass of glowPasses) { + ctx.lineWidth = pass.lineWidth; + for (let i = 0; i < lastIdx; i++) { + const alphaStart = (i / lastIdx) * pass.alphaMul; + const alphaEnd = ((i + 1) / lastIdx) * pass.alphaMul; + const a0 = pts[i]; + const a1 = pts[i + 1]; + + const segGrad = ctx.createLinearGradient(a0.x, a0.y, a1.x, a1.y); + segGrad.addColorStop(0, `rgba(${this.color}, ${alphaStart})`); + segGrad.addColorStop(1, `rgba(${this.color}, ${alphaEnd})`); + + ctx.beginPath(); + ctx.moveTo(a0.x, a0.y); + ctx.lineTo(a1.x, a1.y); + ctx.strokeStyle = segGrad; + ctx.stroke(); + } } } - ctx.shadowColor = 'transparent'; } _strokeRingSegment(wx, wy, radius, a0, a1, lineWidth, strokeStyle) { From 88c7b7f75df6a3ded743e0dc32bd39230f881423 Mon Sep 17 00:00:00 2001 From: zhengziyu54188 Date: Tue, 14 Jul 2026 14:41:48 +0800 Subject: [PATCH 07/11] try1 --- src/Web/index.html | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Web/index.html b/src/Web/index.html index 433bd58..8586ec6 100644 --- a/src/Web/index.html +++ b/src/Web/index.html @@ -333,10 +333,9 @@ // 每段的透明度基于数组索引位置,而非空间位置 // 防止当鼠标锐角转动时,尾迹变淡后突然出现的问题 - const glowPasses = [ - { lineWidth: 18.0, alphaMul: 0.035 }, // 最外层辉光 - { lineWidth: 12.5, alphaMul: 0.10 }, // 中层辉光 - { lineWidth: 8.0, alphaMul: 0.28 }, // 内层辉光 + const glowPasses = [ // 最外层辉光 + { lineWidth: 12.5, alphaMul: 0.1 }, // 中层辉光 + { lineWidth: 8.0, alphaMul: 0.3 }, // 内层辉光 { lineWidth: 5.0, alphaMul: 1.0 }, // 核心线 ]; From ed9deeea938df6219b62651029e11abb4291ab92 Mon Sep 17 00:00:00 2001 From: zhengziyu54188 Date: Tue, 14 Jul 2026 15:14:27 +0800 Subject: [PATCH 08/11] try2 --- src/Web/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Web/index.html b/src/Web/index.html index 8586ec6..b5a7cd5 100644 --- a/src/Web/index.html +++ b/src/Web/index.html @@ -334,9 +334,9 @@ // 每段的透明度基于数组索引位置,而非空间位置 // 防止当鼠标锐角转动时,尾迹变淡后突然出现的问题 const glowPasses = [ // 最外层辉光 - { lineWidth: 12.5, alphaMul: 0.1 }, // 中层辉光 - { lineWidth: 8.0, alphaMul: 0.3 }, // 内层辉光 - { lineWidth: 5.0, alphaMul: 1.0 }, // 核心线 + { lineWidth: 11, alphaMul: 0.08 }, // 中层辉光 + { lineWidth: 7.0, alphaMul: 0.18 }, // 内层辉光 + { lineWidth: 5.0, alphaMul: 2.0 }, // 核心线 ]; const lastIdx = pts.length - 1; From 026ea200b626850161d16df8a2e1c77f84b8cfd3 Mon Sep 17 00:00:00 2001 From: zhengziyu54188 Date: Tue, 14 Jul 2026 15:45:34 +0800 Subject: [PATCH 09/11] final --- src/Web/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Web/index.html b/src/Web/index.html index b5a7cd5..cc366e0 100644 --- a/src/Web/index.html +++ b/src/Web/index.html @@ -334,9 +334,9 @@ // 每段的透明度基于数组索引位置,而非空间位置 // 防止当鼠标锐角转动时,尾迹变淡后突然出现的问题 const glowPasses = [ // 最外层辉光 - { lineWidth: 11, alphaMul: 0.08 }, // 中层辉光 - { lineWidth: 7.0, alphaMul: 0.18 }, // 内层辉光 - { lineWidth: 5.0, alphaMul: 2.0 }, // 核心线 + { lineWidth: 11, alphaMul: 0.05 }, // 外层辉光 + { lineWidth: 7.0, alphaMul: 0.5 }, // 内层辉光 + { lineWidth: 5.0, alphaMul: 1.0 }, // 核心线 ]; const lastIdx = pts.length - 1; From b16ea86384d5f04bc3e67aac59cb3250c6da2c73 Mon Sep 17 00:00:00 2001 From: zhengziyu54188 Date: Tue, 14 Jul 2026 15:50:25 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E4=BA=86=E7=B2=97?= =?UTF-8?q?=E7=BB=86=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Web/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Web/index.html b/src/Web/index.html index cc366e0..415fcd4 100644 --- a/src/Web/index.html +++ b/src/Web/index.html @@ -334,9 +334,9 @@ // 每段的透明度基于数组索引位置,而非空间位置 // 防止当鼠标锐角转动时,尾迹变淡后突然出现的问题 const glowPasses = [ // 最外层辉光 - { lineWidth: 11, alphaMul: 0.05 }, // 外层辉光 - { lineWidth: 7.0, alphaMul: 0.5 }, // 内层辉光 - { lineWidth: 5.0, alphaMul: 1.0 }, // 核心线 + { lineWidth: 9, alphaMul: 0.05 }, // 外层辉光 + { lineWidth: 6.0, alphaMul: 0.5 }, // 内层辉光 + { lineWidth: 4.5, alphaMul: 1.0 }, // 核心线 ]; const lastIdx = pts.length - 1; From efe0e32f78e93ff59a35b1d0d5bf33409e81b2dc Mon Sep 17 00:00:00 2001 From: zhengziyu54188 Date: Fri, 17 Jul 2026 10:54:02 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E6=94=B9=E5=8A=A8=E5=90=8C#125?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ControlPanelWindow.xaml | 2 +- src/Resources/Strings.en.resx | 2 +- src/Resources/Strings.ja.resx | 2 +- src/Resources/Strings.resx | 2 +- src/UiLocalizer.cs | 2 ++ 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ControlPanelWindow.xaml b/src/ControlPanelWindow.xaml index c899ff5..f24ae04 100644 --- a/src/ControlPanelWindow.xaml +++ b/src/ControlPanelWindow.xaml @@ -526,7 +526,7 @@ - + diff --git a/src/Resources/Strings.en.resx b/src/Resources/Strings.en.resx index 48179a7..b9c56b0 100644 --- a/src/Resources/Strings.en.resx +++ b/src/Resources/Strings.en.resx @@ -590,7 +590,7 @@ Download now? Use curved trail lines - Render trails as curves for smoother visuals at lower refresh rates. Recommended for 60Hz and above. If GPU usage is too high, try lowering the refresh rate and enabling this feature — the visual impact is minimal. + Recommended for 60Hz and above Global opacity diff --git a/src/Resources/Strings.ja.resx b/src/Resources/Strings.ja.resx index 76ca4d0..99781ac 100644 --- a/src/Resources/Strings.ja.resx +++ b/src/Resources/Strings.ja.resx @@ -590,7 +590,7 @@ 曲線トレイルを使用 - トレイルを曲線で描画し、低リフレッシュレートでの視覚体験を向上させます。60Hz以上のリフレッシュレートでの使用を推奨します。 GPU使用率が高い場合は、リフレッシュレートを下げてこの機能を有効にしてみてください。見た目への影響は最小限です。 + 60Hz以上のリフレッシュレートでの使用を推奨します 全体の不透明度 diff --git a/src/Resources/Strings.resx b/src/Resources/Strings.resx index 21d97bd..1d36971 100644 --- a/src/Resources/Strings.resx +++ b/src/Resources/Strings.resx @@ -590,7 +590,7 @@ 采用曲线拖尾 - 点击后拖尾渲染变为曲线,适合在低刷新率下使用以获得更好视觉体验。建议在60Hz及以上刷新率时开启。 如果发现该应用显卡占用过高,可以降低刷新率同时开启该功能,对视觉效果影响不大。 + 建议在60Hz及以上刷新率开启 全局不透明度 diff --git a/src/UiLocalizer.cs b/src/UiLocalizer.cs index 3b56a73..5d481c7 100644 --- a/src/UiLocalizer.cs +++ b/src/UiLocalizer.cs @@ -93,6 +93,8 @@ public static void ApplyControlPanel(ControlPanelWindow w) w.TxtVisualOpacity.Text = Localization.Get("Visual_Opacity"); w.CheckLinkedAnimationSpeed.Content = Localization.Get("Visual_LinkedSpeed"); w.TxtLinkedSpeedHint.Text = Localization.Get("Visual_LinkedSpeedHint"); + w.CheckApplyCurveDraw.Content = Localization.Get("Visual_CurveDraw"); + w.TxtCurveDrawHint.Text = Localization.Get("Visual_CurveDrawHint"); w.TxtAnimSpeed.Text = Localization.Get("Visual_AnimSpeed"); w.TxtTrailAnimSpeed.Text = Localization.Get("Visual_TrailAnimSpeed"); w.TxtClickAnimSpeed.Text = Localization.Get("Visual_ClickAnimSpeed");