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
@@ -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.
35. 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.