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:
+47
-13
@@ -52,8 +52,9 @@ Three root causes, all in `PrototypeCameraRig.LateUpdate`:
|
||||
Plus a **one-off 41 ms spike on the first kill** (+44 KB) — first-use warmup of the death VFX/audio path;
|
||||
later kills cost ~15 ms.
|
||||
|
||||
A full remediation plan was presented (Track A camera, Track B allocation, Track C feel). **The operator chose
|
||||
Track B.** Track A and C remain open — see *Next session*.
|
||||
A full remediation plan was presented (Track A camera, Track B allocation, Track C feel). The operator chose
|
||||
**Track B** first, then — on the hold fork — chose **drop**, and Track A shipped in the same session (Part 3).
|
||||
Track C remains open.
|
||||
|
||||
## Part 2 — Track B shipped
|
||||
|
||||
@@ -175,20 +176,53 @@ occurred.*
|
||||
owners.
|
||||
3–5. Two duplicated comment blocks left by structured edits, and a doc-accuracy nit on the ring-size rationale.
|
||||
|
||||
## Part 3 — Track A shipped (the camera), + the dev-tool contaminant
|
||||
|
||||
Operator resolved the fork: **drop the position hold**, impact rides the FOV punch + shake.
|
||||
|
||||
**A2 — the hold is gone.** `PrototypeCameraRig.Hold`/`s_holdFrames`, `CombatFeedbackSystem.TryHold` and its four
|
||||
call sites, and the `HitStopMaxFrames` / `HitStopFreezeEnabled` / `FinisherHoldFrames` knobs all retired; the
|
||||
three saved feel profiles drop the dead keys (`FeelProfileService` skips unknown keys with a warning, so this
|
||||
was safe either way — verified before removing).
|
||||
|
||||
**A1 — the shake channel, which the measurement forced.** Dropping the hold *alone* measured **worse** (max
|
||||
deviation 0.653 vs 0.447): the hold had been partly masking the real bug by pinning the camera during the
|
||||
frames shake was loudest. So A1 landed too — the follow now smooths a `_basePos` that shake never touches, and
|
||||
shake is applied only when writing the transform.
|
||||
|
||||
| | max per-frame step | max deviation | mean deviation |
|
||||
|---|---|---|---|
|
||||
| Original | 0.283 | 0.447 (still 0.199 at +24 frames) | — |
|
||||
| Hold dropped only | 0.429 | 0.653 | — |
|
||||
| **Both fixes** | 0.428 (the shake impulse itself) | **0.329, back to 0.000 within a few frames** | **0.038** |
|
||||
|
||||
Deviation at f42/f45/f50 after the f40 kill is now literally `0.000` (was 0.269/0.429/0.399). Shake reads as a
|
||||
crisp transient punch instead of a drift the follow filter spends half a second digesting.
|
||||
|
||||
**`PixelArtDevControls` is now opt-in.** Gated behind an EditorPrefs toggle (checked menu item, mirroring
|
||||
`ProjectM/Boot Into Menu (Editor)`), off by default. Extra find: the object carries `HideFlags.DontSave`, so it
|
||||
**survives play-mode exit** while the static `_instance` does not — the old code leaked one instance per domain
|
||||
reload, and two live strays were cleared out of the editor.
|
||||
|
||||
## Notes / loose ends
|
||||
|
||||
- **`Assets/_Project/Shaders/PixelOutline.mat` is modified in the working tree and is NOT mine to commit.**
|
||||
`PixelArtDevControls` writes straight to the shared material asset, and `_MasterEnabled` flipped 0→1 with
|
||||
posterize/normal-edges off during the Play sessions. Left untouched in case the toggle was deliberate;
|
||||
excluded from the Track B commits. It is a real look change — decide before committing.
|
||||
- **CLAUDE.md is at 39 850 / 40 960 bytes.** A condensation pass is due; this session's long-form lessons went
|
||||
to the gotchas archive rather than inline.
|
||||
- `Assets/_Project/Shaders/PixelOutline.mat` was dirtied by `PixelArtDevControls` writing to the shared material
|
||||
asset during the Play sessions (`_MasterEnabled` 0→1). **Reverted on the operator's instruction** — it was not
|
||||
an intentional change. The dev tool is now opt-in, so it cannot recur silently.
|
||||
- **CLAUDE.md is at 39 936 / 40 960 bytes** — exactly the ≥1 KB-headroom target. Two ★ rules were added (camera
|
||||
feel; pooling + per-frame cost) and paid for under the net-zero rule by retiring the DR-051 build-palette text
|
||||
(that code died with the purge), the two purge enumerations now carried by their DRs, and prose trims across
|
||||
the MCP-edit, swept-hit, LANTERN-direction and presentation bullets. It is still tight — a dedicated
|
||||
condensation pass would buy room for the next few sessions.
|
||||
|
||||
## Next session
|
||||
|
||||
1. **Track A — the camera** (this is what the operator's report actually describes, and it is still unfixed):
|
||||
split the base/shake channels, make the hold time-based and shake-safe, de-stack the lethal frame, prewarm
|
||||
the first-kill VFX. Open fork: keep the camera hold at all, or drop it and carry impact on FOV + shake.
|
||||
2. **Track C — feel**: enemies have **no collider** (you walk through them); FOV pumps on every hit; the 0.9 s
|
||||
corpse window wants re-judging once the camera is fixed.
|
||||
1. **Track A leftovers** (the two smaller items from the original plan, not yet done): **de-stack the lethal
|
||||
frame** — the hit package and the kill package still both fire on the kill (measured shake 0.10+0.20 stacking,
|
||||
two FOV punches, two SFX, four bursts) — and **prewarm** the first-kill VFX/audio path to kill the one-off
|
||||
41 ms spike.
|
||||
2. **Track C — feel**: enemies have **no collider** (you walk straight through them, which is the biggest
|
||||
remaining feel gap); FOV pumps on every hit; the 0.9 s corpse window wants re-judging now the camera is calm.
|
||||
3. Measure allocation in a **player build** to get a number free of editor contamination.
|
||||
4. **Eyes-on the camera.** The numbers say it settles; whether the impact still reads as *impact* with the hold
|
||||
gone is a feel call only the operator can make.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user