You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The engine saves the current parameter values as its baseline at the start of
every frame and restores them at the end, so a write made after
`internalModel.update()` is baked into the next frame's baseline. `add` writes
are relative to the current value, so every frame stacked on top of the previous
frame's own result: the parameter reached its limit within a few frames and
stayed there (head pinned at +/-30, `breath` pinned at 1).
- apply `add` as `engine baseline + contribution` instead of
`current value + contribution`
- release the contribution once a writer stops
- `reset()` drops pending writes and bookkeeping on a model switch
- `override` semantics unchanged
Also drops the per-parameter `filter()/filter()/reduce()/reduce()` allocations.
…event
The engine saves the parameter values as a baseline every frame and restores
that baseline at the end of the same frame, so a write made after
`internalModel.update()` became part of the next frame's baseline: an `add`
write stacked on top of its own previous result until the parameter reached its
limit.
The previous approach recovered the baseline by subtracting our own previous
contribution, which can leave an offset behind - a fading motion blends on top
of our leftover, so the recovered value is only approximate for the duration of
that fade.
Apply the writes from the engine's `beforeModelUpdate` event instead: it runs
after the baseline was saved and before the model is rendered with those
parameters, so a write is visible for exactly one frame and the engine drops it
afterwards. No contribution bookkeeping or value guessing is needed.
- `add` is applied on top of the engine's current value
- `override` keeps its conflict resolution, now resolved in the same single pass
- drops `AppliedAdd`, `appliedAdds`, `releaseStaleContributions` and the
write-back comparison
Note: a one-shot `override` (the DevTools parameter slider) is now applied for
the frame it was queued in; a caller that needs it to hold has to queue it every
frame.
A write applied from the engine's `beforeModelUpdate` event only survives
the frame it was queued in: the engine restores its own parameter baseline
at the end of every frame. That is what stops `add` writes from
accumulating, but it also meant a writer that knows its value once - the
DevTools parameter slider, an FSM state profile - only took effect for a
single frame.
`ParameterCoordinator.holdOverride()` re-applies such a value on every
flush until `releaseOverride()` (optionally restricted to one source).
The DevTools slider holds its value as MANUAL, FSM state profiles hold
theirs as FSM and release them on state exit, and `getSemanticParameters()`
reports the held value so the panel shows what is actually being applied.
A queued write suppressed by a hold is not logged as a conflict: the hold
is re-applied every frame, so logging it would flood the conflict log.
`flush()` runs on every engine frame. Tracking which parameters were
already resolved in a fresh `Set` allocated one object per frame even when
nothing is held; the queue itself still holds this frame's parameters at
that point, so it doubles as the lookup.
The new engine-hook path is not covered by the controller tests: they exercise ParameterCoordinator with a hand-built lifecycle rig, but never call initialize() with an internalModel emitter to verify that beforeModelUpdate actually flushes/captures and that destroy() removes the listener. A regression in the event name or subscription/cleanup would therefore pass the suite while breaking the runtime fix; add a focused controller integration test for both dispatch and teardown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does / why we need it:
beforeModelUpdate阶段应用参数写入,避免鼠标追踪、呼吸等add值被逐帧累加到引擎基线。exitProfile.semanticParameters的归零行为;保留队列写入之间的冲突记录,对持续发生的锁定值冲突去重。验证:
pnpm exec vitest run:224 项测试通过。pnpm build:TypeScript 检查及两个 Vite 构建通过。.moc3模型:加法参数不累加;手动和 FSM 控制可恢复;情绪及程序动画终点保持;模型切换清除旧锁定值。Which issue(s) this PR fixes:
Fixes #84
Does this PR introduce a user-facing change?