@realnation/builder-shared-sdk 2.6.0 → 2.8.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.
@@ -1 +1 @@
1
- {"version":3,"file":"controls.d.ts","sourceRoot":"","sources":["../../src/gamepad/controls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,mFAAmF;AACnF,eAAO,MAAM,aAAa,uEAAwE,CAAC;AAEnG;;;;GAIG;AACH,eAAO,MAAM,eAAe,+OAoBlB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AACzD,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAC7D,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,aAAa,CAAC;AAEtD,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAA2C,CAAC;AAE5F,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;CACf;AAsCD,eAAO,MAAM,QAAQ,EAAE,SAAS,iBAAiB,EAOhD,CAAC;AAKF,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,iBAAiB,CAIlE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAEpE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAErD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,IAAI,WAAW,CAEpE"}
1
+ {"version":3,"file":"controls.d.ts","sourceRoot":"","sources":["../../src/gamepad/controls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,mFAAmF;AACnF,eAAO,MAAM,aAAa,uEAAwE,CAAC;AAEnG;;;;GAIG;AACH,eAAO,MAAM,eAAe,+OAoBlB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AACzD,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAC7D,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,aAAa,CAAC;AAEtD,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAA2C,CAAC;AAE5F,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;CACf;AAqDD,eAAO,MAAM,QAAQ,EAAE,SAAS,iBAAiB,EAOhD,CAAC;AAKF,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,iBAAiB,CAIlE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAEpE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAErD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,IAAI,WAAW,CAEpE"}
@@ -49,6 +49,20 @@ export const CONTROL_NAMES = [...AXIS_CONTROLS, ...BUTTON_CONTROLS];
49
49
  */
50
50
  const AXIS_BASE = 1001;
51
51
  const BUTTON_BASE = 1011;
52
+ /**
53
+ * 下拉里给运营看的名字。**与上面的 name 刻意不一致**(PF 2026-09-22)。
54
+ *
55
+ * name 是平台内部的角色名,档案按它映射按键,改它会动到导出的类型;label 只管一件事:
56
+ * 运营拿着方向盘的时候,能不能在下拉里一眼找到手上按的那个键。所以:
57
+ *
58
+ * - 背面四个用 `L1 / R1 / L2 / R2`。这是手柄行业的通用叫法,比原来自创的
59
+ * Paddle / Shoulder 通用,而且原来那个区分根本不存在——实测两次都落在同一对物理键上
60
+ * (换挡拨片就是 L2 / R2,见 profiles.ts)。
61
+ * - 正面四个用符号。Builder 的下拉**不可能知道现场插哪只盘**(配活动时设备还不在),
62
+ * 所以没有任何一种标签能对所有型号都准;既然如此,就对着我们实际在用的那只盘做到最好用。
63
+ * 词 + 符号并写:光一个 `△` 在下拉收起来时像渲染坏了,而且打不出来、搜不到;
64
+ * Inter 也确实没有这四个字形(2026-09-22 实测,会回退到系统字体),带着词就不怕它糊。
65
+ */
52
66
  const LABELS = {
53
67
  'wheel-left': 'Wheel Left',
54
68
  'wheel-right': 'Wheel Right',
@@ -58,18 +72,19 @@ const LABELS = {
58
72
  start: 'Wheel Start',
59
73
  select: 'Wheel Select',
60
74
  home: 'Wheel Home',
61
- 'paddle-left': 'Paddle Left',
62
- 'paddle-right': 'Paddle Right',
75
+ 'paddle-left': 'L2',
76
+ 'paddle-right': 'R2',
63
77
  'dpad-up': 'D-pad Up',
64
78
  'dpad-down': 'D-pad Down',
65
79
  'dpad-left': 'D-pad Left',
66
80
  'dpad-right': 'D-pad Right',
67
- 'action-1': 'Action 1',
68
- 'action-2': 'Action 2',
69
- 'action-3': 'Action 3',
70
- 'action-4': 'Action 4',
71
- 'shoulder-left': 'Shoulder Left',
72
- 'shoulder-right': 'Shoulder Right',
81
+ // 符号与位置的对应实测自 PS3/PC Wheel:△ 上、○ 右、✕ 下、□ 左(见 profiles.ts 的注释)
82
+ 'action-1': 'Cross (✕)',
83
+ 'action-2': 'Circle (○)',
84
+ 'action-3': 'Square (□)',
85
+ 'action-4': 'Triangle (△)',
86
+ 'shoulder-left': 'L1',
87
+ 'shoulder-right': 'R1',
73
88
  'aux-1': 'Aux 1',
74
89
  'aux-2': 'Aux 2',
75
90
  'aux-3': 'Aux 3',
@@ -15,7 +15,7 @@ export { createGamepad, GamepadSession, explainGamepadMiss } from './session.js'
15
15
  export type { AxesUpdate, CreateGamepadOptions, GamepadMissReason, GamepadState, GamepadStatus, Unsubscribe, } from './session.js';
16
16
  export { AXIS_CONTROLS, BUTTON_CONTROLS, CONTROLS, CONTROL_NAMES, controlByCode, controlByName, controlCode, isAxisControl, isControlCode, } from './controls.js';
17
17
  export type { AxisControl, ButtonControl, ControlDefinition, ControlName } from './controls.js';
18
- export { DEFAULT_THRESHOLDS, releaseAll, resolveThresholds, stepSignals } from './signals.js';
18
+ export { DEFAULT_THRESHOLDS, releaseAll, resolveThresholds, SENSITIVITY_MAX, SENSITIVITY_MIN, sensitivityFactor, stepSignals, } from './signals.js';
19
19
  export type { ControlEvent, ControlReading, SignalState, Thresholds } from './signals.js';
20
20
  export { PROFILES, matchProfile, selectDevice } from './profiles.js';
21
21
  export type { GamepadProfile, ProfileLookup, ProfileMatch } from './profiles.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gamepad/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACjF,YAAY,EACV,UAAU,EACV,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,WAAW,GACZ,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,aAAa,EACb,eAAe,EACf,QAAQ,EACR,aAAa,EACb,aAAa,EACb,aAAa,EACb,WAAW,EACX,aAAa,EACb,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEhG,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC9F,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1F,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACrE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEjF,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1G,YAAY,EACV,WAAW,EACX,OAAO,EACP,aAAa,EACb,cAAc,EACd,WAAW,EACX,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC5E,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gamepad/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACjF,YAAY,EACV,UAAU,EACV,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,WAAW,GACZ,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,aAAa,EACb,eAAe,EACf,QAAQ,EACR,aAAa,EACb,aAAa,EACb,aAAa,EACb,WAAW,EACX,aAAa,EACb,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEhG,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1F,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACrE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEjF,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1G,YAAY,EACV,WAAW,EACX,OAAO,EACP,aAAa,EACb,cAAc,EACd,WAAW,EACX,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC5E,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
@@ -13,7 +13,7 @@
13
13
  */
14
14
  export { createGamepad, GamepadSession, explainGamepadMiss } from './session.js';
15
15
  export { AXIS_CONTROLS, BUTTON_CONTROLS, CONTROLS, CONTROL_NAMES, controlByCode, controlByName, controlCode, isAxisControl, isControlCode, } from './controls.js';
16
- export { DEFAULT_THRESHOLDS, releaseAll, resolveThresholds, stepSignals } from './signals.js';
16
+ export { DEFAULT_THRESHOLDS, releaseAll, resolveThresholds, SENSITIVITY_MAX, SENSITIVITY_MIN, sensitivityFactor, stepSignals, } from './signals.js';
17
17
  export { PROFILES, matchProfile, selectDevice } from './profiles.js';
18
18
  export { decodeHat, deviceKey, normalizeBinding, parseDeviceIdentity, readBinding } from './normalize.js';
19
19
  export { LiveGamepadSource, MockGamepadSource, mockPad } from './source.js';
@@ -47,7 +47,7 @@ export interface CreateGamepadOptions {
47
47
  export declare class GamepadSession {
48
48
  private readonly source;
49
49
  private readonly profiles;
50
- private readonly thresholdOverrides?;
50
+ private thresholdOverrides?;
51
51
  private readonly waitMs;
52
52
  private readonly setTimer;
53
53
  private readonly clearTimer;
@@ -88,6 +88,8 @@ export declare class GamepadSession {
88
88
  * device, rather than null until the first animation frame lands.
89
89
  */
90
90
  private adoptProfile;
91
+ /** Device profile first, caller overrides on top. */
92
+ private recomputeThresholds;
91
93
  /** One-shot look at what is connected right now. */
92
94
  private probe;
93
95
  private startPolling;
@@ -119,6 +121,24 @@ export declare class GamepadSession {
119
121
  onStateChange(handler: (state: GamepadState) => void): Unsubscribe;
120
122
  /** The device seen last, matched or not. For operator-facing messages. */
121
123
  get device(): ProfileLookup | null;
124
+ /** The press and release lines in force right now, profile plus overrides. */
125
+ get activeThresholds(): Thresholds;
126
+ /**
127
+ * Changes the press and release lines while the session is running.
128
+ *
129
+ * This is how a campaign tunes the feel: a lane-change game wants the wheel
130
+ * to register early, a racing game wants it steady, and the operator sets
131
+ * that per activity rather than waiting for a release. Overrides sit on top
132
+ * of the device profile, so anything left out keeps the model's own value;
133
+ * pass null to drop the overrides and fall back to the profile.
134
+ *
135
+ * Anything held right now is released first. The presses that are down were
136
+ * decided under the old lines, and carrying them across the change mixes two
137
+ * sets of rules in one state: a control could sit above the new release line
138
+ * forever and never send the release a hold-mode module is waiting for.
139
+ * Starting clean costs one release event and removes the whole problem.
140
+ */
141
+ setThresholds(overrides: Partial<Thresholds> | null): void;
122
142
  /**
123
143
  * Releases anything held and stops polling, without ending the session.
124
144
  *
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/gamepad/session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/gamepad/session.ts"],"names":[],"mappings":"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"}
@@ -90,7 +90,14 @@ export class GamepadSession {
90
90
  if (profile === this.profile)
91
91
  return;
92
92
  this.profile = profile;
93
- this.thresholds = resolveThresholds({ ...profile.thresholds, ...this.thresholdOverrides });
93
+ this.recomputeThresholds();
94
+ }
95
+ /** Device profile first, caller overrides on top. */
96
+ recomputeThresholds() {
97
+ this.thresholds = resolveThresholds({
98
+ ...this.profile?.thresholds,
99
+ ...this.thresholdOverrides,
100
+ });
94
101
  }
95
102
  /** One-shot look at what is connected right now. */
96
103
  probe() {
@@ -248,6 +255,30 @@ export class GamepadSession {
248
255
  get device() {
249
256
  return this.lastLookup;
250
257
  }
258
+ /** The press and release lines in force right now, profile plus overrides. */
259
+ get activeThresholds() {
260
+ return { ...this.thresholds };
261
+ }
262
+ /**
263
+ * Changes the press and release lines while the session is running.
264
+ *
265
+ * This is how a campaign tunes the feel: a lane-change game wants the wheel
266
+ * to register early, a racing game wants it steady, and the operator sets
267
+ * that per activity rather than waiting for a release. Overrides sit on top
268
+ * of the device profile, so anything left out keeps the model's own value;
269
+ * pass null to drop the overrides and fall back to the profile.
270
+ *
271
+ * Anything held right now is released first. The presses that are down were
272
+ * decided under the old lines, and carrying them across the change mixes two
273
+ * sets of rules in one state: a control could sit above the new release line
274
+ * forever and never send the release a hold-mode module is waiting for.
275
+ * Starting clean costs one release event and removes the whole problem.
276
+ */
277
+ setThresholds(overrides) {
278
+ this.thresholdOverrides = overrides ?? undefined;
279
+ this.recomputeThresholds();
280
+ this.emitEvents(this.flushReleases());
281
+ }
251
282
  /**
252
283
  * Releases anything held and stops polling, without ending the session.
253
284
  *
@@ -26,13 +26,18 @@ export interface Thresholds {
26
26
  buttonRelease: number;
27
27
  }
28
28
  /**
29
- * Starting values, to be tuned against the real wheel before release.
29
+ * Steering was tuned on the real wheel (PF 2026-09-22): at 0.35 of full lock
30
+ * it had to be dragged round too far before a lane change registered, 0.2
31
+ * lands where a player expects it. Release sits at half of press, so the wheel
32
+ * has to come most of the way back before the next turn counts.
30
33
  *
31
- * Steering sits high so a hand resting slightly off centre does not steer;
32
- * pedals sit low because timing games score the instant of the press, and a
33
- * pedal that only registers when floored feels late. A profile may override
34
- * any of these: a 900-degree wheel needs a much lower steering line than a
35
- * 270-degree one to feel the same.
34
+ * Pedals sit where they are because timing games score the instant of the
35
+ * press, and a pedal that only registers when floored feels late. That they
36
+ * now read higher than steering is not a contradiction: a fifth of full lock
37
+ * is a real turn of the wheel, a quarter of pedal travel is a light touch.
38
+ *
39
+ * A profile may override any of these: a 900-degree wheel needs a much lower
40
+ * steering line than a 270-degree one to feel the same.
36
41
  */
37
42
  export declare const DEFAULT_THRESHOLDS: Thresholds;
38
43
  export declare function resolveThresholds(overrides?: Partial<Thresholds>): Thresholds;
@@ -75,4 +80,8 @@ export declare function releaseAll(previous: SignalState): {
75
80
  state: SignalState;
76
81
  events: ControlEvent[];
77
82
  };
83
+ export declare const SENSITIVITY_MIN = 1;
84
+ export declare const SENSITIVITY_MAX = 10;
85
+ /** 这一档等于设备档案出厂手感的多少倍。超出 1-10 的输入按中间档处理。 */
86
+ export declare function sensitivityFactor(level: number): number;
78
87
  //# sourceMappingURL=signals.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../src/gamepad/signals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,eAAe,CAAC;AAG9D,MAAM,WAAW,UAAU;IACzB,gEAAgE;IAChE,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,UAOhC,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAE7E;AAED,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,kFAAkF;AAClF,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AAE1E,eAAO,MAAM,kBAAkB,EAAE,WAAgB,CAAC;AAElD,wBAAgB,YAAY,IAAI,cAAc,CAE7C;AAqDD;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,cAAc,EACvB,UAAU,GAAE,UAA+B,GAC1C;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,YAAY,EAAE,CAAA;CAAE,CAmBhD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,WAAW,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,YAAY,EAAE,CAAA;CAAE,CAMhG"}
1
+ {"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../src/gamepad/signals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,eAAe,CAAC;AAG9D,MAAM,WAAW,UAAU;IACzB,gEAAgE;IAChE,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,EAAE,UAOhC,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAE7E;AAED,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,kFAAkF;AAClF,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AAE1E,eAAO,MAAM,kBAAkB,EAAE,WAAgB,CAAC;AAElD,wBAAgB,YAAY,IAAI,cAAc,CAE7C;AAqDD;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,cAAc,EACvB,UAAU,GAAE,UAA+B,GAC1C;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,YAAY,EAAE,CAAA;CAAE,CAmBhD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,WAAW,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,YAAY,EAAE,CAAA;CAAE,CAMhG;AAeD,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,2CAA2C;AAC3C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIvD"}
@@ -1,16 +1,21 @@
1
1
  import { AXIS_CONTROLS, BUTTON_CONTROLS } from './controls.js';
2
2
  /**
3
- * Starting values, to be tuned against the real wheel before release.
3
+ * Steering was tuned on the real wheel (PF 2026-09-22): at 0.35 of full lock
4
+ * it had to be dragged round too far before a lane change registered, 0.2
5
+ * lands where a player expects it. Release sits at half of press, so the wheel
6
+ * has to come most of the way back before the next turn counts.
4
7
  *
5
- * Steering sits high so a hand resting slightly off centre does not steer;
6
- * pedals sit low because timing games score the instant of the press, and a
7
- * pedal that only registers when floored feels late. A profile may override
8
- * any of these: a 900-degree wheel needs a much lower steering line than a
9
- * 270-degree one to feel the same.
8
+ * Pedals sit where they are because timing games score the instant of the
9
+ * press, and a pedal that only registers when floored feels late. That they
10
+ * now read higher than steering is not a contradiction: a fifth of full lock
11
+ * is a real turn of the wheel, a quarter of pedal travel is a light touch.
12
+ *
13
+ * A profile may override any of these: a 900-degree wheel needs a much lower
14
+ * steering line than a 270-degree one to feel the same.
10
15
  */
11
16
  export const DEFAULT_THRESHOLDS = {
12
- steeringPress: 0.35,
13
- steeringRelease: 0.2,
17
+ steeringPress: 0.2,
18
+ steeringRelease: 0.1,
14
19
  pedalPress: 0.25,
15
20
  pedalRelease: 0.12,
16
21
  buttonPress: 0.5,
@@ -110,3 +115,24 @@ export function releaseAll(previous) {
110
115
  }
111
116
  return { state: EMPTY_SIGNAL_STATE, events };
112
117
  }
118
+ /**
119
+ * 运营配的灵敏度(1-10)换成阈值倍率。
120
+ *
121
+ * 倍率越小越灵敏(阈值越低,越早算按下)。`5` 必须正好是 `1.0`,也就是「不覆盖,用设备
122
+ * 档案自己的值」。乘在**档案的阈值**上而不是一组写死的数字上:900 度与 270 度的方向盘,
123
+ * 同样「正常」对应的行程完全不同,这样换一只盘、同一个活动还是正常。
124
+ *
125
+ * 放在 SDK 而不是各端各写一份:runner 拿它算真的阈值,Builder 拿它在字段说明里报出
126
+ * 「这一档相当于出厂手感的百分之多少」(设计系统 module-config §12 要求抽象档位必须报出
127
+ * 换算值)。两边抄两份的话,数字一旦不一致,Builder 的提示就会说谎。
128
+ */
129
+ const SENSITIVITY_FACTORS = [2.5, 2.0, 1.6, 1.3, 1.0, 0.85, 0.72, 0.6, 0.5, 0.4];
130
+ export const SENSITIVITY_MIN = 1;
131
+ export const SENSITIVITY_MAX = 10;
132
+ /** 这一档等于设备档案出厂手感的多少倍。超出 1-10 的输入按中间档处理。 */
133
+ export function sensitivityFactor(level) {
134
+ if (!Number.isFinite(level))
135
+ return 1;
136
+ const index = Math.round(level) - SENSITIVITY_MIN;
137
+ return SENSITIVITY_FACTORS[index] ?? 1;
138
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@realnation/builder-shared-sdk",
3
- "version": "2.6.0",
3
+ "version": "2.8.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "exports": {