12 KiB
Window Animations Manual Test Plan
This is the manual verification checklist for Wry's animation work. Use it after building a test compositor and booting into a normal graphical session.
The goal is to catch visual, synchronization, damage, and retained-content problems that unit tests cannot prove from geometry alone.
Setup
- Build and install the
codex-anims-nextbranch. - Start with animations enabled and a deliberately slow duration, around
400-700ms, so phase ordering and damage artifacts are visible. - Test at least one normal Wayland/XDG app, one Xwayland app if available, and one fast-updating app such as a terminal running output, a browser animation, a video, or a GL/Vulkan demo.
- Use visible gaps, borders, titlebars, and rounding. These make clipping and damage mistakes much easier to see.
- If available, test on both a single-output setup and a multi-output setup.
- If logging is convenient, run with debug logging and keep any multiphase fallback messages. A fallback is useful evidence, not automatically a bug.
Relevant internal config hooks:
SetAnimationsEnabledSetAnimationDurationMsSetAnimationCurveSetAnimationCubicBezier
Current curve IDs in code:
0: linear1: CSSease2: CSSease-in3or any other unrecognized value: CSSease-out4: CSSease-in-out
Pass Criteria
A test passes when:
- layout, focus, hit testing, and configure behavior use the final logical geometry immediately
- visible presentation motion is smooth and bounded by the animated frame
- no old pixels, trails, black strips, transparent holes, or stale titlebar fragments remain after motion
- tiled multiphase movement never overlaps and never moves a single window diagonally during a phase
- interruption starts changed windows from their current visual rect without restarting unaffected windows
- drag-driven pointer movement remains direct and does not lag behind the cursor
- cross-output or cross-scale movements snap instead of animating
Record a failure with:
- the layout before and after
- whether the window was tiled, floating, mono, XDG, Xwayland, or layer-shell
- whether the app was GPU/dmabuf-backed or likely SHM, if known
- animation duration and curve
- whether the failure was visual overlap, diagonal motion, debris, clipping, stale content, a missing retained frame, or an incorrect animation trigger
Known Current Limits
These are acceptable unless they produce worse behavior than described:
- Spawn-out is retained-content-only. If the surface cannot be retained safely, it should snap out rather than animate an empty frame.
- Async SHM surfaces are not retained yet. GPU/dmabuf-backed app windows are the primary retained-content path for this phase.
- A dedicated retained-tree scaling/offscreen fallback is deferred. Retained records currently render through the normal texture and stretch/clamp paths.
- Floats may overlap. The no-overlap invariant is for tiled multiphase motion.
- Linear fallback may overlap. This should be rare for valid tiled layouts, and the fallback should be scoped to the affected motion group.
- Cross-output and cross-scale movements should not animate yet.
1. Basic Enable/Disable
- Disable animations.
- Move, resize, spawn, close, and toggle floating on a few windows.
- Confirm all affected windows snap with no delayed presentation state.
- Enable animations at a slow duration.
- Repeat the same operations and confirm only eligible paths animate.
- Disable animations while an animation is in flight.
Expected:
- disabling animations clears any in-flight visual state
- no stale damage remains after disabling
- newly enabled animations use the configured duration and curve
2. Spawn-In
Test newly mapped windows:
- tiled XDG window
- floating XDG window
- Xwayland window, if available
- fullscreen window
- layer-shell or overlay surface, such as a bar, launcher, menu, notification, or lock/overlay component, if available
Expected:
- newly mapped tiled and floating app windows animate in
- layer-shell, overlay, override-redirect, and fullscreen surfaces do not use the app-window spawn-in path
- contents stay clipped to the animated frame
- if contents are smaller than the frame during the animation, no empty strips are visible
3. Spawn-Out
Close windows from these states:
- tiled app window
- floating app window
- Xwayland app window
- fast-updating app window
- a likely SHM/simple app, if available
Expected:
- retained app content shrinks out after the live node is gone
- there is no black, transparent, or unfilled moving rectangle
- if content cannot be retained, the window snaps out cleanly
- neighboring tiled windows reflow without debris left in the old area
Hard failure:
- a destroyed window leaves a moving empty frame
- the last frame shows unrelated newer content
- screen debris remains after the animation completes
4. Linear Tiled Reflow
Use a slow duration and a non-linear curve, then repeat with linear.
Cases:
- open two tiled windows and change split ratio by command
- open three tiled windows and resize the active split repeatedly
- move focus and issue command-driven swaps
- interrupt a resize by issuing another resize before the first completes
- create a layout that forces a linear fallback if possible
Expected:
- final layout is usable immediately
- changed windows animate from their current visual rect on interruption
- unaffected windows keep their existing timeline
- linear fallback is visually smooth, even if overlap occurs
- no pointer drag path becomes animated
5. Float Movement And Tile/Float Transitions
Cases:
- command-toggle a tiled window to floating
- command-toggle the same window back to tiled
- command-move and command-resize a floating window
- mouse-drag a floating window
- mouse-resize a floating window
- double-click/header pointer path if that is part of the local workflow
Expected:
- command-driven tile-to-float and float-to-tile transitions animate linearly
- command-driven floating move/resize animates
- mouse or tablet drag/resize remains direct and tracks the pointer
- pointer/header paths that are intentionally outside the command-animation gate do not unexpectedly use delayed animation
- retained child content remains clipped during tile/float transitions
6. Multiphase Horizontal And Vertical Swaps
Horizontal:
- Create two horizontally adjacent tiled windows.
- Swap their positions.
- Reverse the swap.
Vertical:
- Create two vertically adjacent tiled windows.
- Swap their positions.
- Reverse the swap.
Expected:
- first phase shrinks into lanes on the orthogonal axis
- second phase moves only horizontally or only vertically
- third phase grows out of lanes
- no phase overlaps windows
- no window moves diagonally
- reverse direction uses the same visual logic in reverse
- titlebars, borders, gaps, and rounded corners remain respected
7. Stack Extraction And Return
Build this shape:
[ A | [ B
C ] ]
Then move B out so the target is:
[ A | B | C ]
Reverse the operation by putting B back into the stack.
Expected:
- peer/container space opens first
Bwaits until there is a legal horizontal or vertical laneBmoves on one axis onlyBand the affected peer grow together in the final phase when appropriate- reversing the operation is visually equivalent in reverse
8. Nested Parent/Child Synchronization
Create nested split layouts where a parent changes one axis and children change the other. Use both horizontal-parent/vertical-child and vertical-parent/horizontal-child variants.
Expected:
- parent/container-space axis changes happen before child-axis changes when the hierarchy metadata gives a deterministic order
- child windows do not visually compose parent and child transforms into diagonal motion
- any unsupported group falls back as a group rather than partially violating the one-axis rule
Hard failure:
- a child visibly changes width and height in the same phase
- a child moves diagonally because parent and child animation compound
- a child clips outside its animated frame
9. Mixed-Action Phases
Look for layouts where one window can move on one axis while another window scales on a different axis in the same proven phase.
Expected:
- mixed phases are allowed only when each individual window performs one legal move or scale on one axis
- no individual window moves diagonally
- no overlap occurs at any point during the phase
This is easier to confirm with debug fallback logs plus visual inspection. A fallback here is acceptable if the planner cannot prove the sequence.
10. Mono Mode
Cases:
- enter mono mode with several siblings
- exit mono mode
- switch active tabs/windows inside mono
- move a window into mono
- move a window out of mono
Expected:
- entering/exiting mono may animate where it clarifies hierarchy change
- active child animates to the mono geometry
- inactive siblings snap invisible
- ordinary tab switches inside mono do not animate
- no hidden inactive sibling leaves debris or stale retained content
11. Interruption And Retargeting
Use a long duration, then issue commands mid-animation:
- swap, then reverse before completion
- resize, then resize in the other direction before completion
- move a window out of a stack, then back before completion
- start a multiphase group, then change only one window's destination if a command sequence allows it
Expected:
- affected windows restart from their current visual rect
- unaffected windows do not restart if their destination is unchanged
- a new valid multiphase plan replaces the old plan cleanly
- retained content remains the same frozen content during the retarget
- damage covers old, current, and new visual regions
12. Damage And Clipping Stress
Use a high-contrast wallpaper/background and high contrast window contents.
Cases:
- fast repeated swaps
- repeated spawn-in/spawn-out
- rounded corners with large gaps
- titlebar-heavy layouts
- resize while a terminal is rapidly updating
- move/resize over another window's old location
- run on different output scales if available
Expected:
- no trails remain in gaps, borders, or titlebar strips
- rounded corners do not reveal old pixels outside the frame
- contents never draw outside the animated bounds
- final frame exactly matches the steady layout
13. Texture Freezing
Use fast-updating contents so freezing is obvious.
Cases:
- tiled GPU/dmabuf-backed app during reflow
- floating GPU/dmabuf-backed app during command move/resize
- tile-to-float and float-to-tile with dynamic content
- spawn-out with dynamic content
- likely SHM/simple app, if available
Expected:
- retained GPU/dmabuf-backed windows freeze visually during animation
- spawn-out uses the last retained content, not a blank or unrelated frame
- undersized contents stretch/clamp to avoid unfilled frame regions
- SHM/unretained surfaces either render live safely or snap where retention is required
Record separately:
- content continues updating during movement
- content freezes but samples the wrong source region
- edges show empty/black strips while scaling
- spawn-out skips because capture was unavailable
14. Cross-Output And Scale Boundaries
Cases:
- move a tiled window to another output
- move a floating window to another output
- move between outputs with different scale factors, if available
- move a workspace between outputs, if supported locally
Expected:
- movement snaps instead of animating
- no retained content is rendered at the wrong scale
- no stale damage remains on the source output
- destination output renders the final layout immediately
15. Regression Sweep
After visual tests, return to normal animation duration and curve.
Repeat:
- ordinary tiling navigation
- workspace switching
- fullscreen enter/exit
- focus changes
- app launch/close loops
- suspend/resume or VT switch if convenient
Expected:
- animation state does not survive across unrelated compositor state changes
- no stuck retained frames
- no persistent high CPU/GPU use after animations stop
- no obvious client throttling after many retained-content animations
Summary Result Template
Commit:
Build:
Outputs/scales:
GPU/session:
Animation config:
Passed:
-
Known-limit observations:
-
Failures:
- case:
app:
layout:
expected:
actual:
reproducible:
logs: