# Window Animations Plan This document is the working plan for Wry's window animation system. It records the decisions already made, the implementation phases, and the risks that must be handled deliberately. ## Accepted Decisions - The first landed slice is linear interpolation only, disabled by default. - Animation is presentation-only. Logical layout, input hit testing, focus, and Wayland configure state use final geometry immediately. - Pointer drag and resize initiated by the mouse or tablet do not animate. - Linear animations restart only for windows whose destination changes. Other in-flight windows keep their existing timelines. - Spawn-in uses scale and position. Spawn-out requires retained visual content and is deferred until the freezing layer exists. - Command-driven tile-to-float and float-to-tile transitions may animate. Protocol drag/drop paths do not. - The no-overlap multiphase system is a separate phase after the linear path is working and testable. - Content freezing will use retained per-surface texture references, not a full offscreen snapshot as the default design. - The multiphase animation concept is original to Wry. Hy3 is relevant only as partial inspiration for tiling style and titlebar/grouping behavior. - Mono mode should mostly avoid animations. Exceptions are windows entering or exiting mono mode, where a visual transition can clarify the hierarchy change. ## Texture Freezing Decision The approved freezing design is to capture a renderable surface tree at animation start: - texture references - source sample rects - target sizes - alpha and color metadata - subsurface offsets and stacking order - enough synchronization/release state to keep referenced buffers alive safely This is lighter than rendering every toplevel into a compositor-owned offscreen texture, and it should handle normal GPU-backed windows without an extra full window copy. It also gives spawn-out a path: capture the surface tree before the toplevel is logically destroyed, then animate the retained records after the live node is gone. Tradeoffs: - Retained references can delay buffer release. For dmabuf clients this can increase memory pressure or throttle clients if many large windows animate. - SHM buffers still matter for simple clients, fallback paths, some utilities, and cursor-like surfaces. They are probably not the common case for large app windows, but the implementation must still treat SHM texture flipping as a correctness issue. - The release/sync contract must be explicit. A retained texture must not be released back to the client while the compositor may still render it. - True offscreen snapshots remain a possible fallback for cases where retained references cannot safely preserve the rendered content. ## Phase 1: Linear Presentation Animations Goal: add the smallest correct animation layer without changing layout semantics. Implementation shape: - Add animation state owned by `State`. - Track per-toplevel animation entries keyed by `NodeId`. - Store logical target rect, current presentation rect, previous damaged rect, start time, duration, and curve. - On command-driven tiled layout geometry changes, animate from current presentation rect to new final rect. - On interruption, restart only the affected window from its current presentation rect. - Drive frames from the existing output latch/presentation event flow. - Damage the union of previous presentation rect, current presentation rect, and final logical rect. Initial scope: - Tiled reflow animation. - Floating command-driven moves, tile-to-float, float-to-tile, and spawn-in are deferred until after tiled reflow is validated. - Cross-output and cross-scale movements snap for now. - Linear mode may overlap windows during swaps. That is expected for the classic interpolation mode; no-overlap is Phase 3. - Live client buffers are rendered in Phase 1. Retained content freezing is deferred, but animated windows must still be clipped to their presentation bounds and must preserve the existing stretch behavior for undersized contents. - No spawn-out. - No content freezing. - No multiphase no-overlap planner. Tests: - rect interpolation is direction-independent - interruption restarts only changed windows - unchanged in-flight windows keep their original timeline - drag-driven floating movement bypasses animation - damage includes old, current, and final rects ## Phase 2: Retained Texture Freezing Goal: freeze visual contents during movement and enable spawn-out. Implementation shape: - Add a retained render-record tree for toplevel surfaces. - Capture records before movement animations that require freezing. - Capture records before destroy/unmap for spawn-out. - Render retained records through the normal renderer primitives where possible. - Extend event/sync handling so retained buffers remain valid until the animation is complete. Open design work: - Exact lifetime model for retained `SurfaceBuffer` / `GfxTexture` references. - Whether retained records participate in frame callbacks or presentation feedback. Default assumption: no, because they are compositor animation frames, not client commits. - How to fall back when a buffer cannot be safely retained. ## Phase 3: Multiphase No-Overlap Animations Goal: implement Wry's staged no-overlap planner while preserving the rule that windows never overlap. Core rules: - Each phase is a discrete animation using the full curve. - A phase performs only one action kind per window: move or scale. - Movement and scaling are split by axis. - No diagonal motion. - A window or synchronized group owns its own timeline. - New layout changes interrupt only windows/groups with changed destinations. - Current hierarchy and target hierarchy both matter. The planner must know whether a window is ascending toward a higher-level/toplevel position, descending into a container, or moving between containers at the same depth. - If some child windows require fewer phases than their parent/container context, parent/container-space changes generally happen first so space exists before the child moves into it. This rule can be overridden only when the non-overlap invariant still clearly holds. - Windows that become peers in the target hierarchy may synchronize later phases even if they were not peers in the source hierarchy. Important parent/child synchronization issue: The planner must not let a parent container and child window animate independent axes at the same time in a way that violates the visual rules. For example, a parent scaling horizontally while a child scales vertically can accidentally produce a diagonal or multi-axis motion in screen space. Preferred approach: - Plan in terms of leaf toplevel visual rectangles first. - Treat containers as constraints and grouping boundaries, not as independently animated visual actors. - Derive every leaf's per-phase rect from one phase schedule so parent and child effects cannot compose into forbidden motion. - Add container-level grouping only after the leaf planner proves correct. - Include hierarchy-transition metadata in the planner input: source parent, target parent, source depth, target depth, and whether the window is ascending, descending, or staying at the same hierarchy level. - For mono containers, suppress ordinary in-mono focus/tab changes. Animate only transitions into mono, out of mono, or across the mono boundary. Tests: - horizontal swaps shrink, move, then grow without overlap - extraction from a stack creates space before moving the extracted window - nested containers do not produce simultaneous cross-axis motion - interruption restarts only affected phase groups - reversing direction produces equivalent motion in reverse - child waits for parent/container-space phases when moving upward into a toplevel peer position - mono-mode tab switches do not animate, while entering/exiting mono can animate ## Configuration Phase 1 should expose a disabled-by-default setting for: - enabled/disabled - duration - curve preset or cubic bezier Initial TOML shape: ```toml [animations] enabled = false duration-ms = 160 curve = "ease-out" ``` Bezier curves should be analyzed at configuration time and stored in a form that is cheap to evaluate during rendering. ## Existing Note `docs/animation-integration.md` appears to document a prior animation attempt whose `src/animation/` implementation is not present in this checkout. Treat this plan as the current source of truth until implementation docs are updated.