feat(editor): Settings > Appearance gets "Show timeline on hover"

Off by default. On, the timeline sits as a strip — its header, so the title,
transport and Composer stay reachable — and opens to full height while the
pointer is on it or something inside it has focus.

It also opens for the whole of a DRAG. During one the pointer is in drag mode
and a strip that stays shut is a drop target you cannot hit, so dragenter holds
it open and drop/dragend closes it. The tracker counts depth rather than
holding a boolean: dragleave for the element being left fires AFTER dragenter
for the one being entered, so a flag closes the strip mid-drag as the pointer
crosses from one clip to the next.

The strip height is MEASURED from the header rather than fixed: .zone-head
wraps when the zone is narrow (34px min-height, 138px on a normal window), so
any constant clips the very controls the strip exists to keep visible. It is
re-measured on resize. flex: 0 0 auto matters — .zone is a shrinkable column
child, and a height with min-height: 0 let the workspace squeeze the strip to
1px. The body collapses rather than being display:none so the lanes are not
torn down and rebuilt on every open.

A browser preference like the colour scheme, not a project one, and registered
in the same Settings section for that reason.

Also in this commit:
- vf: train wherever there is a GPU, not only when the sample sits on one. The
  x0 value function's snapshot loads with map_location="cpu", so keying on the
  sample left it training on the CPU — the run that named it measured
  "x0 vf: train 10.1s" against 46ms for the same net locally.
- The stage line counted nested sub-stages twice and reported 153% of a run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
digital-garbage
2026-08-25 14:32:11 +03:00
co-authored by Claude Opus 5
parent a689aaa87d
commit 8cdee7072f
9 changed files with 325 additions and 4 deletions
+16
View File
@@ -74,3 +74,19 @@ def test_the_latent_value_function_inherits_the_same_path():
vf.buffer_r.append(float(i % 2))
vf.train_on(torch.randn(1, 1, 4096), 0.7)
assert vf.n_trained == 1
def test_a_cpu_snapshot_still_goes_to_the_gpu(monkeypatch):
"""The x0 value function's sample is loaded with map_location="cpu". Keying the device on
the sample left it training on the CPU — 10.1s a run against 46ms for the same net."""
import value_function as V
monkeypatch.setattr(V.torch.cuda, "is_available", lambda: True)
home = torch.device("cpu")
assert V.OnlineValueFunction._training_device(torch.zeros(4), home) == torch.device("cuda")
def test_without_a_gpu_it_stays_home(monkeypatch):
import value_function as V
monkeypatch.setattr(V.torch.cuda, "is_available", lambda: False)
home = torch.device("cpu")
assert V.OnlineValueFunction._training_device(torch.zeros(4), home) is home