74dc80fd3bd2a70371fa75218347ddc45a556dde braney Wed Aug 5 07:28:59 2026 -0700 Docent: render a tour at print resolution, and make zoom wait for its redraw refs #37892 scale: k (DOCENT_SCALE=k, make hires [SCALE=3]) renders the same tour with k times the pixels, for figures that have to print -- a screen still is about 120 dpi across a journal column. Nothing is upscaled; each layer that draws is asked for more: * deviceScaleFactor: k with the viewport left at its 1x CSS size, so the page lays out exactly as at 1x -- same line breaks, same jQuery-dialog width, same tooltip placement -- and rasterizes with k times the pixels, * pix x k so the server draws a wider browser image, with textSize stepped up its ladder to match (3x lands on 24) so hgTracks makes the same layout decisions in it: same tick spacing, same room for labels, same packing of features into rows, * zoom: 1/k on the image table, handing that wider image the 1x amount of layout space, so one image pixel falls on one device pixel. A scaled run is stills-only (no mp4), and DOCENT_STILLS names a different parent so a print render lands beside the screen stills instead of over them. Everything hgTracks reports about the image -- map-box coords, mouseOver spans, insideX, a px: drag endpoint -- is in the pixels the SERVER drew, which is not the displayed size once the image is scaled. Those now go through the image's natural-to-displayed ratio (1 at 1x). Without it a named mouseover: lands k times off and pins a different feature. zoom: in|out waited only for #imgTbl, which the buttons never remove (they redraw in place via ajax), so the following step could read the previous window's map boxes and report an item "not found" that was simply not in view yet. It now waits for the window itself to change. Pre-existing, hidden by the dwell that FAST removes -- and every hires run is FAST. An item-not-found error also names the current window and the items that ARE in that row, which is what told the two cases apart. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> diff --git src/hg/utils/docent/docent.mk src/hg/utils/docent/docent.mk index dfd6ef68d86..7925bf6c2d7 100644 --- src/hg/utils/docent/docent.mk +++ src/hg/utils/docent/docent.mk @@ -26,31 +26,49 @@ DOCENT ?= $(HOME)/kent/src/hg/utils/docent/docent.js SCRIPTS ?= $(wildcard *.docent.yaml) BASES ?= $(SCRIPTS:.docent.yaml=) FIGDIR ?= .. MP4S := $(addprefix $(FIGDIR)/,$(addsuffix .mp4,$(BASES))) # Shared Playwright/Chromium install. Anywhere you have playwright + js-yaml works; # at UCSC this is the ~/pwrec tree. PW_ENV ?= PLAYWRIGHT_BROWSERS_PATH=$(HOME)/pwrec/browsers NODE_PATH=$(HOME)/pwrec/node_modules # FAST=1 -> figures only: no dwells, no cursor animation, no screen recording, no mp4. # Same stills, about a third of the wall clock. Use it while iterating on figure content; # drop it for the final build that has to produce the videos. FAST_ENV = $(if $(FAST),DOCENT_FAST=1 ,) -.PHONY: all list clean $(BASES) +.PHONY: all list clean hires $(BASES) all: $(MP4S) $(FIGDIR)/%.mp4: %.docent.yaml $(DOCENT) $(FAST_ENV)$(PW_ENV) node $(DOCENT) $< +# hires: the same tours rendered for print -- SCALE times the pixels (a wider server image +# drawn with a bigger track font, the HTML zoomed to match), stills only, written to their +# own tree so the screen stills and the videos are left alone. Always a full rebuild: a +# print run is rare and cheap to ask for exactly when it is wanted. +# +# make hires # every scenario at 3x -> stills.hires/<base>/ +# make hires SCALE=2 # 2x +# make hires BASES=BP1 # one scenario +# +SCALE ?= 3 +HIRES ?= stills.hires +hires: + @for b in $(BASES); do \ + echo "=== $$b at $(SCALE)x"; \ + DOCENT_SCALE=$(SCALE) DOCENT_STILLS=$(HIRES) DOCENT_FAST=1 $(PW_ENV) \ + node $(DOCENT) $$b.docent.yaml || exit 1; \ + done + # Convenience: `make AP1` -> build ../AP1.mp4 $(BASES): %: $(FIGDIR)/%.mp4 list: @echo $(BASES) clean: rm -f $(MP4S) - rm -rf stills + rm -rf stills $(HIRES)