Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | 1x 1x 2x 2x 2x 1x 1x | import { deepMergeRecord } from '../internal/deepMergeRecord.js';
/** Runtime-configurable session features. Nested objects deliberately mirror
* the profile JSON so the normal profile merge and provenance rules apply. */
export type MoveBackTriggerSpec = {
kind: 'moveBack';
windowMs: number;
};
/** A shake gesture over the calibrated gyro stream. Params default to
* `ShakeTrigger.defaults`; a profile or host overrides only what it needs. */
export type ShakeTriggerSpec = {
kind: 'shake';
minStepAngleDeg?: number;
minSteps?: number;
minReversals?: number;
maxSampleGapMs?: number;
burstWindowMs?: number;
faceGuardMs?: number;
cooldownMs?: number;
};
/** One configured app-level gesture detector. */
export type CustomTriggerSpec = MoveBackTriggerSpec | ShakeTriggerSpec;
/** Complete runtime feature configuration after profile resolution. */
export type SessionFeatures = {
stabilizer: {
enabled: boolean;
radiusDeg: number;
snapDeg: number;
velocityMax: number;
hysteresis: { enabled: boolean; marginDeg: number };
drift: { enabled: boolean; degPerSec: number };
};
regrip: {
enabled: boolean;
};
customTrigger: { enabled: boolean; triggers: CustomTriggerSpec[] };
};
/** Partial profile or host override for session features. */
export type SessionFeaturesPatch = {
stabilizer?: {
enabled?: boolean;
radiusDeg?: number;
snapDeg?: number;
velocityMax?: number;
hysteresis?: { enabled?: boolean; marginDeg?: number };
drift?: { enabled?: boolean; degPerSec?: number };
};
regrip?: {
enabled?: boolean;
};
customTrigger?: { enabled?: boolean; triggers?: CustomTriggerSpec[] };
};
/** Baseline feature configuration used when no profile overrides it. */
export const defaultSessionFeatures: SessionFeatures = {
stabilizer: {
enabled: true,
radiusDeg: 35,
snapDeg: 4,
velocityMax: 2.5,
hysteresis: { enabled: true, marginDeg: 6 },
drift: { enabled: true, degPerSec: 2 },
},
// Virtual regrips were opt-in before the feature model.
regrip: { enabled: false },
// Move-back gestures were always enabled before the feature model.
customTrigger: { enabled: true, triggers: [{ kind: 'moveBack', windowMs: 300 }] },
};
/** Useful explicit starting points for hosts which do not use profiles. */
export const featurePresets: Record<'all' | 'minimal' | 'none', SessionFeatures> = {
all: {
...defaultSessionFeatures,
regrip: { enabled: true },
customTrigger: {
enabled: true,
triggers: [{ kind: 'moveBack', windowMs: 300 }, { kind: 'shake' }],
},
},
minimal: {
...defaultSessionFeatures,
regrip: { ...defaultSessionFeatures.regrip, enabled: false },
customTrigger: { ...defaultSessionFeatures.customTrigger, enabled: false },
},
none: {
...defaultSessionFeatures,
stabilizer: { ...defaultSessionFeatures.stabilizer, enabled: false },
regrip: { ...defaultSessionFeatures.regrip, enabled: false },
customTrigger: { ...defaultSessionFeatures.customTrigger, enabled: false },
},
};
/** Deeply merge a feature patch. Arrays (the trigger list) replace wholesale. */
export function mergeSessionFeatures(
base: SessionFeatures,
patch: SessionFeaturesPatch | undefined,
): SessionFeatures {
Iif (!patch) return base;
return deepMergeRecord(base, patch) as SessionFeatures;
}
/** Resolve profile feature overrides onto the baseline configuration. */
export function resolveSessionFeatures(profileFeatures?: SessionFeaturesPatch): SessionFeatures {
return mergeSessionFeatures(defaultSessionFeatures, profileFeatures);
}
/** Adapter for the existing domain stabilizer configuration. */
export function stabilizerConfig(features: SessionFeatures): {
radiusDeg: number;
snapDeg: number;
hysteresisDeg: number;
velocityMax: number;
driftDegPerSec: number;
} {
const { stabilizer } = features;
return {
radiusDeg: stabilizer.radiusDeg,
snapDeg: stabilizer.snapDeg,
hysteresisDeg: stabilizer.hysteresis.enabled ? stabilizer.hysteresis.marginDeg : 0,
velocityMax: stabilizer.velocityMax,
driftDegPerSec: stabilizer.drift.enabled ? stabilizer.drift.degPerSec : 0,
};
}
|