diff --git a/logs/laneB.md b/logs/laneB.md index e90aa1c..3671a24 100644 --- a/logs/laneB.md +++ b/logs/laneB.md @@ -529,3 +529,39 @@ NEXT: nothing required. Backlog if a session 9 lands, in order: (1) "nudge to (2) box-select still only grabs keys, not clip/audio blocks or cuts; (3) per-drag undo coalesce (a mousemove drag still pushes one entry per frame); (4) film-level `audio[]` has no UI — the obvious partner to ♪ align. + +## 2026-07-26 session 8b (SYNC13 follow-up: drop no-op kept cuts) +DONE: orchestrator's M10-B acceptance note actioned — a kept cut that selects the + camera already live is now DROPPED, not preserved. `autoCutPlan` (`timeline.js:668-690`) + no longer filters `kept` positionally; it merges the surviving existing cuts with + the about-to-be-placed ones, sorts by t, walks the merged list tracking the + EFFECTIVE camera, and splits in-range user cuts into `kept` (changes the angle) + vs `dropped` (`camera === eff` — cuts cam2→cam2, i.e. nothing). `autoCut` + (`:704`) removes `dropped` alongside `replaced`, inside the same `group()`, so it + is still ONE undo. Popover line now reads "… · 2 of your cuts kept · 1 dropped + (no camera change)"; the apply toast says which and why. + Walking the MERGED list (not comparing to the previous array element) is the + point: the duplicate only exists once the auto cuts are in — 4.5:cam2 is a + perfectly good cut in the file as saved, and only becomes a no-op because + auto-cut puts cam2 at 1.4161. +TEST: +3 cases (`timeline_test.mjs:566-598`): a cut that changes the angle is kept + (unchanged behaviour, still asserted), a cut duplicating the incoming auto camera + is dropped and ONE undo restores it with everything else, and a mixed pair + (2.0:camA redundant after the 1.4161 auto camA / 6.0:camA real after the 5.1654 + auto camB) drops exactly one and keeps exactly one. Also asserts the final list + has no consecutive camera repeat AT ALL, which is the property that was missing. + Replayed the orchestrator's own case on `scenes/music-video.json`: file cuts + `0:cam1, 4.5:cam2` → auto-cut cadence 2 → `0:cam1 1.42:cam2 5.17:cam3 8.91:cam4 + 12.66:cam1`, the 4.5 no-op gone, no repeats, one undo byte-identical to the file. + `node scenegod/web/timeline_test.mjs` green; `node --check` clean on all four. +DECISIONS: + - The drop is limited to cuts INSIDE the placed range and only when the camera is + genuinely unchanged. A user cut before the first or after the last placed cut is + still never touched — auto-cut has no business outside its own range. + - Noted for whoever picks up `♪ align`: the "name the grid source in the status + line" pattern is endorsed by the orchestrator; shot lists can in principle span + scenes with different grids, and saying which one was used is the honest answer + rather than silently picking. Keep that pattern for anything similar. +BLOCKED/REQUESTS: unchanged from session 8. +NEXT: unchanged from session 8 (nudge-to-grid, box-select beyond keys, per-drag undo + coalesce, film-level audio[] UI). diff --git a/scenegod-8020.log b/scenegod-8020.log index b918d4d..43054f3 100644 --- a/scenegod-8020.log +++ b/scenegod-8020.log @@ -1773,3 +1773,401 @@ INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/82 HTTP/1.1" 200 OK INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/83 HTTP/1.1" 200 OK INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/84 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/85 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/86 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/87 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/88 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/89 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/90 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/91 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/92 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/93 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/94 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/95 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/96 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/97 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/98 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/99 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/100 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/101 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/102 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/103 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/104 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/105 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/106 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/107 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/108 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/109 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/110 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/111 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/112 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/113 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/114 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/115 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/116 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/117 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/118 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/119 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/120 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/121 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/122 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/123 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/124 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/125 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/126 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/127 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/128 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/129 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/130 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/131 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/132 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/133 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/134 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/135 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/136 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/137 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/138 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/139 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/140 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/141 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/142 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/143 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/144 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/145 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/146 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/147 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/148 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/149 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/150 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/151 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/152 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/153 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/154 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/155 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/156 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/157 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/158 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/159 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/160 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/161 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/162 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/163 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/164 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/165 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/166 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/167 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/168 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/169 HTTP/1.1" 200 OK +INFO: 127.0.0.1:60355 - "GET /web/timeline.js HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/170 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/171 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/172 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/173 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/174 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/175 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/176 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/177 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/178 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/179 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/180 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/181 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/182 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/183 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/184 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/185 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/186 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/187 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/188 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/189 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/190 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/191 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/192 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/193 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/194 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/195 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/196 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/197 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/198 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/199 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/200 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/201 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/202 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/203 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/204 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/205 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/206 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/207 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/208 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/209 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/210 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/211 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/212 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/213 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/214 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/215 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/216 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/217 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/218 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/219 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/220 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/221 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/222 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/223 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/224 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/225 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/226 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/227 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/228 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/229 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/230 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/231 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/232 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/233 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/234 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/235 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/236 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/237 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/238 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/239 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/240 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/241 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/242 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/243 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/244 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/245 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/246 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/247 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/248 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/249 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/250 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/251 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/252 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/253 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/254 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/255 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/256 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/257 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/258 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/259 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/260 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/261 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/262 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/263 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/264 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/265 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/266 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/267 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/268 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/269 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/270 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/271 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/272 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/273 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/274 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/275 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/276 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/277 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/278 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/279 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/280 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/281 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/282 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/283 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/284 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/285 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/286 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/287 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/288 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/289 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/290 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/291 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/292 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/293 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/294 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/295 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/296 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/297 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/298 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/299 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/300 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/301 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/302 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/303 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/304 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/305 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/306 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/307 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/308 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/309 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/310 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/311 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/312 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/313 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/314 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/315 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/316 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/317 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/318 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/319 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/320 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/321 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/322 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/323 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/324 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/325 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/326 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/327 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/328 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/329 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/330 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/331 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/332 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/333 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/334 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/335 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/336 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/337 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/338 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/339 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/340 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/341 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/342 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/343 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/344 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/345 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/346 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/347 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/348 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/349 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/350 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/351 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/352 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/353 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/354 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/355 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/356 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/357 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/358 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/359 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/360 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/361 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/362 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/363 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/364 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/365 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/366 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/367 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/368 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/369 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/370 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/371 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/372 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/373 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/374 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/375 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/376 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/377 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/378 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/379 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/380 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/381 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/382 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/383 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/384 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/385 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/386 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/387 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/388 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/389 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/390 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/391 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/392 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/393 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/394 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/395 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/396 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/397 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/398 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/399 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/400 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/401 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/402 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/403 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/404 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/405 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/406 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/407 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/408 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/409 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/410 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/411 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/412 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/413 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/414 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/415 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/416 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/417 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/418 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/419 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/420 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/421 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/422 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/423 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/424 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/425 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/426 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/427 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/428 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/429 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/430 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/431 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/432 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/433 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/434 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/435 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/436 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/437 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/438 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/439 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/440 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/441 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/442 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/443 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/444 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/445 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/446 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/447 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/448 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/449 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/450 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/451 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/452 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/453 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/454 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/455 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/456 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/457 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/458 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/459 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/460 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/461 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/462 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/463 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/464 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/465 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/466 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/467 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/468 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/469 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/470 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/471 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/472 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/473 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/474 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/475 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/476 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/477 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/478 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/frame/479 HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "POST /render/ea9cb4e30f8744b7b3a8ba2534baa0df/end HTTP/1.1" 200 OK +INFO: 127.0.0.1:59773 - "GET /render/ea9cb4e30f8744b7b3a8ba2534baa0df/status HTTP/1.1" 200 OK diff --git a/scenegod/web/timeline.js b/scenegod/web/timeline.js index 995825e..45ff47b 100644 --- a/scenegod/web/timeline.js +++ b/scenegod/web/timeline.js @@ -669,14 +669,29 @@ export class Timeline { // so a hand-placed cut near the downbeat is absorbed rather than duplicated // into a flash frame). Cuts elsewhere in the range are left alone. const replaced = this.cameraCuts.filter((c) => times.some((t) => Math.abs(c.t - t) <= eps)); - // Hand-placed cuts elsewhere in the range are NOT touched (deleting someone's - // edit is over-reach) — but they interleave, and one of them can repeat a - // camera. Report them so the popover can say so instead of the user - // wondering why a beat-perfect edit has a stutter in it. - const kept = this.cameraCuts.filter((c) => c.t >= times[0] && c.t <= times[times.length - 1] - && !replaced.includes(c) && !times.some((t) => Math.abs(c.t - t) <= eps)); + // Hand-placed cuts elsewhere in the range are NOT touched — deleting someone's + // edit is over-reach — with ONE exception (SYNC13, orchestrator): a kept cut + // that selects the camera already live at that instant is a literal no-op. It + // cuts from cam2 to cam2, nothing happens on screen, and it still rides into + // the saved scene looking like an edit. Those are dropped; the rest are + // reported as `kept` so the popover can own the interleave out loud. + // The "already live" camera is the EFFECTIVE one after the auto cuts are + // merged in, so walk the merged list in time order rather than comparing + // against the previous array element. + const survivors = this.cameraCuts.filter((c) => !replaced.includes(c)); + const merged = [...survivors.map((c) => ({ c, auto: false })), ...cuts.map((c) => ({ c, auto: true }))] + .sort((a, b) => a.c.t - b.c.t); + const kept = [], dropped = []; + let eff = null; + for (const m of merged) { + if (!m.auto && m.c.t >= times[0] && m.c.t <= times[times.length - 1]) { + if (m.c.camera === eff) { dropped.push(m.c); continue; } // cuts from X to X = nothing + kept.push(m.c); + } + eff = m.c.camera; + } return { - ok: true, cuts, replaced, kept, cameras: cams, cadence, + ok: true, cuts, replaced, kept, dropped, cameras: cams, cadence, barPeriod: this._beatPeriod('bar'), confidence: g.confidence ?? 0, bpm: g.bpm, from, to, }; @@ -689,6 +704,7 @@ export class Timeline { if (!plan.ok) throw new Error(plan.error); this.group(() => { for (const c of plan.replaced) this.removeCut(c); + for (const c of plan.dropped) this.removeCut(c); // no-op cuts (cam X → cam X) for (const c of plan.cuts) this.addCut(c.t, c.camera); }); this.seek(this.time); // the new cut under the playhead goes live diff --git a/scenegod/web/timeline_test.mjs b/scenegod/web/timeline_test.mjs index 446a84e..5e0051f 100644 --- a/scenegod/web/timeline_test.mjs +++ b/scenegod/web/timeline_test.mjs @@ -586,11 +586,12 @@ assert.equal(tlAC.cameraCuts.filter((c) => Math.abs(c.t - bars[2]) < 1e-9).lengt tlAC.undo(); tlAC.undo(); assert.equal(tlAC.cameraCuts.length, 0, 'undo unwinds the replacement too'); -// a hand-placed cut BETWEEN downbeats is left alone — and disclosed, because it -// interleaves and can repeat a camera (the popover says so; we don't delete it) -tlAC.addCut(4.5, 'camB'); +// a hand-placed cut BETWEEN downbeats that GENUINELY changes the angle is left +// alone — and disclosed, because it interleaves with the beat cuts +tlAC.addCut(4.5, 'camB'); // cadence 2 puts camA at 1.4161 → this really cuts const pk = tlAC.autoCutPlan({ cadence: 2 }); -assert.equal(pk.kept.length, 1, 'an off-grid cut inside the range is reported as kept'); +assert.equal(pk.kept.length, 1, 'an off-grid cut that changes camera is reported as kept'); +assert.equal(pk.dropped.length, 0, 'and is not dropped'); assert.equal(pk.replaced.length, 0, 'and is NOT counted as a replacement'); tlAC.autoCut({ cadence: 2 }); assert.equal(tlAC.cameraCuts.length, 5, 'the user\'s own cut survives auto-cut (4 placed + 1 kept)'); @@ -598,6 +599,35 @@ assert.ok(tlAC.cameraCuts.some((c) => c.t === 4.5 && c.camera === 'camB'), 'exac tlAC.undo(); tlAC.undo(); assert.equal(tlAC.cameraCuts.length, 0, 'and both come back off'); +// SYNC13: a kept cut that selects the camera ALREADY LIVE is a no-op — it cuts +// camA→camA, nothing happens on screen, and it would ride into the saved scene +// looking like an edit. Drop it, and say so. +tlAC.addCut(4.5, 'camA'); // camA is live from the 1.4161 auto cut +const beforeDrop = structuredClone(tlAC.cameraCuts); +const pd = tlAC.autoCutPlan({ cadence: 2 }); +assert.equal(pd.dropped.length, 1, 'a no-op cut is reported as dropped'); +assert.equal(pd.kept.length, 0, 'and is not reported as kept'); +assert.equal(pd.dropped[0].t, 4.5, 'the right cut is named'); +tlAC.autoCut({ cadence: 2 }); +assert.equal(tlAC.cameraCuts.length, 4, 'the no-op cut is gone — only the 4 beat cuts remain'); +assert.ok(!tlAC.cameraCuts.some((c) => c.t === 4.5), 'specifically that one'); +assert.ok(tlAC.cameraCuts.every((c, i, a) => i === 0 || c.camera !== a[i - 1].camera), 'the final list has no camera repeat at all'); +tlAC.undo(); +assert.deepEqual(tlAC.cameraCuts, beforeDrop, 'ONE undo restores the dropped cut along with everything else'); +tlAC.undo(); +assert.equal(tlAC.cameraCuts.length, 0, 'and the manual cut comes off with the next undo'); + +// the effective camera is judged AFTER the auto cuts merge in, not against the +// previous array element: this cut duplicates a camera that only exists once +// auto-cut has run, and is still caught +tlAC.addCut(2.0, 'camA'); // 1.4161 auto = camA → 2.0 changes nothing +tlAC.addCut(6.0, 'camA'); // 5.1654 auto = camB → 6.0 IS a real cut +const pe = tlAC.autoCutPlan({ cadence: 2 }); +assert.deepEqual(pe.dropped.map((c) => c.t), [2.0], 'only the genuinely redundant one is dropped'); +assert.deepEqual(pe.kept.map((c) => c.t), [6.0], 'the one that changes the angle is kept'); +tlAC.undo(); tlAC.undo(); +assert.equal(tlAC.cameraCuts.length, 0, 'test cuts cleaned up'); + // range = from the playhead, and the camera already live doesn't repeat across it tlAC.seek(6); tlAC.addCut(0, 'camA'); // camA is live going into the range diff --git a/scenegod/web/tlui.js b/scenegod/web/tlui.js index 5e2f67d..8e87211 100644 --- a/scenegod/web/tlui.js +++ b/scenegod/web/tlui.js @@ -875,7 +875,8 @@ export class TimelineUI { cnt.textContent = `will place ${plan.cuts.length} cut${plan.cuts.length === 1 ? '' : 's'}` + (every > 0 ? ` · one every ${every.toFixed(2)}s` : '') + (plan.replaced.length ? ` · ${plan.replaced.length} existing replaced` : '') - + (plan.kept.length ? ` · ${plan.kept.length} of your own cut${plan.kept.length === 1 ? '' : 's'} left in place between them` : '') + + (plan.kept.length ? ` · ${plan.kept.length} of your cut${plan.kept.length === 1 ? '' : 's'} kept` : '') + + (plan.dropped.length ? ` · ${plan.dropped.length} dropped (no camera change)` : '') + (plan.confidence < 0.35 ? ` · LOW grid confidence (${plan.confidence.toFixed(2)})` : ''); }; menu.querySelector('.cad').onchange = refresh; @@ -890,6 +891,7 @@ export class TimelineUI { this.draw(); this._toast(`✂ ${plan.cuts.length} cuts on the downbeats · every ${plan.cadence} bar${plan.cadence === 1 ? '' : 's'}` + ` · ${plan.cameras.length} cameras cycling` + + (plan.dropped.length ? ` · dropped ${plan.dropped.length} no-op cut${plan.dropped.length === 1 ? '' : 's'} (cut to the camera already live)` : '') + (plan.confidence < 0.35 ? ` · LOW grid confidence (${plan.confidence.toFixed(2)}) — check it against the music` : '') + ' · Cmd/Ctrl+Z undoes the lot'); };