# Cold construction and pan alternatives Follow-up to [the stationary-camera cache](README.md), for issue 44. Application source remains `336720559bcec511949caa8a42bee8a55c3822da`, with evidence checkpoint `2ca84676ee4dc30846208881a27d90a901482085`. These standalone experiments change no application code, dependencies, event handling or release. Native interaction remains paused; no result below establishes native FPS. ## Question and method The existing cache removes repeated construction at identical camera inputs but misses during pan/zoom. Can simpler geometry or renderer-level translation remove that cost without changing the grid's appearance? Use the same unoptimized Iced 0.14 WGPU dependencies and Windows environment recorded in `context.json`. Compile the new drivers with the same `rustc`/extern/linker arguments described in README, replacing the driver filename and output executable. No desktop window is created and no input is sent. Run `cold_grid_probe` with argument `20`; phase drivers take no arguments. The cold driver compares original circles, one reusable origin circle transformed for each fill, one path per column, and direct 1.15-unit squares. Every candidate also constructs one origin-circle template; this small common overhead is retained. Three warmups precede 20 changing-pan samples. Construction ends before geometry destruction, rendering and readback. Percentiles use sorted index `ceil((n-1)*p)`. Fixed candidate ordering and uncontrolled OS load limit small timing comparisons. ## Cold construction results `cold_grid_probe.rs` produces `grid-cold-01.log`. Median milliseconds: | Canvas, zoom | Original | Reused circle | Column batch | Square | | --- | ---: | ---: | ---: | ---: | | 1900x660, 1.0 | 61.0564 | 55.3975 | 54.3594 | 3.5527 | | 1900x660, 0.5 | 215.8919 | 162.3073 | 158.5968 | 7.5699 | | 1440x900, 1.0 | 60.1683 | 43.3860 | 60.8198 | 2.0340 | | 1440x900, 0.5 | 165.2049 | 133.3420 | 143.1489 | 6.8178 | Both circle alternatives exactly match original pixels in all 12 sampled cases (four integer canvas/zoom pairs, three pan offsets, scale 1). This does not prove equivalence at fractional zoom, other DPI or other camera inputs. Squares match eight of those cases but differ at the third pan offset in each canvas/zoom pair: 4,266–13,184 changed pixels, maximum channel difference 7. Their different shape and area are an explicit appearance change, not a pixel-preserving optimization. Reusing circles and column batches leave substantial cold cost; the experiment does not justify adding them to production as the solution to low FPS. The square alternative is much faster in this scope, but is not adopted without evaluating its appearance and the actual interaction result. The previous all-grid single path experiment remains rejected for its much higher construction cost. ## Source explanation and independent review A fresh read-only critic checked the probes and actual local Iced source. Each `Path::circle` allocates/builds a path and converts its arc into quadratic segments. Each WGPU `Frame::fill` allocates a boxed geometry builder and invokes Lyon fill tessellation. Same-color fills already share a solid mesh buffer: this is not one GPU draw call per dot. Frame translation transforms paths before tessellation, so path reuse alone does not reuse triangles. Renderer-level `with_translation` can reuse cached triangles. Stock Canvas cannot attach a separate transform to each returned geometry; application adoption would need a small background widget or wrapper, with layout, clipping, lifecycle and interaction checks. Scaling the grid to handle zoom is unsuitable because the dot radius must remain fixed in screen units. The critic also identified two important controls. Original opaque background geometry must not silently become screenshot-clear color: MSAA/alpha composition can change quantized pixels. Also, `iced_wgpu::triangle::Storage::prepare` rewrites cached mesh data when its transform changes. Construction/command-recording time therefore excludes real preparation/upload costs. The later probe measures a rendering/readback path separately; neither timer represents native presentation. Primary sources: Iced 0.14 `iced_graphics/src/geometry/path{,/builder}.rs`, `iced_wgpu/src/{geometry,triangle}.rs`, `iced_core/src/renderer.rs`, and `iced_widget/src/canvas.rs`. The reviewer changed no files and did not execute the probes; execution and interpretation remain the parent's responsibility. ## Renderer-translated phase cache `phase_grid_probe_v1.rs` / `grid-phase-01.log` cache zero-phase circles once for each size/spacing pair, translate by `pan.rem_euclid(step)`, and externally clip to the original viewport. The original nonnegative row/column indices and fixed screen-space radius are retained. Cache clip bounds include the radius margins. This first prototype uses screenshot clear color instead of opaque background geometry; its widespread one-level pixel differences are not accepted as parity. Its compiler emitted one duplicate Renderer-import warning, retained in the original driver. Later drivers remove that import and compile with `-D warnings`. `phase_grid_opaque_probe.rs` / `grid-phase-opaque-01.log` add an oversized opaque background to the same cached geometry as the circles. Its bounds extend from `(-step,-step)` to `(width+2*step,height+2*step)`, covering the viewport at every positive remainder without adding extra dot rows or columns. This directly compares against the unchanged legacy painter. A proposed separate-background control was not executed; no result is claimed for it. Of 75 comparisons (five size/zoom pairs, five offsets, three DPI scales), 73 are byte-exact. All 60 cases at integer canvas sizes and spacing 14 or 24 are exact. At 301.5x211.25, zoom 0.73, pan (-13.25,9.75), scale 1 changes 12 pixels by at most one channel level; scale 2 changes one pixel by at most six levels. These are failures of exact parity and are preserved, not hidden behind a tolerance. The targeted `phase_grid_diagnostic.rs` / `grid-phase-diagnostic-01.log` locates all 12 scale-1 differences at the rightmost physical column x=301. The scale-2 single-pixel difference does not recur. That diagnostic skips earlier large cases and their rendering/timing sequence: it does not exonerate the earlier failure or establish that every residual difference is at an edge. The replay driver's first compilation failed with E0689 because the new control's `Vector::new(-13.25,9.75)` left its numeric type ambiguous before `rem_euclid`. An explicit `Vector` annotation corrects the experiment harness. No probe executed during that failed attempt; no application source changed. `phase_grid_replay.rs` preserves the full opaque probe's rendering/timing sequence and adds coordinate diagnostics without extra renders until that sequence ends. `grid-phase-replay-01.log` reproduces both failures: the 12 right-edge pixels and one **interior** pixel at physical (149,263), where legacy RGBA is `[240,243,246,255]` and cached RGBA is `[246,248,251,255]`. The latter cannot be dismissed as viewport-edge rounding. Afterwards, all 12 same-renderer repeat controls (three repetitions of old/old and cached/cached at two scales) are byte-exact; the control cache builds once. This finite control does not establish universal determinism, but supports investigating differing geometry coverage instead of treating the reproduced pixel as random readback noise. Cold construction plus command recording takes 68.42–173.72ms median for the four large viewports; cached translation takes 0.0008–0.0011ms. Each per-size/spacing cache builds exactly once through all pan comparisons and measurements. Zoom and resize through a single retained cache are not tested by these drivers. The labels containing `submit` mean renderer command recording, not GPU submission. Two selected cases include construction, recording, backend preparation and GPU readback in a separate timer (two warmups, eight samples, sorted-index median): | Canvas, zoom | Original p50 ms | Phase cache p50 ms | | --- | ---: | ---: | | 1900x660, 1.0 | 259.9265 | 212.6536 | | 1440x900, 0.5 | 337.2560 | 170.3780 | These support a benefit within the headless path, but retain significant renderer and readback cost and variable outliers. They are not native frame times. Sample size, sequential ordering and uncontrolled machine load prohibit a precise general speedup claim. All driver/log hashes and execution mapping are in `cold-pan-context.json`. The phase candidate removes the measured pan tessellation cost, but does not meet exact visual preservation. Do not adopt it as an invisible optimization. The small circle rewrites leave the main cost and squares change appearance. Further work should investigate the reproduced interior coverage difference or compare optimized dependency/build profiles before adding a custom widget. Any adopted rendering candidate must then verify a real mounted scene at a nonzero widget origin, foreground ordering, viewport clipping, pan/zoom/resize cache lifecycle and unchanged event behavior. Native interaction/FPS verification remains a separate required gate. No application implementation is changed by these experiments.