Skip to content

feat(spring): точные observable constructors без semantic feel #230

Description

@lemone112

Пользовательский результат

Пользователь может описать пружину наблюдаемыми свойствами движения — реальным первым перелётом, временем первого пика, периодом и half-life — вместо подбора stiffness/damping или субъективных light/heavy/playful.

Новые constructors являются точными координатными преобразованиями одной second-order модели, а не новой физикой и не пресетами.

Constructor A: first overshoot + peak time

Пусть:

M  = доля первого перелёта относительно амплитуды, 0 < M <= 1
tp = время первого пика > 0
L  = -ln(M)

Для пружины из покоя:

ζ  = L / sqrt(π²+L²)
ω₀ = sqrt(π²+L²) / tp
k  = m(π²+L²)/tp²
c  = 2mL/tp

Последние две формулы особенно важны: один log, без итераций, и k не требует sqrt.

Предлагаемый API-уровень:

fromPeak({
  overshoot: 0.08,
  peakTime: 0.22,
  mass?: 1,
})

Точное имя согласовать с naming conventions; семантика обязательна.

Контрольный пример

overshoot = 0.08
peakTime  = 0.22s
mass      = 1

ζ  ≈ 0.6265771869
ω₀ ≈ 18.3226982847
k  ≈ 335.7212724332
c  ≈ 22.9611694937

Первый пик обязан быть 1.08 ровно при t=0.22 в математическом oracle.

Constructor B: damped period + envelope half-life

Пусть:

P = damped oscillation period > 0
h = envelope half-life > 0
α = ln(2)/h
β = 2π/P

Комплексные полюса:

p = -α ± iβ

Параметры:

ω₀ = sqrt(α²+β²)
ζ  = α/ω₀
k  = m(α²+β²)
c  = 2mα

Возможный API:

fromOscillation({
  period: 0.4,
  halfLife: 0.18,
  mass?: 1,
})

Отношение к существующим API

Сохранить:

  • raw mass/stiffness/damping как interoperability API;
  • duration/bounce и visualDuration/bounce как SwiftUI/Motion-compatible coordinates;
  • react-spring presets как явно названную compatibility surface.

Новые constructors не заменяют существующие, но дают более буквальный professional authoring contract.

Важная документационная правда о bounce

При текущем ζ=1-bounce видимый первый перелёт:

M = exp(-πζ/sqrt(1-ζ²))

Он нелинеен по bounce. Документация не должна называть bounce=0.5 «50% overshoot».

Нужна generated reference table/interactive docs из формулы, но не хардкод ручных значений в prose.

Домены и taxonomy

fromPeak

  • только underdamped из покоя;
  • 0 < overshoot <= 1;
  • peakTime > 0;
  • mass > 0;
  • overshoot -> 0 имеет critical limit, но точный 0 должен либо маршрутизироваться в отдельный no-overshoot constructor, либо отклоняться — решение явно зафиксировать, не подставлять epsilon.

fromOscillation

  • только underdamped;
  • finite positive period/halfLife/mass;
  • не принимать «period=∞» как скрытый critical branch.

Executor representability остаётся #218, constructors не искажают параметры ради budget.

RED / доказательства

  1. Independent Wolfram/high-precision inverse oracle.
  2. fromPeak: найденный solver peak time и first overshoot совпадают с запросом на широком домене.
  3. fromOscillation: соседние peak amplitudes уменьшаются вдвое за declared half-life; period exact.
  4. Round-trip через (ω₀,ζ) и raw (m,k,c).
  5. Scale invariance по mass.
  6. Boundary fuzz near M→0, M→1, tiny/large times без NaN/Infinity.
  7. Constructors exact и не содержат settle coercion.
  8. Type/error docs/generated examples.
  9. Mutation: sign/log/π/time-square/mass factors.
  10. Import cost: unused constructors tree-shake; nano byte-identical.

Не входит

  • semantic presets;
  • автоматический выбор «красивого» overshoot;
  • arbitrary initial velocity inverse design;
  • nonlinear/dynamic damping;
  • изменение solver.

Зависит: #218, #226. Родитель: #225. Связано: #105, #219.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions