88 lines
2.5 KiB
JavaScript
88 lines
2.5 KiB
JavaScript
/**
|
|
* Deterministic executable model for the XZBT 0.1 GC3 resolution contract.
|
|
*
|
|
* This is a Phase 0 contract oracle, not the production runtime resolver.
|
|
*/
|
|
|
|
export function clamp(value, minimum, maximum) {
|
|
return Math.min(maximum, Math.max(minimum, value));
|
|
}
|
|
|
|
export function bindingValue(source, { scale = 1, offset = 0, clamp: limits } = {}) {
|
|
let result = source * scale + offset;
|
|
if (limits) result = clamp(result, limits[0], limits[1]);
|
|
return result;
|
|
}
|
|
|
|
export function smoothBinding(previous, input, dtSeconds, tauSeconds) {
|
|
if (tauSeconds === 0 || previous === undefined) return input;
|
|
const alpha = 1 - Math.exp(-dtSeconds / tauSeconds);
|
|
return previous + alpha * (input - previous);
|
|
}
|
|
|
|
export function easingValue(name, t) {
|
|
const bounded = clamp(t, 0, 1);
|
|
switch (name) {
|
|
case 'linear':
|
|
return bounded;
|
|
case 'ease-in':
|
|
return bounded * bounded;
|
|
case 'ease-out':
|
|
return 1 - (1 - bounded) * (1 - bounded);
|
|
case 'ease-in-out':
|
|
return bounded < 0.5
|
|
? 2 * bounded * bounded
|
|
: 1 - ((-2 * bounded + 2) ** 2) / 2;
|
|
default:
|
|
throw new RangeError(`Unsupported easing: ${name}`);
|
|
}
|
|
}
|
|
|
|
export function lerp(from, to, amount) {
|
|
return from + (to - from) * amount;
|
|
}
|
|
|
|
export function attackValue(origin, target, progress, easing = 'linear') {
|
|
return lerp(origin, target, easingValue(easing, progress));
|
|
}
|
|
|
|
export function releaseValue(releaseStart, currentLower, progress, easing = 'linear') {
|
|
return lerp(currentLower, releaseStart, 1 - easingValue(easing, progress));
|
|
}
|
|
|
|
export function selectWinningOverride(overrides) {
|
|
return overrides
|
|
.filter((override) => override.live !== false)
|
|
.reduce((winner, candidate) => {
|
|
if (!winner) return candidate;
|
|
if (candidate.priority !== winner.priority) {
|
|
return candidate.priority > winner.priority ? candidate : winner;
|
|
}
|
|
return candidate.activationSequence > winner.activationSequence ? candidate : winner;
|
|
}, null);
|
|
}
|
|
|
|
export function resolveNumericTarget({
|
|
base,
|
|
binding,
|
|
automation,
|
|
overrides = [],
|
|
modulation = 0,
|
|
safetyClamp = [-Infinity, Infinity]
|
|
}) {
|
|
const afterBinding = binding ?? base;
|
|
const lower = automation ?? afterBinding;
|
|
const winner = selectWinningOverride(overrides);
|
|
const afterOverride = winner ? winner.value : lower;
|
|
const beforeClamp = afterOverride + modulation;
|
|
return {
|
|
base,
|
|
afterBinding,
|
|
lower,
|
|
winner: winner?.id ?? null,
|
|
afterOverride,
|
|
beforeClamp,
|
|
resolved: clamp(beforeClamp, safetyClamp[0], safetyClamp[1])
|
|
};
|
|
}
|