desktop-team-doc 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/README.md +89 -0
  2. package/content/docs/README.md +227 -0
  3. package/content/docs/index.md +352 -0
  4. package/content/docs/instructions/coding-conventions/.clang-format +65 -0
  5. package/content/docs/instructions/coding-conventions/cpp.md +132 -0
  6. package/content/docs/instructions/coding-conventions/frontend.md +612 -0
  7. package/content/docs/instructions/coding-conventions/team-wide.md +176 -0
  8. package/content/docs/instructions/workflows/assets/jira-1.png +0 -0
  9. package/content/docs/instructions/workflows/assets/jira-comment.png +0 -0
  10. package/content/docs/instructions/workflows/assets/jira-release-note.png +0 -0
  11. package/content/docs/instructions/workflows/assets/jira-tag.png +0 -0
  12. package/content/docs/instructions/workflows/code-review.md +451 -0
  13. package/content/docs/instructions/workflows/git-branch-convention.md +246 -0
  14. package/content/docs/instructions/workflows/git-commit.md +95 -0
  15. package/content/docs/instructions/workflows/jira-process.md +173 -0
  16. package/content/docs/instructions/workflows/jira-ticket-guide.md +105 -0
  17. package/content/docs/instructions/workflows/pull-request-generation.md +319 -0
  18. package/content/docs/instructions/workflows/scrum-process.md +104 -0
  19. package/content/docs/instructions/workflows/survey-project-setup.md +76 -0
  20. package/content/docs/knowledge/architecture/README.md +11 -0
  21. package/content/docs/knowledge/architecture/audio-plugin-architecture.md +213 -0
  22. package/content/docs/knowledge/architecture/cross-platform-design.md +176 -0
  23. package/content/docs/knowledge/architecture/frontend-native-bridge.md +193 -0
  24. package/content/docs/knowledge/architecture/native-command.md +189 -0
  25. package/content/docs/knowledge/architecture/state-management-architecture.md +105 -0
  26. package/content/docs/knowledge/component-library/ControlComponent/README.md +281 -0
  27. package/content/docs/knowledge/component-library/ControlComponent/accessibility/accessibility-implementation.md +503 -0
  28. package/content/docs/knowledge/component-library/ControlComponent/common-mechanisms.md +278 -0
  29. package/content/docs/knowledge/component-library/ControlComponent/core/error-handling.md +451 -0
  30. package/content/docs/knowledge/component-library/ControlComponent/core/native-interface.md +515 -0
  31. package/content/docs/knowledge/component-library/ControlComponent/core/state-management.md +509 -0
  32. package/content/docs/knowledge/component-library/ControlComponent/creating-new-controls.md +654 -0
  33. package/content/docs/knowledge/component-library/ControlComponent/design/api-design-reference.md +1142 -0
  34. package/content/docs/knowledge/component-library/ControlComponent/design/design-principles.md +336 -0
  35. package/content/docs/knowledge/component-library/ControlComponent/design/styling-architecture.md +595 -0
  36. package/content/docs/knowledge/component-library/ControlComponent/design/visual-feedback.md +456 -0
  37. package/content/docs/knowledge/component-library/ControlComponent/development-environment.md +213 -0
  38. package/content/docs/knowledge/component-library/ControlComponent/interaction/gesture-algorithms.md +705 -0
  39. package/content/docs/knowledge/component-library/ControlComponent/interaction/touch-support.md +525 -0
  40. package/content/docs/knowledge/component-library/ControlComponent/interaction/value-processing-patterns.md +801 -0
  41. package/content/docs/knowledge/component-library/ControlComponent/interaction/velocity-damping-systems.md +741 -0
  42. package/content/docs/knowledge/component-library/ControlComponent/knob/architecture.md +490 -0
  43. package/content/docs/knowledge/component-library/ControlComponent/knob/how-to-use.md +304 -0
  44. package/content/docs/knowledge/component-library/ControlComponent/knob/index.md +105 -0
  45. package/content/docs/knowledge/component-library/ControlComponent/optimization/performance-benchmarks.md +535 -0
  46. package/content/docs/knowledge/component-library/ControlComponent/optimization/performance-optimization.md +1092 -0
  47. package/content/docs/knowledge/component-library/ControlComponent/quick-start.md +345 -0
  48. package/content/docs/knowledge/component-library/ControlComponent/slider/architecture.md +444 -0
  49. package/content/docs/knowledge/component-library/ControlComponent/slider/how-to-use.md +470 -0
  50. package/content/docs/knowledge/component-library/ControlComponent/slider/index.md +107 -0
  51. package/content/docs/knowledge/component-library/ControlComponent/testing-guide.md +950 -0
  52. package/content/docs/knowledge/component-library/ControlComponent/troubleshooting.md +657 -0
  53. package/content/docs/knowledge/component-library/frontend-develop/LICENSE.txt +176 -0
  54. package/content/docs/knowledge/component-library/frontend-develop/SKILL.md +124 -0
  55. package/content/docs/knowledge/component-library/frontend-develop/references/code-organization.md +620 -0
  56. package/content/docs/knowledge/component-library/frontend-develop/references/coding-standards.md +275 -0
  57. package/content/docs/knowledge/component-library/frontend-develop/references/component-reusability.md +559 -0
  58. package/content/docs/knowledge/component-library/frontend-develop/references/examples.md +554 -0
  59. package/content/docs/knowledge/component-library/frontend-develop/references/layout-separation.md +638 -0
  60. package/content/docs/knowledge/component-library/frontend-develop/references/performance-optimization.md +678 -0
  61. package/content/docs/knowledge/component-library/frontend-develop/references/state-management.md +331 -0
  62. package/content/docs/knowledge/component-library/frontend-develop/references/styling-guidelines.md +349 -0
  63. package/content/docs/knowledge/component-library/frontend-develop/references/type-safety.md +493 -0
  64. package/content/docs/knowledge/development/assets/cyberduck-aws-credentials.png +0 -0
  65. package/content/docs/knowledge/development/assets/postman-environment-setup.png +0 -0
  66. package/content/docs/knowledge/development/aws-storage.md +95 -0
  67. package/content/docs/knowledge/development/crm-system.md +22 -0
  68. package/content/docs/knowledge/development/glossary.md +246 -0
  69. package/content/docs/knowledge/development/pg-api-guide.md +71 -0
  70. package/content/docs/knowledge/development/staging-license-management.md +44 -0
  71. package/content/docs/knowledge/development/tech-stack.md +240 -0
  72. package/content/docs/knowledge/domain/popup-system.md +106 -0
  73. package/content/docs/knowledge/domain/sigpath.md +264 -0
  74. package/content/docs/knowledge/environment-setup/aax-signing-update.md +149 -0
  75. package/content/docs/knowledge/environment-setup/assets/aax-1.png +0 -0
  76. package/content/docs/knowledge/environment-setup/assets/aax-2.png +0 -0
  77. package/content/docs/knowledge/environment-setup/assets/aax-3.png +0 -0
  78. package/content/docs/knowledge/environment-setup/assets/aax-4.png +0 -0
  79. package/content/docs/knowledge/environment-setup/assets/aax-5.png +0 -0
  80. package/content/docs/knowledge/environment-setup/assets/aax-6.png +0 -0
  81. package/content/docs/knowledge/environment-setup/assets/aax-7.png +0 -0
  82. package/content/docs/knowledge/environment-setup/assets/buildmachine-1.png +0 -0
  83. package/content/docs/knowledge/environment-setup/assets/buildmachine-10.png +0 -0
  84. package/content/docs/knowledge/environment-setup/assets/buildmachine-11.png +0 -0
  85. package/content/docs/knowledge/environment-setup/assets/buildmachine-12.png +0 -0
  86. package/content/docs/knowledge/environment-setup/assets/buildmachine-13.png +0 -0
  87. package/content/docs/knowledge/environment-setup/assets/buildmachine-14.png +0 -0
  88. package/content/docs/knowledge/environment-setup/assets/buildmachine-2.png +0 -0
  89. package/content/docs/knowledge/environment-setup/assets/buildmachine-3.png +0 -0
  90. package/content/docs/knowledge/environment-setup/assets/buildmachine-4.png +0 -0
  91. package/content/docs/knowledge/environment-setup/assets/buildmachine-5.png +0 -0
  92. package/content/docs/knowledge/environment-setup/assets/buildmachine-6.png +0 -0
  93. package/content/docs/knowledge/environment-setup/assets/buildmachine-7.png +0 -0
  94. package/content/docs/knowledge/environment-setup/assets/buildmachine-8.png +0 -0
  95. package/content/docs/knowledge/environment-setup/assets/buildmachine-9.png +0 -0
  96. package/content/docs/knowledge/environment-setup/build-machine-setup.md +224 -0
  97. package/content/docs/knowledge/environment-setup/build-machine-troubleshooting.md +193 -0
  98. package/content/docs/knowledge/implementation-guides/adding-amp.md +190 -0
  99. package/content/docs/knowledge/implementation-guides/adding-fx.md +111 -0
  100. package/content/docs/knowledge/implementation-guides/cab-integration.md +194 -0
  101. package/content/docs/knowledge/implementation-guides/custom-pedal-integration.md +309 -0
  102. package/content/docs/knowledge/projects/BIAS_ONE_GUI/README.md +17 -0
  103. package/content/manifest.json +122 -0
  104. package/content/rules/cpp.mdc +135 -0
  105. package/content/rules/frontend.mdc +615 -0
  106. package/content/rules/index.mdc +256 -0
  107. package/content/rules/knowledge.mdc +46 -0
  108. package/content/rules/team-wide.mdc +179 -0
  109. package/content/rules/workflows.mdc +43 -0
  110. package/content/tools/agents/context-compressor.md +357 -0
  111. package/content/tools/agents/context-writer.md +328 -0
  112. package/content/tools/agents/release-notes-generator.md +389 -0
  113. package/content/tools/agents/srs-writer-agent.md +63 -0
  114. package/content/tools/mcp/README.md +25 -0
  115. package/content/tools/mcp/mcp-desktop-team.example.json +13 -0
  116. package/content/tools/skills/frontend-develop/LICENSE.txt +176 -0
  117. package/content/tools/skills/frontend-develop/SKILL.md +124 -0
  118. package/content/tools/skills/frontend-develop/references/code-organization.md +620 -0
  119. package/content/tools/skills/frontend-develop/references/coding-standards.md +275 -0
  120. package/content/tools/skills/frontend-develop/references/component-reusability.md +559 -0
  121. package/content/tools/skills/frontend-develop/references/examples.md +554 -0
  122. package/content/tools/skills/frontend-develop/references/layout-separation.md +638 -0
  123. package/content/tools/skills/frontend-develop/references/performance-optimization.md +678 -0
  124. package/content/tools/skills/frontend-develop/references/state-management.md +331 -0
  125. package/content/tools/skills/frontend-develop/references/styling-guidelines.md +349 -0
  126. package/content/tools/skills/frontend-develop/references/type-safety.md +493 -0
  127. package/content/tools/slash-commands/commit.md +17 -0
  128. package/content/tools/slash-commands/context-compress.md +149 -0
  129. package/content/tools/slash-commands/context-write.md +92 -0
  130. package/content/tools/slash-commands/jira.md +12 -0
  131. package/content/tools/slash-commands/pr-gen.md +12 -0
  132. package/content/tools/slash-commands/pr-review.md +12 -0
  133. package/dist/commands/detect.d.ts +1 -0
  134. package/dist/commands/detect.js +33 -0
  135. package/dist/commands/install.d.ts +1 -0
  136. package/dist/commands/install.js +100 -0
  137. package/dist/commands/uninstall.d.ts +1 -0
  138. package/dist/commands/uninstall.js +132 -0
  139. package/dist/index.d.ts +2 -0
  140. package/dist/index.js +53 -0
  141. package/dist/lib/detect-env.d.ts +3 -0
  142. package/dist/lib/detect-env.js +52 -0
  143. package/dist/lib/prompt-env.d.ts +3 -0
  144. package/dist/lib/prompt-env.js +16 -0
  145. package/dist/lib/resolve-doc-repo.d.ts +14 -0
  146. package/dist/lib/resolve-doc-repo.js +61 -0
  147. package/dist/lib/symlink.d.ts +7 -0
  148. package/dist/lib/symlink.js +60 -0
  149. package/dist/lib/sync-from-manifest.d.ts +8 -0
  150. package/dist/lib/sync-from-manifest.js +64 -0
  151. package/package.json +46 -0
