Docs: 2026-08-13 — Track A (camera) shipped alongside Track B

Session log gains Part 3: the operator picked "drop" on the hold fork, and both
halves of the camera fix landed. Records the measurement that forced the second
half — dropping the hold ALONE was worse (max deviation 0.653 vs 0.447) because the
hold had been masking the shake-integration bug — plus the before/after table and
the PixelArtDevControls opt-in.

Gotchas archive gains four more entries: never let a transient offset live in the
value your smoothing filter reads back; a frame-counted hold is a framerate-
dependent freeze; a masking fix can make the metric worse before better, so
re-measure the intermediate state; HideFlags.DontSave objects survive play-mode
exit and leak one per domain reload.

CLAUDE.md gains a Camera-feel ★ line, paid for by trimming the MCP-edit, swept-hit,
LANTERN-direction, harvest, bootstrap and presentation bullets. Now 39936 bytes —
exactly the >=1 KB headroom target.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-13 23:09:53 -07:00
parent 150f30f56c
commit 5dced78de2
3 changed files with 85 additions and 23 deletions
@@ -616,3 +616,30 @@ this session (net-zero rule): the six items below stay here, one condensed point
9. **Injecting a kill: append a lethal `DamageEvent`, never write `Health.Current = 0`.**
`HealthApplyDamageSystem` early-`continue`s on an empty `DamageEvent` buffer, so a direct Health write is
never seen by the death branch and no `Dying` is ever stamped.
### 2026-08-13b — camera feel (Track A, same session)
10. **★ Never let a transient offset (shake, recoil, punch) live in the same value your smoothing filter reads
back.** `Lerp(transform.position, desired, k)` where `transform.position` already carries last frame's shake
makes the filter treat shake as real positional error and INTEGRATE it — at `FollowSharpness 8` / ~12 ms
that is ~9 %/frame, so it washes out over half a second while new shake piles on. Measured on a stationary
player (ideal motion = 0): one kill left the camera 0.447 units off-frame, still 0.199 off 24 frames later.
Fix: smooth a private `_basePos` the offset never touches; add the offset only when writing the transform.
After: deviation returns to 0.000 within a few frames, mean 0.038.
11. **A frame-counted hold is a framerate-dependent freeze.** `FinisherHoldFrames = 7` was documented as
"~117 ms" — true only at 60 fps; it is 49 ms at 144 and 233 ms at 30. Anything that gates on *feel duration*
must be time-based. Worse, the hold branch took its base from `transform.position`, permanently baking that
frame's shake in (a measured 0.283-unit single-frame jump).
12. **★ A masking fix can make the metric WORSE before it makes it better — measure the intermediate state.**
Dropping the camera hold alone measured worse than leaving it (max deviation 0.653 vs 0.447), because the
hold had been pinning the camera during the frames shake was loudest and thereby hiding the integration bug
in #10. Had I shipped the drop on its own and stopped, the "fix" would have been a regression. Re-measure
after each half of a two-part fix.
13. **`HideFlags.DontSave` objects SURVIVE play-mode exit.** A self-spawning dev tool created with
`HideAndDontSave` + `DontDestroyOnLoad` outlives the play session while its `static _instance` guard is
cleared by the domain reload — so it leaks one live instance per reload (two were found). If you gate such
a bootstrap off, also sweep the existing strays with
`Resources.FindObjectsOfTypeAll<GameObject>()``GameObject.Find` alone will not show you the history.