diff --git a/src/players.jl b/src/players.jl
index f805cf91b922e61d7bd765e922ab158bfcfc035b..ff1f5fd5ae8ed5fa98a213c2aee584ace3fc1903 100644
--- a/src/players.jl
+++ b/src/players.jl
@@ -158,6 +158,7 @@ function timecontroller(times::Vector{Float64}; speed=1.0)
     stepmin = Observable(1)
     stepmax = Observable(nsteps)
     boundreached = Observable(true)
+    initialized = Ref(false) # useful for skipping a "Time bound reached" message at startup
     #
     on(timestep) do step
         min, max = stepmin[], stepmax[]
@@ -177,7 +178,8 @@ function timecontroller(times::Vector{Float64}; speed=1.0)
         end
     end
     on(boundreached) do b
-        b && @info "Time bound reached"
+        b && initialized[] && @info "Time bound reached"
+        initialized[] = true
     end
     on(stepmin) do bound
         0 < bound || throw(DomainError("stepmin < 1"))
diff --git a/src/plots.jl b/src/plots.jl
index 8832675f03b019b6a85f25d51b5769e048b8b4f7..0364c82020fdb99104df2c9c5f37025810f5b481 100644
--- a/src/plots.jl
+++ b/src/plots.jl
@@ -528,13 +528,7 @@ function Makie.plot!(plot::LarvaPlot{Tuple{DecoratedLarva}})
     # decoration
     p = Makie.Point2f ∘ coordinates
     outline = p.(Vector(vertices(decoratedlarva.activearea)))
-    # TODO: design a more systematic way to prevent path closing of spine, i.e. when outline
-    # data is not available and `outline` is actually a spine
-    close!(path) = if 7 < length(path)
-        push!(path, path[1])
-    else
-        path
-    end
+    close!(path) = push!(path, path[1])
     lines!(plot, close!(outline);
            color=theme[:DecoratedLarva][:hover_color],
            linewidth=theme[:DecoratedLarva][:hover_linewidth],
@@ -599,7 +593,7 @@ function DecoratedLarvae(larvae::Vector{DecoratedLarva})
             else
                 @error begin
                     j_id = larvae[j].larva.model.id
-                    "cannot decorate invisible larva #$(j_id) - please file an issue at https://gitlab.pasteur.fr/nyx/larvatagger.jl/-/issues"
+                    "Cannot decorate invisible larva #$(j_id)"
                 end
                 hovered_larva.val = 0
             end
diff --git a/src/wgl.jl b/src/wgl.jl
index c9cad2c70a4623d433ca57ff2afb8b4ac616f8d9..009c01e686342a8b0c6d9cf5baece2784312b3d7 100644
--- a/src/wgl.jl
+++ b/src/wgl.jl
@@ -118,6 +118,7 @@ struct AssayPlot
 end
 
 function AssayPlot(ctrl, larvae::DecoratedLarvae; size=FIGSIZE)
+    gethub(ctrl)[:decoratedlarvae] = larvae
     fig = Figure(resolution=size)
     width = 0.1f0 # try to get 1px
     color = RGBAf(0, 0, 0, 0.36)
@@ -448,14 +449,41 @@ end
 struct LarvaInfo
     controller
     id::LarvaID
+    hovered::AbstractObservable{Bool}
     reviewed::AbstractObservable{Bool}
     edited::AbstractObservable{Bool}
     included::AbstractObservable{Bool}
 end
 
 function larvainfo(controller, id)
+    hovered = Observable(false)
     reviewed = Observable(false)
     edited = Observable(false)
+    #
+    larvae = gethub(controller)[:decoratedlarvae]
+    larvaindex = nothing
+    for (i, larva) in enumerate(larvae.larvae)
+        larva = larva.larva
+        if larva.model.id == id
+            larvaindex = i
+        end
+    end
+    larvavisible = larvae.larvae[larvaindex].larva.visible
+    on(hovered) do b
+        if larvae.hovering_active[]
+            if b
+                if larvavisible[]
+                    larvae.hovered_larva[] = larvaindex
+                end
+            else
+                i = larvae.hovered_larva[]
+                if i != 0
+                    i == larvaindex || @warn "Larva #$(larvae.larvae[i].larva.model.id) unexpectedly decorated"
+                    larvae.hovered_larva[] = 0
+                end
+            end
+        end
+    end
     on(edited) do b
         if b
             #@assert reviewed[]
@@ -474,6 +502,7 @@ function larvainfo(controller, id)
     included = Observable(false)
     LarvaInfo(controller,
               id,
+              hovered,
               reviewed,
               edited,
               included)
@@ -482,7 +511,9 @@ end
 JSServe.jsrender(session::Session, li::LarvaInfo) = r(session, prerender(li))
 
 function prerender(li::LarvaInfo)
-    label = "#$(li.id)"
+    label = DOM.label("#$(li.id)",
+                      onmouseenter=js"JSServe.update_obs($(li.hovered), true)",
+                      onmouseleave=js"JSServe.update_obs($(li.hovered), false)")
     discard_larva_edits = js"LarvaTagger.discardLarvaEdits(this, $(li.edited), $label)"
     reviewed_checkbox = DOM.input(type="checkbox",
                                   checked=li.reviewed,