Log set_view_end and progressive tile/region walk timings to the console
so post-zoom ViewportReady cost can be broken down while tuning the
paint-once path. Remove before merging to develop.
Size Current and layer surfaces to the viewport plus interest pad on
window resize, walk each uncached batch once, and GPU-crop 512 tiles
into the atlases so post-zoom HQ avoids re-walking the tree per tile.
Soft-flush the GPU during paint-region batches so Partial submit does
not stall on a full command backlog.
Allow clip, frames, non-identity transforms, and SrcOver opacity on the
Current-surface fast path; early-out drop-shadow composite when a shape
has no visible shadows and warm DropShadows once per tile instead.
Pass performance.now from finalize/debounce and re-anchor the WASM
budget if the stamp is 0 or already past max_blocking_time, so HQ
tiles are not yielded after a few nodes with almost no real work.
Copy Current into DocAtlas and the tile atlas with Surface::draw
instead of image_snapshot_with_bounds, matching the interactive
path and removing a GPU sync stall on every completed tile.
render_from_cache composites DocAtlas and tile-atlas textures, not
the Cache surface. Stop clearing and filling Cache per completed
tile to avoid wasted full-tile GPU copies during progressive render.
Defer the interest-ring until visible tiles are done, present via
FrameType::ViewportReady, then fill interest on later Partial frames
so large files show the viewport without waiting on off-screen work.
Skipping DropShadows→Current entirely made flush_and_submit very
slow due to Skia ops-task ordering, but doing that empty blit on
every shape was wasted GPU work. Touch it once per tile when
shadows are skipped, and drop the redundant DropShadows clear.
Marking intermediate surfaces dirty after clearing them on tile
context switch made the first stack composite blit empty
Fills/Strokes/shadows into Current. Dirty means content to
composite, so clear the flags after the clear instead.
Partial frames only flushed the Backbuffer, so tile GPU commands
queued until present_frame's flush_and_submit and stalled the
browser on large files. Submit the context each partial frame
without presenting Target or re-composing the tile atlas.
Remove the guard in stop-devenv that refused to stop ws0 while any
ws1+ instance was running. Each workspace is now fully independent
and can be started/stopped in any order. Shared infra shuts down
only when no instances remain running.
Updated docs (devenv.md, agentic-devenv.md) and devenv memory to
reflect the new behavior.
AI-assisted-by: mimo-v2.5-pro
Never pipe test output directly to filters (head, tail, grep).
Always redirect to a file first to prevent hiding test failures.
AI-assisted-by: mimo-v2.5
Move Dockerfile.frontend, .backend, .exporter, .mcp and .storybook
under docker/images/ from ubuntu:26.04 / nginx-unprivileged / a
manual Node tarball install to Docker Hardened Images (Debian 13,
or Alpine for storybook). storybook and mcp get a true non-dev
runtime; frontend, backend and exporter keep the -dev tag as their
final image, since each needs a shell and/or package manager at
container runtime (nginx templating, fontforge/python3, and a
headless-browser stack, respectively).
Move docker/imagemagick/Dockerfile and docker/devenv/Dockerfile from
ubuntu:26.04 to Docker Hardened Images (Debian 13 / trixie).
imagemagick gets a true non-dev runtime with its shared libraries
vendored via ldd; devenv keeps the -dev tag as its final image since
it's an interactive development container, not a production
artifact.