a3a7b83236
Every fix here is the same shape: the keyframe data was already parsed
correctly and then dropped somewhere downstream, with no error logged.
Found by dumping the authoritative schema with tools/ and comparing against
what the handlers actually consume.
BgColor1 (8) — the largest track in the corpus, 43617 keys / 59 songs
* AlterUpdate_BgColor1 filtered on a `validBgColorNames` whitelist of four
character group names, discarding the other 16 stage groups outright.
On song 1177 that is ~92% of the track's keys. Filter removed; Director
now routes by group name (characters vs stage).
* Stage branch resolves renderers by walking the whole stage hierarchy.
StageObjectMap alone is not enough: it dedupes by name, and crowd groups
have 66-570 same-named objects, so only the first was ever coloured.
* Writes _MulColor0, confirmed by enumerating the shaders' property tables.
_AmbientColor belongs to BgColor2 — they are separate channels on the
same shader and must not be written by both.
* Populates fields the dispatcher had always left at default: colorPower,
scale, vertexColorToonPower, outlineWidthPower, LightBlendMode,
IsSilhouette, IsProjector, TimelineName.
Object (33) — the neon sign never descended from the ceiling
* The group name `neonsign` is a StageController._stageObjectUnits *unit*
name; no GameObject of that name exists, so the whole track never fired.
UpdateObject now falls back to StageObjectUnitMap and applies to each
child of the unit.
* ObjectUpdateInfo.OffsetType was populated by the dispatcher but never
read, so Add-relative positions were written as absolute and objects
snapped to their parent's origin. Now honoured against a lazily captured
base local TRS.
BlinkLight (45) — 19420 keys / 57 songs, the biggest lighting payload
* Wrote _Color, which does not exist on Gallop/3D/Live/Stage/LightBlinkBlend
(its colour channel is _BlinkLightColor), so the write was a no-op and the
lights rendered black. Now probes the shader for the real property.
* Brightness goes to _ColorPower instead of being folded into the colour,
falling back to colour*power only where that property is absent.
* Uses MaterialPropertyBlock; the old path hit Renderer.materials every
frame, allocating and breaking batching.
PostFilm (39) — ~20200 keys / 59 songs, previously recorded as empty
* Data class fields reordered to the bundle's TypeTree order and the five
missing BlinkLight* fields added; LiveTimelineKeyPostFilmDataList created;
postFilmKeys / postFilm2Keys / postFilm3Keys declared on the worksheet.
Runtime now deserializes 100 / 161 / 87 keys on song 1177.
* AlterUpdate_PostFilm dispatch with interpolation, PostFilmUpdateInfo,
a URP ScriptableRendererFeature and a full-screen blit shader.
* Rendering is disabled by default: filmOptionParam's geometry is undefined
anywhere we can read. All 100 keys on song 1177 are Vignette variants, so
that parameter decides the whole look, and the shader that defines it is
not in the `shader` bundle (all 499 searched by name and by property
signature) — it ships inside the app binary.
Diagnostics
* LiveTimelineWorksheetDiag dumps every track field with group names and key
counts, and Probe() tests whether a candidate field name matches the
bundle TypeTree. Confirmed worksheetList.Count == 1 (SheetType MainLive),
and that WashLightList really is spelled with a capital W — upstream
katboi01 uses washLightList, which never populates.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>