@@ -0,0 +1,741 @@
1
+ # 速度感應與阻尼系統
2
+
3
+ 本文檔詳細說明音訊控制項中的速度感應 (Velocity Sensitivity) 和阻尼效果 (Damping) 系統,這兩種機制是專業音訊軟體的核心特性。
4
+
5
+ ---
6
+
7
+ ## 1. Damping vs Velocity 的本質區別
8
+
9
+ ### 概念區分
10
+
11
+ 這兩種功能滿足使用者在不同情境下的需求:
12
+
13
+ | 特性 | 阻尼效果 (Damping) | 速度感應 (Velocity) |
14
+ |------|-------------------|-------------------|
15
+ | **觸發方式** | 修飾鍵 (Shift/Ctrl) | 滑鼠移動速度 |
16
+ | **效果** | 固定降低靈敏度 | 動態調整靈敏度 |
17
+ | **使用情境** | 刻意的精細微調 | 快速粗調 + 慢速精調 |
18
+ | **範例** | 調整 EQ 增益、濾波器共振 | 掃過合成器頻率範圍 |
19
+
20
+ ### JUCE 論壇的關鍵洞察
21
+
22
+ > "在速度感應模式下,拖動滑桿的精確度取決於你滑鼠移動的速度...但在精細模式下,滑桿只是單純地變得更慢。"
23
+ > — JUCE 開發者論壇
24
+
25
+ ### 正交設計原則
26
+
27
+ 這兩種功能是**正交的**,可以獨立使用或同時作用:
28
+
29
+ ```typescript
30
+ // 最終變化量公式
31
+ finalChange = baseChange * dampingMultiplier * velocityMultiplier
32
+
33
+ // 當使用者按住 Shift 並快速移動時:
34
+ // - damping 先降低基礎變化量
35
+ // - velocity 再根據速度放大結果
36
+ // 結果:快速移動時有適度放大,但基底已被阻尼降低
37
+ ```
38
+
39
+ ---
40
+
41
+ ## 2. 阻尼效果 (Damping) 系統
42
+
43
+ ### 修飾鍵配置策略
44
+
45
+ 不同平台有不同的慣例,應該允許配置:
46
+
47
+ ```typescript
48
+ /**
49
+ * 阻尼配置
50
+ */
51
+ interface DampingConfig {
52
+ enabled?: boolean;
53
+ key?: 'shift' | 'ctrl' | 'alt' | 'meta';
54
+ factor?: number; // 0.1 = 1/10 靈敏度
55
+ dynamic?: {
56
+ adaptToRange?: boolean; // 根據參數範圍自動調整
57
+ adaptToPrecision?: boolean; // 根據當前精確度調整
58
+ };
59
+ }
60
+
61
+ /**
62
+ * 預設配置 (可覆蓋)
63
+ */
64
+ const DEFAULT_DAMPING: DampingConfig = {
65
+ enabled: true,
66
+ key: 'shift', // 業界最常見
67
+ factor: 0.1, // 1/10 靈敏度
68
+ };
69
+ ```
70
+
71
+ ### BIAS ONE 現有實作
72
+
73
+ ```typescript
74
+ // BIAS ONE 現有的精確模式檢測 (來自 common-mechanisms.md)
75
+ const usePreciseMode = () => {
76
+ const agent = useAgent();
77
+
78
+ const isPreciseMode = useCallback((e: MouseEvent | WheelEvent) => {
79
+ return (agent.isMac && e.metaKey) || (agent.isWin && e.ctrlKey);
80
+ }, [agent]);
81
+
82
+ return isPreciseMode;
83
+ };
84
+
85
+ // 在 Slider 中的應用
86
+ const PRECISE_DRAG_SENSITIVITY = 0.2; // = factor 0.2
87
+ const DRAG_SENSITIVITY = 1;
88
+
89
+ const sensitivity = isPreciseMode(event)
90
+ ? PRECISE_DRAG_SENSITIVITY
91
+ : DRAG_SENSITIVITY;
92
+ ```
93
+
94
+ ### 建議改進:可配置的阻尼系統
95
+
96
+ ```typescript
97
+ /**
98
+ * 阻尼處理器
99
+ */
100
+ class DampingProcessor {
101
+ private config: DampingConfig;
102
+
103
+ constructor(config: DampingConfig = DEFAULT_DAMPING) {
104
+ this.config = config;
105
+ }
106
+
107
+ /**
108
+ * 檢查是否啟用阻尼
109
+ */
110
+ isDamped(event: PointerEvent | MouseEvent | WheelEvent): boolean {
111
+ if (!this.config.enabled || !this.config.key) {
112
+ return false;
113
+ }
114
+
115
+ const keyMap: Record<string, keyof PointerEvent> = {
116
+ shift: 'shiftKey',
117
+ ctrl: 'ctrlKey',
118
+ alt: 'altKey',
119
+ meta: 'metaKey',
120
+ };
121
+
122
+ return Boolean(event[keyMap[this.config.key]]);
123
+ }
124
+
125
+ /**
126
+ * 獲取阻尼乘數
127
+ */
128
+ getMultiplier(event: PointerEvent | MouseEvent | WheelEvent): number {
129
+ return this.isDamped(event) ? (this.config.factor ?? 0.1) : 1.0;
130
+ }
131
+
132
+ /**
133
+ * 應用阻尼到數值變化
134
+ */
135
+ apply(delta: number, event: PointerEvent | MouseEvent | WheelEvent): number {
136
+ return delta * this.getMultiplier(event);
137
+ }
138
+ }
139
+ ```
140
+
141
+ ---
142
+
143
+ ## 3. 速度感應 (Velocity) 系統
144
+
145
+ ### VelocityTracker 完整實作
146
+
147
+ ```typescript
148
+ /**
149
+ * 速度追蹤器配置
150
+ */
151
+ interface VelocityTrackerConfig {
152
+ maxSamples?: number; // 最大樣本數,預設 10
153
+ timeWindow?: number; // 時間窗口 (ms),預設 100
154
+ smoothingFactor?: number; // 平滑因子,預設 0.3
155
+ }
156
+
157
+ /**
158
+ * 速度樣本
159
+ */
160
+ interface VelocitySample {
161
+ position: Point;
162
+ timestamp: number;
163
+ }
164
+
165
+ /**
166
+ * 高精度速度追蹤器
167
+ */
168
+ class VelocityTracker {
169
+ private samples: VelocitySample[] = [];
170
+ private config: Required<VelocityTrackerConfig>;
171
+
172
+ constructor(config: VelocityTrackerConfig = {}) {
173
+ this.config = {
174
+ maxSamples: 10,
175
+ timeWindow: 100,
176
+ smoothingFactor: 0.3,
177
+ ...config,
178
+ };
179
+ }
180
+
181
+ /**
182
+ * 添加位置樣本
183
+ */
184
+ addSample(position: Point, timestamp: number = performance.now()): void {
185
+ this.samples.push({ position, timestamp });
186
+
187
+ // 清理過期樣本
188
+ this.cleanupSamples(timestamp);
189
+
190
+ // 限制樣本數量
191
+ while (this.samples.length > this.config.maxSamples) {
192
+ this.samples.shift();
193
+ }
194
+ }
195
+
196
+ /**
197
+ * 重置追蹤器
198
+ */
199
+ reset(): void {
200
+ this.samples = [];
201
+ }
202
+
203
+ /**
204
+ * 計算瞬時速度 (最近兩點)
205
+ * 單位:像素/毫秒
206
+ */
207
+ getInstantVelocity(): number {
208
+ if (this.samples.length < 2) return 0;
209
+
210
+ const latest = this.samples[this.samples.length - 1];
211
+ const previous = this.samples[this.samples.length - 2];
212
+
213
+ return this.calculateVelocityBetween(previous, latest);
214
+ }
215
+
216
+ /**
217
+ * 計算平均速度 (時間窗口內)
218
+ */
219
+ getAverageVelocity(): number {
220
+ if (this.samples.length < 2) return 0;
221
+
222
+ let totalDistance = 0;
223
+
224
+ for (let i = 1; i < this.samples.length; i++) {
225
+ const prev = this.samples[i - 1];
226
+ const curr = this.samples[i];
227
+ totalDistance += this.calculateDistance(prev.position, curr.position);
228
+ }
229
+
230
+ const timeSpan =
231
+ this.samples[this.samples.length - 1].timestamp -
232
+ this.samples[0].timestamp;
233
+
234
+ return timeSpan > 0 ? totalDistance / timeSpan : 0;
235
+ }
236
+
237
+ /**
238
+ * 計算平滑速度 (指數移動平均)
239
+ * 最推薦使用,能有效過濾雜訊
240
+ */
241
+ getSmoothedVelocity(): number {
242
+ if (this.samples.length < 2) return 0;
243
+
244
+ let smoothedVelocity = 0;
245
+ const alpha = this.config.smoothingFactor;
246
+
247
+ for (let i = 1; i < this.samples.length; i++) {
248
+ const velocity = this.calculateVelocityBetween(
249
+ this.samples[i - 1],
250
+ this.samples[i]
251
+ );
252
+
253
+ // 指數移動平均: EMA = α * current + (1-α) * previous
254
+ smoothedVelocity = alpha * velocity + (1 - alpha) * smoothedVelocity;
255
+ }
256
+
257
+ return smoothedVelocity;
258
+ }
259
+
260
+ /**
261
+ * 計算加速度 (速度變化率)
262
+ */
263
+ getAcceleration(): number {
264
+ if (this.samples.length < 3) return 0;
265
+
266
+ const velocities: number[] = [];
267
+ for (let i = 1; i < this.samples.length; i++) {
268
+ velocities.push(
269
+ this.calculateVelocityBetween(this.samples[i - 1], this.samples[i])
270
+ );
271
+ }
272
+
273
+ if (velocities.length < 2) return 0;
274
+
275
+ const latestVelocity = velocities[velocities.length - 1];
276
+ const previousVelocity = velocities[velocities.length - 2];
277
+ const timeDelta =
278
+ this.samples[this.samples.length - 1].timestamp -
279
+ this.samples[this.samples.length - 2].timestamp;
280
+
281
+ return timeDelta > 0 ? (latestVelocity - previousVelocity) / timeDelta : 0;
282
+ }
283
+
284
+ /**
285
+ * 獲取方向性速度 (用於判斷移動方向)
286
+ */
287
+ getDirectionalVelocity(): Point {
288
+ if (this.samples.length < 2) return { x: 0, y: 0 };
289
+
290
+ const latest = this.samples[this.samples.length - 1];
291
+ const previous = this.samples[this.samples.length - 2];
292
+ const timeDelta = latest.timestamp - previous.timestamp;
293
+
294
+ if (timeDelta <= 0) return { x: 0, y: 0 };
295
+
296
+ return {
297
+ x: (latest.position.x - previous.position.x) / timeDelta,
298
+ y: (latest.position.y - previous.position.y) / timeDelta,
299
+ };
300
+ }
301
+
302
+ private calculateVelocityBetween(
303
+ sample1: VelocitySample,
304
+ sample2: VelocitySample
305
+ ): number {
306
+ const distance = this.calculateDistance(sample1.position, sample2.position);
307
+ const timeDelta = sample2.timestamp - sample1.timestamp;
308
+
309
+ return timeDelta > 0 ? distance / timeDelta : 0;
310
+ }
311
+
312
+ private calculateDistance(p1: Point, p2: Point): number {
313
+ const dx = p2.x - p1.x;
314
+ const dy = p2.y - p1.y;
315
+ return Math.sqrt(dx * dx + dy * dy);
316
+ }
317
+
318
+ private cleanupSamples(currentTime: number): void {
319
+ const cutoffTime = currentTime - this.config.timeWindow;
320
+ this.samples = this.samples.filter(
321
+ (sample) => sample.timestamp >= cutoffTime
322
+ );
323
+ }
324
+ }
325
+ ```
326
+
327
+ ---
328
+
329
+ ## 4. VelocityResponseCalculator 響應曲線
330
+
331
+ ### 多種響應曲線實作
332
+
333
+ ```typescript
334
+ /**
335
+ * 速度配置
336
+ */
337
+ interface VelocityConfig {
338
+ enabled?: boolean;
339
+ sensitivity?: number; // 速度影響強度
340
+ threshold?: number; // 啟動閾值
341
+ maxMultiplier?: number; // 最大乘數上限
342
+ curve?: 'linear' | 'exponential' | 'logarithmic' | 'sigmoid' | 'custom';
343
+ exponent?: number; // exponential 曲線的指數
344
+ steepness?: number; // sigmoid 曲線的陡度
345
+ controlPoints?: ControlPoint[]; // custom 曲線的控制點
346
+ }
347
+
348
+ /**
349
+ * 控制點 (用於自訂曲線)
350
+ */
351
+ interface ControlPoint {
352
+ x: number; // 0-1 範圍的速度比
353
+ y: number; // 對應的乘數
354
+ }
355
+
356
+ /**
357
+ * 速度響應曲線計算器
358
+ */
359
+ class VelocityResponseCalculator {
360
+ /**
361
+ * 計算速度乘數
362
+ * @param velocity 當前速度 (像素/毫秒)
363
+ * @param config 速度配置
364
+ * @returns 乘數 (1.0 = 無影響)
365
+ */
366
+ static calculateMultiplier(velocity: number, config: VelocityConfig): number {
367
+ if (!config.enabled) {
368
+ return 1.0;
369
+ }
370
+
371
+ const threshold = config.threshold ?? 0.5;
372
+
373
+ // 低於閾值時不啟用
374
+ if (velocity < threshold) {
375
+ return 1.0;
376
+ }
377
+
378
+ // 正規化速度
379
+ const normalizedVelocity = velocity - threshold;
380
+ const maxVelocity = 10.0; // 預設最大速度參考值
381
+ const velocityRatio = Math.min(1, normalizedVelocity / maxVelocity);
382
+
383
+ let multiplier: number;
384
+
385
+ switch (config.curve) {
386
+ case 'linear':
387
+ multiplier = this.calculateLinearResponse(velocityRatio, config);
388
+ break;
389
+
390
+ case 'exponential':
391
+ multiplier = this.calculateExponentialResponse(velocityRatio, config);
392
+ break;
393
+
394
+ case 'logarithmic':
395
+ multiplier = this.calculateLogarithmicResponse(velocityRatio, config);
396
+ break;
397
+
398
+ case 'sigmoid':
399
+ multiplier = this.calculateSigmoidResponse(velocityRatio, config);
400
+ break;
401
+
402
+ case 'custom':
403
+ multiplier = this.calculateCustomResponse(velocityRatio, config);
404
+ break;
405
+
406
+ default:
407
+ multiplier = 1.0;
408
+ }
409
+
410
+ // 限制在合理範圍內
411
+ const minMultiplier = 0.1;
412
+ const maxMultiplier = config.maxMultiplier ?? 10.0;
413
+
414
+ return Math.max(minMultiplier, Math.min(maxMultiplier, multiplier));
415
+ }
416
+
417
+ /**
418
+ * 線性響應曲線
419
+ * 速度與乘數成正比
420
+ */
421
+ private static calculateLinearResponse(
422
+ ratio: number,
423
+ config: VelocityConfig
424
+ ): number {
425
+ const sensitivity = config.sensitivity ?? 1;
426
+ return 1 + ratio * sensitivity;
427
+ }
428
+
429
+ /**
430
+ * 指數響應曲線
431
+ * 高速時乘數快速增加
432
+ */
433
+ private static calculateExponentialResponse(
434
+ ratio: number,
435
+ config: VelocityConfig
436
+ ): number {
437
+ const exponent = config.exponent ?? 2;
438
+ const sensitivity = config.sensitivity ?? 1;
439
+ return 1 + Math.pow(ratio, exponent) * sensitivity;
440
+ }
441
+
442
+ /**
443
+ * 對數響應曲線
444
+ * 低速時變化明顯,高速時趨緩
445
+ */
446
+ private static calculateLogarithmicResponse(
447
+ ratio: number,
448
+ config: VelocityConfig
449
+ ): number {
450
+ const sensitivity = config.sensitivity ?? 1;
451
+ // log(1 + x*(e-1)) 確保 x=0 時 y=0,x=1 時 y=1
452
+ return 1 + Math.log(1 + ratio * (Math.E - 1)) * sensitivity;
453
+ }
454
+
455
+ /**
456
+ * S 型曲線 (Sigmoid)
457
+ * 中速區間變化最明顯
458
+ */
459
+ private static calculateSigmoidResponse(
460
+ ratio: number,
461
+ config: VelocityConfig
462
+ ): number {
463
+ const steepness = config.steepness ?? 5;
464
+ const sensitivity = config.sensitivity ?? 1;
465
+
466
+ // Sigmoid: 1 / (1 + e^(-k*(x-0.5)))
467
+ const sigmoid = 1 / (1 + Math.exp(-steepness * (ratio - 0.5)));
468
+ return 1 + sigmoid * sensitivity;
469
+ }
470
+
471
+ /**
472
+ * 自訂曲線 (透過控制點插值)
473
+ */
474
+ private static calculateCustomResponse(
475
+ ratio: number,
476
+ config: VelocityConfig
477
+ ): number {
478
+ const controlPoints = config.controlPoints ?? [
479
+ { x: 0, y: 1 },
480
+ { x: 1, y: 1 + (config.sensitivity ?? 1) },
481
+ ];
482
+
483
+ return this.interpolateControlPoints(ratio, controlPoints);
484
+ }
485
+
486
+ /**
487
+ * 控制點線性插值
488
+ */
489
+ private static interpolateControlPoints(
490
+ x: number,
491
+ points: ControlPoint[]
492
+ ): number {
493
+ if (points.length === 0) return 1;
494
+ if (points.length === 1) return points[0].y;
495
+
496
+ // 排序控制點
497
+ const sortedPoints = [...points].sort((a, b) => a.x - b.x);
498
+
499
+ // 找到 x 所在的區間
500
+ for (let i = 0; i < sortedPoints.length - 1; i++) {
501
+ const p1 = sortedPoints[i];
502
+ const p2 = sortedPoints[i + 1];
503
+
504
+ if (x >= p1.x && x <= p2.x) {
505
+ // 線性插值
506
+ const t = (x - p1.x) / (p2.x - p1.x);
507
+ return p1.y + t * (p2.y - p1.y);
508
+ }
509
+ }
510
+
511
+ // 超出範圍,返回邊界值
512
+ if (x < sortedPoints[0].x) {
513
+ return sortedPoints[0].y;
514
+ }
515
+ return sortedPoints[sortedPoints.length - 1].y;
516
+ }
517
+ }
518
+ ```
519
+
520
+ ### 響應曲線視覺化參考
521
+
522
+ ```
523
+ 乘數
524
+ 10 | ______ exponential
525
+ | ____/
526
+ 5 | ____/
527
+ | ____/ ______ linear
528
+ | ____/ ____/
529
+ | ____/____/_______ logarithmic
530
+ 1 |__________/____/
531
+ |_______________________________________
532
+ 0 速度
533
+ threshold
534
+ ```
535
+
536
+ ---
537
+
538
+ ## 5. BIAS ONE 現有實作對照
539
+
540
+ ### 現有常數
541
+
542
+ ```typescript
543
+ // BIAS ONE Slider 常數
544
+ const DRAG_SENSITIVITY = 1;
545
+ const PRECISE_DRAG_SENSITIVITY = 0.2; // = damping factor 0.2
546
+
547
+ // BIAS ONE Knob 常數
548
+ const WHEEL_DEFAULT_SENSITIVITY = 5000;
549
+ const WHEEL_SENSITIVITY_DIVISOR = 15000;
550
+ ```
551
+
552
+ ### 現有精確模式實作
553
+
554
+ ```typescript
555
+ // BIAS ONE 精確模式 Hook
556
+ const usePreciseMode = () => {
557
+ const agent = useAgent();
558
+
559
+ return useCallback((e: MouseEvent | WheelEvent) => {
560
+ return (agent.isMac && e.metaKey) || (agent.isWin && e.ctrlKey);
561
+ }, [agent]);
562
+ };
563
+ ```
564
+
565
+ ### 建議整合方案
566
+
567
+ ```typescript
568
+ /**
569
+ * 整合的速度-阻尼處理器
570
+ * 統一處理 BIAS ONE 現有邏輯和新功能
571
+ */
572
+ class UnifiedSensitivityProcessor {
573
+ private dampingProcessor: DampingProcessor;
574
+ private velocityTracker: VelocityTracker;
575
+ private velocityConfig: VelocityConfig;
576
+
577
+ constructor(
578
+ dampingConfig: DampingConfig,
579
+ velocityConfig: VelocityConfig
580
+ ) {
581
+ this.dampingProcessor = new DampingProcessor(dampingConfig);
582
+ this.velocityTracker = new VelocityTracker();
583
+ this.velocityConfig = velocityConfig;
584
+ }
585
+
586
+ /**
587
+ * 處理指標移動
588
+ */
589
+ processPointerMove(
590
+ event: PointerEvent,
591
+ baseDelta: number
592
+ ): number {
593
+ // 更新速度追蹤
594
+ this.velocityTracker.addSample(
595
+ { x: event.clientX, y: event.clientY },
596
+ event.timeStamp
597
+ );
598
+
599
+ let result = baseDelta;
600
+
601
+ // 1. 應用阻尼 (修飾鍵)
602
+ result = this.dampingProcessor.apply(result, event);
603
+
604
+ // 2. 應用速度感應
605
+ if (this.velocityConfig.enabled) {
606
+ const velocity = this.velocityTracker.getSmoothedVelocity();
607
+ const velocityMultiplier = VelocityResponseCalculator.calculateMultiplier(
608
+ velocity,
609
+ this.velocityConfig
610
+ );
611
+ result *= velocityMultiplier;
612
+ }
613
+
614
+ return result;
615
+ }
616
+
617
+ /**
618
+ * 處理滾輪事件
619
+ */
620
+ processWheel(event: WheelEvent, baseDelta: number): number {
621
+ // 滾輪通常只應用阻尼,不應用速度感應
622
+ return this.dampingProcessor.apply(baseDelta, event);
623
+ }
624
+
625
+ /**
626
+ * 重置 (拖曳結束時)
627
+ */
628
+ reset(): void {
629
+ this.velocityTracker.reset();
630
+ }
631
+
632
+ /**
633
+ * 獲取當前狀態
634
+ */
635
+ getState(): {
636
+ isDamped: boolean;
637
+ velocity: number;
638
+ velocityMultiplier: number;
639
+ } {
640
+ const velocity = this.velocityTracker.getSmoothedVelocity();
641
+ const velocityMultiplier = this.velocityConfig.enabled
642
+ ? VelocityResponseCalculator.calculateMultiplier(
643
+ velocity,
644
+ this.velocityConfig
645
+ )
646
+ : 1.0;
647
+
648
+ return {
649
+ isDamped: false, // 需要事件才能判斷
650
+ velocity,
651
+ velocityMultiplier,
652
+ };
653
+ }
654
+ }
655
+ ```
656
+
657
+ ---
658
+
659
+ ## 6. 使用指南
660
+
661
+ ### 基礎使用
662
+
663
+ ```typescript
664
+ // 僅阻尼
665
+ const config = {
666
+ damping: { enabled: true, key: 'shift', factor: 0.1 },
667
+ };
668
+
669
+ // 僅速度感應
670
+ const config = {
671
+ velocity: { enabled: true, curve: 'logarithmic', sensitivity: 2 },
672
+ };
673
+
674
+ // 兩者組合
675
+ const config = {
676
+ damping: { enabled: true, key: 'shift', factor: 0.1 },
677
+ velocity: { enabled: true, curve: 'logarithmic', sensitivity: 2 },
678
+ };
679
+ ```
680
+
681
+ ### 不同參數類型的建議配置
682
+
683
+ | 參數類型 | 阻尼因子 | 速度曲線 | 說明 |
684
+ |---------|---------|---------|------|
685
+ | 頻率 (20-20kHz) | 0.05 | logarithmic | 大範圍,需要精細微調 |
686
+ | 增益 (dB) | 0.1 | linear | 適中範圍 |
687
+ | 百分比 (0-100%) | 0.2 | linear | 小範圍 |
688
+ | 時間 (ms) | 0.1 | exponential | 需要快速掃過大範圍 |
689
+ | Pan (-100 to 100) | 0.15 | linear | 需要精確定位中心 |
690
+
691
+ ### 完整使用範例
692
+
693
+ ```typescript
694
+ // 在 useAudioControl 中使用
695
+ function useAudioControl(options: UseAudioControlOptions) {
696
+ const processor = useRef(
697
+ new UnifiedSensitivityProcessor(
698
+ options.damping ?? { enabled: true, key: 'shift', factor: 0.1 },
699
+ options.velocity ?? { enabled: false }
700
+ )
701
+ );
702
+
703
+ const handlePointerMove = useCallback((e: React.PointerEvent) => {
704
+ const rawDelta = calculateRawDelta(e);
705
+ const processedDelta = processor.current.processPointerMove(
706
+ e.nativeEvent,
707
+ rawDelta
708
+ );
709
+
710
+ // 更新數值...
711
+ }, []);
712
+
713
+ // ...
714
+ }
715
+ ```
716
+
717
+ ---
718
+
719
+ ## 總結
720
+
721
+ ### 核心公式
722
+
723
+ ```typescript
724
+ // 完整的數值變化計算
725
+ finalChange = baseDelta * sensitivity * dampingMultiplier * velocityMultiplier
726
+
727
+ // 其中:
728
+ // - baseDelta: 從手勢轉換得到的原始變化量
729
+ // - sensitivity: 基礎靈敏度
730
+ // - dampingMultiplier: 阻尼乘數 (0.1-1.0)
731
+ // - velocityMultiplier: 速度乘數 (1.0-10.0)
732
+ ```
733
+
734
+ ### 選擇指南
735
+
736
+ | 場景 | 建議配置 |
737
+ |------|---------|
738
+ | 一般參數調整 | 僅阻尼 (Shift + 0.1) |
739
+ | 頻率/大範圍參數 | 阻尼 + 速度感應 (對數曲線) |
740
+ | 專業混音環境 | 完整功能 + 可配置修飾鍵 |
741
+ | 入門級應用 | 僅阻尼 (簡單易懂) |